From 5c1207be90fdf296c1b83034b7c68915e1749284 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Queru Date: Fri, 31 Jul 2009 17:38:20 -0700 Subject: [PATCH] donut snapshot --- Android.mk | 5 +- api/current.xml | 1418 +++++++++++++---- cmds/bootanimation/BootAnimation.cpp | 5 +- cmds/bootanimation/bootanimation_main.cpp | 20 +- cmds/keystore/keymgmt.c | 66 +- cmds/keystore/tests/Android.mk | 28 + cmds/keystore/tests/netkeystore_test.c | 249 +++ .../AccessibilityService.java | 4 + .../android/app/ActivityManagerNative.java | 40 + core/java/android/app/ActivityThread.java | 26 +- core/java/android/app/ApplicationContext.java | 17 +- core/java/android/app/IActivityManager.java | 8 +- core/java/android/app/IActivityWatcher.aidl | 1 + core/java/android/app/LauncherActivity.java | 4 +- core/java/android/app/PendingIntent.java | 7 +- core/java/android/app/SearchDialog.java | 245 ++- core/java/android/app/SearchManager.java | 9 +- core/java/android/app/SuggestionsAdapter.java | 45 +- core/java/android/content/Context.java | 3 +- core/java/android/content/ContextWrapper.java | 1 + core/java/android/content/Intent.java | 48 +- core/java/android/content/IntentSender.java | 9 +- .../android/content/pm/ApplicationInfo.java | 37 +- .../android/content/pm/PackageManager.java | 6 - .../android/content/pm/PackageParser.java | 56 +- .../android/content/res/AssetManager.java | 3 +- .../content/res/CompatibilityInfo.java | 55 +- core/java/android/content/res/TypedArray.java | 1 + core/java/android/database/MatrixCursor.java | 43 +- core/java/android/gesture/GestureLibrary.java | 1 + .../inputmethodservice/KeyboardView.java | 9 +- core/java/android/provider/CallLog.java | 30 +- core/java/android/provider/Settings.java | 7 + .../server/search/SearchDialogWrapper.java | 46 +- .../server/search/SearchManagerService.java | 5 + .../android/server/search/SearchableInfo.java | 8 + .../java/android/speech/tts/TextToSpeech.java | 309 ++-- core/java/android/text/format/DateFormat.java | 34 +- core/java/android/text/style/ImageSpan.java | 25 +- core/java/android/util/DisplayMetrics.java | 9 + core/java/android/view/Display.java | 1 + core/java/android/view/Surface.java | 88 +- core/java/android/view/SurfaceView.java | 53 +- core/java/android/view/View.java | 2 + core/java/android/view/ViewDebug.java | 5 +- core/java/android/view/ViewRoot.java | 16 +- core/java/android/webkit/LoadListener.java | 4 +- core/java/android/webkit/MimeTypeMap.java | 1 + core/java/android/webkit/WebView.java | 23 +- core/java/android/widget/AbsListView.java | 3 + .../android/widget/AutoCompleteTextView.java | 45 +- core/java/android/widget/DatePicker.java | 77 +- core/java/android/widget/ImageView.java | 3 +- core/java/android/widget/RelativeLayout.java | 14 +- core/java/android/widget/TabWidget.java | 6 +- .../internal/widget/EditStyledText.java | 3 +- core/jni/android/graphics/Canvas.cpp | 57 +- core/jni/android/graphics/Graphics.cpp | 9 - core/jni/android/graphics/GraphicsJNI.h | 1 - core/jni/android/graphics/MaskFilter.cpp | 22 +- core/jni/android/graphics/NinePatch.cpp | 40 +- core/jni/android/graphics/Shader.cpp | 20 +- core/jni/android_util_AssetManager.cpp | 26 +- core/res/AndroidManifest.xml | 10 +- .../res/drawable/expander_ic_maximized.9.png | Bin 1149 -> 1150 bytes .../res/drawable/expander_ic_minimized.9.png | Bin 1172 -> 1167 bytes .../res/res/drawable/rate_star_small_half.png | Bin 537 -> 540 bytes core/res/res/drawable/rate_star_small_off.png | Bin 320 -> 447 bytes core/res/res/drawable/rate_star_small_on.png | Bin 558 -> 570 bytes .../layout/zoom_browser_accessory_buttons.xml | 11 +- .../res/values-bg-rBG/donottranslate-cldr.xml | 2 +- .../res/values-cs-rCZ/donottranslate-cldr.xml | 147 -- .../res/res/values-cs/donottranslate-cldr.xml | 80 +- core/res/res/values-cs/strings.xml | 1 - .../res/values-da-rDK/donottranslate-cldr.xml | 147 -- .../res/res/values-da/donottranslate-cldr.xml | 88 +- core/res/res/values-da/strings.xml | 2 - .../res/values-de-rAT/donottranslate-cldr.xml | 147 -- .../res/values-de-rCH/donottranslate-cldr.xml | 147 -- .../res/values-de-rDE/donottranslate-cldr.xml | 147 -- .../res/values-de-rLI/donottranslate-cldr.xml | 147 -- .../res/res/values-de/donottranslate-cldr.xml | 100 +- core/res/res/values-de/strings.xml | 1 - .../res/values-el-rGR/donottranslate-cldr.xml | 147 -- core/res/res/values-el/strings.xml | 2 - .../res/values-en-rGB/donottranslate-cldr.xml | 16 +- .../res/values-en-rSG/donottranslate-cldr.xml | 147 -- .../res/values-es-rES/donottranslate-cldr.xml | 147 -- .../res/values-es-rUS/donottranslate-cldr.xml | 58 +- core/res/res/values-es-rUS/strings.xml | 2 - .../res/res/values-es/donottranslate-cldr.xml | 108 +- core/res/res/values-es/strings.xml | 1 - .../res/values-fi-rFI/donottranslate-cldr.xml | 64 +- .../res/values-fr-rBE/donottranslate-cldr.xml | 147 -- .../res/values-fr-rCA/donottranslate-cldr.xml | 147 -- .../res/values-fr-rCH/donottranslate-cldr.xml | 147 -- .../res/values-fr-rFR/donottranslate-cldr.xml | 147 -- .../res/res/values-fr/donottranslate-cldr.xml | 68 +- core/res/res/values-fr/strings.xml | 1 - .../res/values-he-rIL/donottranslate-cldr.xml | 147 -- .../res/values-hu-rHU/donottranslate-cldr.xml | 44 +- .../res/values-id-rID/donottranslate-cldr.xml | 62 +- .../res/values-it-rCH/donottranslate-cldr.xml | 147 -- .../res/values-it-rIT/donottranslate-cldr.xml | 147 -- .../res/res/values-it/donottranslate-cldr.xml | 28 +- core/res/res/values-it/strings.xml | 1 - .../res/values-ja-rJP/donottranslate-cldr.xml | 147 -- .../res/res/values-ja/donottranslate-cldr.xml | 78 +- core/res/res/values-ja/strings.xml | 2 - .../res/values-ko-rKR/donottranslate-cldr.xml | 135 -- .../res/res/values-ko/donottranslate-cldr.xml | 80 +- core/res/res/values-ko/strings.xml | 2 - .../res/values-lt-rLT/donottranslate-cldr.xml | 106 +- .../res/values-lv-rLV/donottranslate-cldr.xml | 62 +- .../res/values-nb-rNO/donottranslate-cldr.xml | 147 -- core/res/res/values-nb/strings.xml | 2 - .../res/values-nl-rBE/donottranslate-cldr.xml | 147 -- .../res/values-nl-rNL/donottranslate-cldr.xml | 147 -- .../res/res/values-nl/donottranslate-cldr.xml | 2 +- core/res/res/values-nl/strings.xml | 1 - .../res/values-pl-rPL/donottranslate-cldr.xml | 147 -- .../res/res/values-pl/donottranslate-cldr.xml | 66 +- core/res/res/values-pl/strings.xml | 1 - .../res/values-pt-rBR/donottranslate-cldr.xml | 147 -- core/res/res/values-pt-rPT/strings.xml | 2 - core/res/res/values-pt/strings.xml | 2 - .../res/values-ru-rRU/donottranslate-cldr.xml | 147 -- .../res/res/values-ru/donottranslate-cldr.xml | 104 +- core/res/res/values-ru/strings.xml | 2 - .../res/values-sk-rSK/donottranslate-cldr.xml | 54 +- .../res/values-sl-rSI/donottranslate-cldr.xml | 128 +- .../res/values-sv-rSE/donottranslate-cldr.xml | 147 -- .../res/res/values-sv/donottranslate-cldr.xml | 24 +- core/res/res/values-sv/strings.xml | 2 - .../res/values-tr-rTR/donottranslate-cldr.xml | 147 -- .../res/res/values-tr/donottranslate-cldr.xml | 40 +- core/res/res/values-tr/strings.xml | 2 - .../res/values-uk-rUA/donottranslate-cldr.xml | 120 +- .../res/values-zh-rCN/donottranslate-cldr.xml | 180 +-- core/res/res/values-zh-rCN/strings.xml | 2 - .../res/values-zh-rTW/donottranslate-cldr.xml | 190 +-- core/res/res/values-zh-rTW/strings.xml | 1 - core/res/res/values/attrs_manifest.xml | 27 +- core/res/res/values/public.xml | 2 +- core/res/res/values/strings.xml | 8 +- data/sounds/AudioPackage2.mk | 1 - data/sounds/OriginalAudio.mk | 1 - data/sounds/Silence.ogg | Bin 3973 -> 0 bytes docs/html/community/index.jd | 2 +- docs/html/guide/developing/device.jd | 2 +- docs/html/guide/guide_toc.cs | 510 ++++-- .../practices/ui_guidelines/icon_design.jd | 240 +-- .../guide/practices/ui_guidelines/index.jd | 8 + .../practices/ui_guidelines/menu_design.jd | 507 ++++++ docs/html/guide/topics/appwidgets/index.jd | 16 +- .../guide/topics/resources/resources-i18n.jd | 43 +- .../images/menu_design/ContextMenuDiagram.png | Bin 0 -> 79806 bytes .../ContextMenuViewContactDiagram.png | Bin 0 -> 85574 bytes docs/html/images/menu_design/MenuDiagram.png | Bin 0 -> 155648 bytes .../images/menu_design/TaskFlowDiagram.png | Bin 0 -> 32794 bytes .../TextFieldContextMenuDiagram.png | Bin 0 -> 33313 bytes docs/html/index.jd | 48 +- docs/html/intl/ja/community/index.jd | 108 ++ .../intl/ja/guide/basics/what-is-android.jd | 81 + .../intl/ja/guide/developing/eclipse-adt.jd | 243 +++ .../intl/ja/guide/developing/other-ide.jd | 271 ++++ docs/html/intl/ja/guide/index.jd | 52 + .../intl/ja/guide/publishing/app-signing.jd | 336 ++++ .../intl/ja/guide/publishing/preparing.jd | 154 ++ .../intl/ja/guide/publishing/versioning.jd | 100 ++ .../html/intl/ja/guide/topics/fundamentals.jd | 922 +++++++++++ .../intl/ja/guide/tutorials/hello-world.jd | 375 +++++ docs/html/intl/ja/index.jd | 159 ++ docs/html/intl/ja/sdk/1.5_r2/installing.jd | 212 +++ docs/html/intl/ja/sdk/1.5_r3/installing.jd | 212 +++ docs/html/sdk/1.5_r2/installing.jd | 8 +- docs/html/sdk/1.5_r3/index.jd | 87 + docs/html/sdk/1.5_r3/installing.jd | 332 ++++ docs/html/sdk/1.5_r3/requirements.jd | 39 + docs/html/sdk/1.5_r3/upgrading.jd | 395 +++++ docs/html/sdk/RELEASENOTES.jd | 69 + docs/html/sdk/android-1.5.jd | 1 + docs/html/sdk/index.jd | 3 +- docs/html/sdk/ndk/{1.5-r1 => 1.5_r1}/index.jd | 80 +- docs/html/sdk/older_releases.jd | 6 + docs/html/sdk/preview/features.html | 191 --- docs/html/sdk/preview/features.jd | 6 + docs/html/sdk/preview/index.jd | 2 +- docs/html/sdk/sdk_toc.cs | 65 +- docs/html/sitemap-intl.txt | 12 + docs/html/videos/index.jd | 338 ++++ graphics/java/android/graphics/Bitmap.java | 240 +-- .../java/android/graphics/BitmapFactory.java | 180 ++- graphics/java/android/graphics/Canvas.java | 132 +- graphics/java/android/graphics/NinePatch.java | 31 +- .../graphics/drawable/BitmapDrawable.java | 128 +- .../android/graphics/drawable/Drawable.java | 32 +- .../graphics/drawable/DrawableContainer.java | 11 +- .../graphics/drawable/NinePatchDrawable.java | 115 +- include/utils/ResourceTypes.h | 6 +- keystore/java/android/security/CertTool.java | 6 +- keystore/jni/cert.c | 56 +- keystore/jni/cert.h | 5 +- keystore/jni/certtool.c | 12 +- .../DisplayHardware/DisplayHardware.cpp | 3 + libs/surfaceflinger/SurfaceFlinger.cpp | 21 +- libs/surfaceflinger/SurfaceFlinger.h | 1 + libs/utils/ResourceTypes.cpp | 11 +- media/java/android/media/JetPlayer.java | 1 + media/jni/soundpool/SoundPool.cpp | 3 +- .../res/values-cs/defaults.xml | 22 - .../res/values-cs/strings.xml | 2 +- .../res/values-de/defaults.xml | 22 - .../res/values-de/strings.xml | 2 +- .../res/values-es/defaults.xml | 22 - .../res/values-es/strings.xml | 2 +- .../res/values-fr/defaults.xml | 22 - .../res/values-fr/strings.xml | 2 +- .../res/values-it/defaults.xml | 22 - .../res/values-it/strings.xml | 2 +- .../res/values-nl/defaults.xml | 22 - .../res/values-nl/strings.xml | 2 +- .../res/values-pl/defaults.xml | 22 - .../res/values-pl/strings.xml | 2 +- .../res/values-zh-rTW/strings.xml | 2 +- .../SettingsProvider/res/values/defaults.xml | 6 +- .../src/android/tts/TtsService.java | 83 +- .../server/vpn/AndroidServiceProxy.java | 261 --- .../com/android/server/vpn/DaemonProxy.java | 199 +++ .../server/vpn/L2tpIpsecPskService.java | 14 +- .../android/server/vpn/L2tpIpsecService.java | 13 +- .../com/android/server/vpn/L2tpService.java | 5 + .../com/android/server/vpn/MtpdHelper.java | 22 +- .../server/vpn/NormalProcessProxy.java | 85 - .../com/android/server/vpn/PptpService.java | 8 +- .../com/android/server/vpn/ProcessProxy.java | 210 --- .../com/android/server/vpn/VpnService.java | 479 +++--- .../android/server/vpn/VpnServiceBinder.java | 85 +- .../server/AccessibilityManagerService.java | 23 +- .../server/NotificationManagerService.java | 13 +- .../android/server/PackageManagerService.java | 175 +- .../java/com/android/server/WifiService.java | 11 + .../android/server/WindowManagerService.java | 8 +- .../server/am/ActivityManagerService.java | 63 +- .../java/android/telephony/SmsManager.java | 17 +- .../java/android/telephony/SmsMessage.java | 84 +- .../android/telephony/TelephonyManager.java | 2 +- .../android/telephony/gsm/SmsManager.java | 1 + .../internal/telephony/RILConstants.java | 11 +- .../internal/telephony/SmsMessageBase.java | 1 + test-runner/android/test/IsolatedContext.java | 5 + .../android/test/mock/MockContext.java | 1 + .../android/unit_tests/SearchManagerTest.java | 59 +- .../src/com/android/unit_tests/VpnTest.java | 116 +- tests/CoreTests/android/AndroidManifest.xml | 1 + tests/CoreTests/android/core/CryptoTest.java | 11 - .../android/database/MatrixCursorTest.java | 6 + .../res/drawable-hdpi/npatch240dpi.9.png | Bin 0 -> 17331 bytes .../res/drawable-hdpi/reslogo240dpi.png | Bin 0 -> 13388 bytes .../res/drawable-hdpi/smlnpatch240dpi.9.png | Bin 0 -> 946 bytes .../res/drawable-hdpi/stylogo240dpi.png | Bin 0 -> 13388 bytes .../res/drawable-ldpi/npatch120dpi.9.png | Bin 0 -> 6299 bytes .../res/drawable-ldpi/reslogo120dpi.png | Bin 0 -> 5178 bytes .../res/drawable-ldpi/smlnpatch120dpi.9.png | Bin 0 -> 804 bytes .../res/drawable-ldpi/stylogo120dpi.png | Bin 0 -> 5178 bytes tests/DpiTest/res/drawable/npatch160dpi.9.png | Bin 0 -> 9978 bytes tests/DpiTest/res/drawable/reslogo160dpi.png | Bin 0 -> 8114 bytes .../res/drawable/smlnpatch160dpi.9.png | Bin 0 -> 855 bytes tests/DpiTest/res/drawable/stylogo160dpi.png | Bin 0 -> 8114 bytes tests/DpiTest/res/layout/image_views.xml | 37 + .../DpiTest/res/layout/styled_image_views.xml | 20 +- tests/DpiTest/res/values/styles.xml | 35 + .../android/test/dpi/DpiTestActivity.java | 44 +- .../widget/AutoCompleteTextViewCallbacks.java | 6 +- .../layoutlib/bridge/BridgeTypedArray.java | 223 +-- vpn/java/android/net/vpn/PptpProfile.java | 26 + vpn/java/android/net/vpn/VpnManager.java | 4 + .../android/net/wifi/WifiConfiguration.java | 14 + wifi/java/android/net/wifi/WifiManager.java | 78 +- 279 files changed, 11153 insertions(+), 8126 deletions(-) create mode 100644 cmds/keystore/tests/Android.mk create mode 100644 cmds/keystore/tests/netkeystore_test.c delete mode 100644 core/res/res/values-cs-rCZ/donottranslate-cldr.xml delete mode 100644 core/res/res/values-da-rDK/donottranslate-cldr.xml delete mode 100644 core/res/res/values-de-rAT/donottranslate-cldr.xml delete mode 100644 core/res/res/values-de-rCH/donottranslate-cldr.xml delete mode 100644 core/res/res/values-de-rDE/donottranslate-cldr.xml delete mode 100644 core/res/res/values-de-rLI/donottranslate-cldr.xml delete mode 100644 core/res/res/values-el-rGR/donottranslate-cldr.xml delete mode 100644 core/res/res/values-en-rSG/donottranslate-cldr.xml delete mode 100644 core/res/res/values-es-rES/donottranslate-cldr.xml delete mode 100644 core/res/res/values-fr-rBE/donottranslate-cldr.xml delete mode 100644 core/res/res/values-fr-rCA/donottranslate-cldr.xml delete mode 100644 core/res/res/values-fr-rCH/donottranslate-cldr.xml delete mode 100644 core/res/res/values-fr-rFR/donottranslate-cldr.xml delete mode 100644 core/res/res/values-he-rIL/donottranslate-cldr.xml delete mode 100644 core/res/res/values-it-rCH/donottranslate-cldr.xml delete mode 100644 core/res/res/values-it-rIT/donottranslate-cldr.xml delete mode 100644 core/res/res/values-ja-rJP/donottranslate-cldr.xml delete mode 100644 core/res/res/values-ko-rKR/donottranslate-cldr.xml delete mode 100644 core/res/res/values-nb-rNO/donottranslate-cldr.xml delete mode 100644 core/res/res/values-nl-rBE/donottranslate-cldr.xml delete mode 100644 core/res/res/values-nl-rNL/donottranslate-cldr.xml delete mode 100644 core/res/res/values-pl-rPL/donottranslate-cldr.xml delete mode 100644 core/res/res/values-pt-rBR/donottranslate-cldr.xml delete mode 100644 core/res/res/values-ru-rRU/donottranslate-cldr.xml delete mode 100644 core/res/res/values-sv-rSE/donottranslate-cldr.xml delete mode 100644 core/res/res/values-tr-rTR/donottranslate-cldr.xml delete mode 100644 data/sounds/Silence.ogg create mode 100644 docs/html/guide/practices/ui_guidelines/menu_design.jd create mode 100644 docs/html/images/menu_design/ContextMenuDiagram.png create mode 100644 docs/html/images/menu_design/ContextMenuViewContactDiagram.png create mode 100644 docs/html/images/menu_design/MenuDiagram.png create mode 100644 docs/html/images/menu_design/TaskFlowDiagram.png create mode 100644 docs/html/images/menu_design/TextFieldContextMenuDiagram.png create mode 100644 docs/html/intl/ja/community/index.jd create mode 100644 docs/html/intl/ja/guide/basics/what-is-android.jd create mode 100644 docs/html/intl/ja/guide/developing/eclipse-adt.jd create mode 100644 docs/html/intl/ja/guide/developing/other-ide.jd create mode 100644 docs/html/intl/ja/guide/index.jd create mode 100644 docs/html/intl/ja/guide/publishing/app-signing.jd create mode 100644 docs/html/intl/ja/guide/publishing/preparing.jd create mode 100644 docs/html/intl/ja/guide/publishing/versioning.jd create mode 100644 docs/html/intl/ja/guide/topics/fundamentals.jd create mode 100644 docs/html/intl/ja/guide/tutorials/hello-world.jd create mode 100644 docs/html/intl/ja/index.jd create mode 100644 docs/html/intl/ja/sdk/1.5_r2/installing.jd create mode 100644 docs/html/intl/ja/sdk/1.5_r3/installing.jd create mode 100644 docs/html/sdk/1.5_r3/index.jd create mode 100644 docs/html/sdk/1.5_r3/installing.jd create mode 100644 docs/html/sdk/1.5_r3/requirements.jd create mode 100644 docs/html/sdk/1.5_r3/upgrading.jd rename docs/html/sdk/ndk/{1.5-r1 => 1.5_r1}/index.jd (82%) delete mode 100644 docs/html/sdk/preview/features.html create mode 100644 docs/html/sdk/preview/features.jd create mode 100644 docs/html/sitemap-intl.txt create mode 100644 docs/html/videos/index.jd delete mode 100644 packages/SettingsProvider/res/values-cs/defaults.xml delete mode 100644 packages/SettingsProvider/res/values-de/defaults.xml delete mode 100644 packages/SettingsProvider/res/values-es/defaults.xml delete mode 100644 packages/SettingsProvider/res/values-fr/defaults.xml delete mode 100644 packages/SettingsProvider/res/values-it/defaults.xml delete mode 100644 packages/SettingsProvider/res/values-nl/defaults.xml delete mode 100644 packages/SettingsProvider/res/values-pl/defaults.xml delete mode 100644 packages/VpnServices/src/com/android/server/vpn/AndroidServiceProxy.java create mode 100644 packages/VpnServices/src/com/android/server/vpn/DaemonProxy.java delete mode 100644 packages/VpnServices/src/com/android/server/vpn/NormalProcessProxy.java delete mode 100644 packages/VpnServices/src/com/android/server/vpn/ProcessProxy.java create mode 100644 tests/DpiTest/res/drawable-hdpi/npatch240dpi.9.png create mode 100644 tests/DpiTest/res/drawable-hdpi/reslogo240dpi.png create mode 100644 tests/DpiTest/res/drawable-hdpi/smlnpatch240dpi.9.png create mode 100644 tests/DpiTest/res/drawable-hdpi/stylogo240dpi.png create mode 100644 tests/DpiTest/res/drawable-ldpi/npatch120dpi.9.png create mode 100644 tests/DpiTest/res/drawable-ldpi/reslogo120dpi.png create mode 100644 tests/DpiTest/res/drawable-ldpi/smlnpatch120dpi.9.png create mode 100644 tests/DpiTest/res/drawable-ldpi/stylogo120dpi.png create mode 100644 tests/DpiTest/res/drawable/npatch160dpi.9.png create mode 100644 tests/DpiTest/res/drawable/reslogo160dpi.png create mode 100644 tests/DpiTest/res/drawable/smlnpatch160dpi.9.png create mode 100644 tests/DpiTest/res/drawable/stylogo160dpi.png create mode 100644 tests/DpiTest/res/layout/image_views.xml rename packages/SettingsProvider/res/values-zh-rTW/defaults.xml => tests/DpiTest/res/layout/styled_image_views.xml (60%) create mode 100644 tests/DpiTest/res/values/styles.xml diff --git a/Android.mk b/Android.mk index 038af0d6b67a0..011e59ed34794 100644 --- a/Android.mk +++ b/Android.mk @@ -349,7 +349,7 @@ web_docs_sample_code_flags := \ # most current Android platform version included in the SDK package. framework_docs_SDK_VERSION := 1.5 # release version for SDK (ie "Release x") -framework_docs_SDK_REL_ID := 2 +framework_docs_SDK_REL_ID := 3 framework_docs_SDK_CURRENT_DIR := $(framework_docs_SDK_VERSION)_r$(framework_docs_SDK_REL_ID) framework_docs_LOCAL_DROIDDOC_OPTIONS += \ @@ -416,7 +416,8 @@ LOCAL_DROIDDOC_OPTIONS:= \ $(framework_docs_LOCAL_DROIDDOC_OPTIONS) \ $(web_docs_sample_code_flags) \ -toroot / \ - -hdf android.whichdoc online + -hdf android.whichdoc online \ + -hdf template.showLanguageMenu true LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk LOCAL_DROIDDOC_CUSTOM_ASSET_DIR:=assets-sdk diff --git a/api/current.xml b/api/current.xml index 0e04f50a89a2f..b17cbe7955c3a 100644 --- a/api/current.xml +++ b/api/current.xml @@ -698,7 +698,7 @@ type="java.lang.String" transient="false" volatile="false" - value=""android.permission.READ_HISTORY_BOOKMARKS"" + value=""com.android.browser.permission.READ_HISTORY_BOOKMARKS"" static="true" final="true" deprecated="not deprecated" @@ -991,17 +991,6 @@ visibility="public" > - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - + + + + + + + + - - - - - - - - + - - + + + + - - - + + + @@ -59150,6 +58989,28 @@ deprecated="not deprecated" visibility="public" > + + + + + + + + + + @@ -59315,6 +59176,45 @@ + + + + + + + + + + + + + + + + + + + + + + @@ -61367,6 +61286,36 @@ deprecated="not deprecated" visibility="public" > + + + + + + + + + + + + + + + + + + @@ -61431,6 +61380,45 @@ + + + + + + + + + + + + + + + + - + + - - - - - - - - + + + + - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + + + + + + + @@ -130434,6 +131219,8 @@ deprecated="not deprecated" visibility="public" > + + @@ -133375,6 +134162,16 @@ visibility="public" > + + @@ -141804,6 +142601,17 @@ visibility="public" > + + setSwapRectangle(updateRect.left, updateRect.top, updateRect.width(), updateRect.height()); - glEnable(GL_SCISSOR_TEST); glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(), updateRect.height()); @@ -219,6 +218,10 @@ bool BootAnimation::android() { GLint offset = (1 - (t - floorf(t))) * mAndroid[1].w; GLint x = xc - offset; + glDisable(GL_SCISSOR_TEST); + glClear(GL_COLOR_BUFFER_BIT); + + glEnable(GL_SCISSOR_TEST); glDisable(GL_BLEND); glBindTexture(GL_TEXTURE_2D, mAndroid[1].name); glDrawTexiOES(x, yc, 0, mAndroid[1].w, mAndroid[1].h); diff --git a/cmds/bootanimation/bootanimation_main.cpp b/cmds/bootanimation/bootanimation_main.cpp index 675ea8167a0ed..a8359c40d0d27 100644 --- a/cmds/bootanimation/bootanimation_main.cpp +++ b/cmds/bootanimation/bootanimation_main.cpp @@ -16,6 +16,8 @@ #define LOG_TAG "BootAnimation" +#include + #include #include #include @@ -41,12 +43,20 @@ int main(int argc, char** argv) setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY); #endif - sp proc(ProcessState::self()); - ProcessState::self()->startThreadPool(); + char value[PROPERTY_VALUE_MAX]; + property_get("debug.sf.nobootanimation", value, "0"); + int noBootAnimation = atoi(value); + LOGI_IF(noBootAnimation, "boot animation disabled"); + if (!noBootAnimation) { - // create the boot animation object - sp boot = new BootAnimation(); + sp proc(ProcessState::self()); + ProcessState::self()->startThreadPool(); - IPCThreadState::self()->joinThreadPool(); + // create the boot animation object + sp boot = new BootAnimation(); + + IPCThreadState::self()->joinThreadPool(); + + } return 0; } diff --git a/cmds/keystore/keymgmt.c b/cmds/keystore/keymgmt.c index 66edd566166a1..9a1f8457d224d 100644 --- a/cmds/keystore/keymgmt.c +++ b/cmds/keystore/keymgmt.c @@ -79,14 +79,26 @@ static int encrypt_n_save(AES_KEY *enc_key, DATA_BLOB *blob, { int size, fd, ret = -1; unsigned char enc_blob[MAX_BLOB_LEN]; - char tmpfile[KEYFILE_LEN]; + + if ((keyfile == NULL) || (strlen(keyfile) >= (KEYFILE_LEN - 4))) { + LOGE("keyfile name is too long or null"); + return -1; + } strcpy(tmpfile, keyfile); strcat(tmpfile, ".tmp"); // prepare the blob + if (IV_LEN > USER_KEY_LEN) { + LOGE("iv length is too long."); + return -1; + } memcpy(blob->iv, iv, IV_LEN); blob->blob_size = get_blob_size(blob); + if (blob->blob_size > MAX_BLOB_LEN) { + LOGE("blob data size is too large."); + return -1; + } memcpy(enc_blob, blob->blob, blob->blob_size); AES_cbc_encrypt((unsigned char *)enc_blob, (unsigned char *)blob->blob, blob->blob_size, enc_key, iv, AES_ENCRYPT); @@ -133,8 +145,13 @@ static int store_master_key(char *upasswd, unsigned char *master_key) DATA_BLOB blob; // prepare the blob + if (strlen(MASTER_KEY_TAG) >= USER_KEY_LEN) return -1; strlcpy(blob.keyname, MASTER_KEY_TAG, USER_KEY_LEN); blob.value_size = USER_KEY_LEN; + if (USER_KEY_LEN > MAX_KEY_VALUE_LENGTH) { + LOGE("master_key length is too long."); + return -1; + } memcpy((void*)blob.value, (const void*)master_key, USER_KEY_LEN); // generate the encryption key @@ -150,6 +167,10 @@ static int get_master_key(char *upasswd, unsigned char *master_key) get_decrypt_key(upasswd, &key); ret = load_n_decrypt(MASTER_KEY_TAG, MASTER_KEY, &key, &blob); + if (blob.value_size > USER_KEY_LEN) { + LOGE("the blob's value size is too large"); + return -1; + } if (!ret) memcpy(master_key, blob.value, blob.value_size); return ret; } @@ -207,6 +228,11 @@ int remove_key(const char *namespace, const char *keyname) char keyfile[KEYFILE_LEN]; if (state != UNLOCKED) return -state; + if ((strlen(namespace) >= MAX_KEY_NAME_LENGTH) || + (strlen(keyname) >= MAX_KEY_NAME_LENGTH)) { + LOGE("keyname is too long."); + return -1; + } sprintf(keyfile, KEYFILE_NAME, namespace, keyname); return unlink(keyfile); } @@ -222,10 +248,18 @@ int put_key(const char *namespace, const char *keyname, LOGE("Can not store key with current state %d\n", state); return -state; } + if ((strlen(namespace) >= MAX_KEY_NAME_LENGTH) || + (strlen(keyname) >= MAX_KEY_NAME_LENGTH)) { + LOGE("keyname is too long."); + return -1; + } sprintf(keyfile, KEYFILE_NAME, namespace, keyname); - // flatten the args strcpy(blob.keyname, keyname); blob.value_size = size; + if (size > MAX_KEY_VALUE_LENGTH) { + LOGE("the data size is too large."); + return -1; + } memcpy(blob.value, data, size); return encrypt_n_save(&encryptKey, &blob, keyfile); } @@ -242,10 +276,16 @@ int get_key(const char *namespace, const char *keyname, LOGE("Can not retrieve key value with current state %d\n", state); return -state; } + if ((strlen(namespace) >= MAX_KEY_NAME_LENGTH) || + (strlen(keyname) >= MAX_KEY_NAME_LENGTH)) { + LOGE("keyname is too long."); + return -1; + } sprintf(keyfile, KEYFILE_NAME, namespace, keyname); ret = load_n_decrypt(keyname, keyfile, &decryptKey, &blob); if (!ret) { if ((blob.value_size > MAX_KEY_VALUE_LENGTH)) { + LOGE("blob value size is too large."); ret = -1; } else { *size = blob.value_size; @@ -269,6 +309,13 @@ int list_keys(const char *namespace, char reply[BUFFER_MAX]) LOGE("cannot open keystore dir or namespace is null\n"); return -1; } + + if (strlen(namespace) >= MAX_KEY_NAME_LENGTH) { + LOGE("namespace is too long."); + return -1; + } + + reply[0] = 0; while ((de = readdir(d))) { char *prefix, *name, *keyfile = de->d_name; char *context = NULL; @@ -337,6 +384,7 @@ KEYSTORE_STATE get_state() int reset_keystore() { + int ret = 0; DIR *d; struct dirent *de; @@ -344,18 +392,24 @@ int reset_keystore() LOGE("cannot open keystore dir\n"); return -1; } - while ((de = readdir(d))) unlink(de->d_name); + while ((de = readdir(d))) { + if (unlink(de->d_name) != 0) ret = -1; + } closedir(d); state = UNINITIALIZED; - LOGI("keystore is reset."); - return 0; + if (ret == 0) { + LOGI("keystore is reset."); + } else { + LOGI("keystore can not be cleaned up entirely."); + } + return ret; } int init_keystore(const char *dir) { int fd; - if (!dir) mkdir(dir, 0770); + if (dir) mkdir(dir, 0770); if (!dir || chdir(dir)) { LOGE("Can not open/create the keystore directory %s\n", dir ? dir : "(null)"); diff --git a/cmds/keystore/tests/Android.mk b/cmds/keystore/tests/Android.mk new file mode 100644 index 0000000000000..33541cc79f191 --- /dev/null +++ b/cmds/keystore/tests/Android.mk @@ -0,0 +1,28 @@ +# Copyright (C) 2009 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# define the KEYSTORE_TESTS environment variable to build the test programs +ifdef KEYSTORE_TESTS +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) +LOCAL_SRC_FILES:= netkeystore_test.c ../keymgmt.c +LOCAL_SHARED_LIBRARIES := libcutils libssl +LOCAL_MODULE:= netkeystore_test +LOCAL_MODULE_TAGS := optional +LOCAL_C_INCLUDES := external/openssl/include \ + frameworks/base/cmds/keystore +EXTRA_CFLAGS := -g -O0 -DGTEST_OS_LINUX -DGTEST_HAS_STD_STRING +include $(BUILD_EXECUTABLE) + +endif #KEYSTORE_TESTS diff --git a/cmds/keystore/tests/netkeystore_test.c b/cmds/keystore/tests/netkeystore_test.c new file mode 100644 index 0000000000000..e7e686bd4368d --- /dev/null +++ b/cmds/keystore/tests/netkeystore_test.c @@ -0,0 +1,249 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +#include "common.h" +#include "keymgmt.h" + +typedef int FUNC_PTR(); +typedef struct { + const char *name; + FUNC_PTR *func; +} TESTFUNC; + +#define FUNC_NAME(x) { #x, test_##x } +#define FUNC_BODY(x) int test_##x() + +#define TEST_PASSWD "12345678" +#define TEST_NPASSWD "11111111" +#define TEST_DIR "/data/local/tmp/keystore" +#define READONLY_DIR "/proc/keystore" +#define TEST_NAMESPACE "test" +#define TEST_KEYNAME "key" +#define TEST_KEYNAME2 "key2" +#define TEST_KEYVALUE "ANDROID" + +void setup() +{ + if (init_keystore(TEST_DIR) != 0) { + fprintf(stderr, "Can not create the test directory %s\n", TEST_DIR); + exit(-1); + } +} + +void teardown() +{ + reset_keystore(); + rmdir(TEST_DIR); +} + +FUNC_BODY(init_keystore) +{ + if (init_keystore(READONLY_DIR) == 0) return -1; + + return EXIT_SUCCESS; +} + +FUNC_BODY(reset_keystore) +{ + chdir("/procx"); + if (reset_keystore() == 0) return -1; + chdir(TEST_DIR); + return EXIT_SUCCESS; +} + +FUNC_BODY(get_state) +{ + if (get_state() != UNINITIALIZED) return -1; + passwd(TEST_PASSWD); + if (get_state() != UNLOCKED) return -1; + lock(); + if (get_state() != LOCKED) return -1; + reset_keystore(); + if (get_state() != UNINITIALIZED) return -1; + return EXIT_SUCCESS; +} + +FUNC_BODY(passwd) +{ + char buf[512]; + + if (passwd(" 23432dsfsdf") == 0) return -1; + if (passwd("dsfsdf") == 0) return -1; + passwd(TEST_PASSWD); + lock(); + if (unlock("55555555") == 0) return -1; + if (unlock(TEST_PASSWD) != 0) return -1; + + // change the password + sprintf(buf, "%s %s", "klfdjdsklfjg", "abcdefghi"); + if (passwd(buf) == 0) return -1; + + sprintf(buf, "%s %s", TEST_PASSWD, TEST_NPASSWD); + if (passwd(buf) != 0) return -1; + lock(); + + if (unlock(TEST_PASSWD) == 0) return -1; + if (unlock(TEST_NPASSWD) != 0) return -1; + + return EXIT_SUCCESS; +} + +FUNC_BODY(lock) +{ + if (lock() == 0) return -1; + passwd(TEST_PASSWD); + if (lock() != 0) return -1; + if (lock() != 0) return -1; + return EXIT_SUCCESS; +} + +FUNC_BODY(unlock) +{ + int i = MAX_RETRY_COUNT; + passwd(TEST_PASSWD); + lock(); + while (i > 1) { + if (unlock(TEST_NPASSWD) != --i) return -1; + } + if (unlock(TEST_NPASSWD) != -1) return -1; + return EXIT_SUCCESS; +} + +FUNC_BODY(put_key) +{ + int i = 0; + char keyname[512]; + + if (put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE, + strlen(TEST_KEYVALUE)) == 0) return -1; + passwd(TEST_PASSWD); + if (put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE, + strlen(TEST_KEYVALUE)) != 0) return -1; + + for(i = 0; i < 500; i++) keyname[i] = 'K'; + keyname[i] = 0; + if (put_key(TEST_NAMESPACE, keyname, (unsigned char *)TEST_KEYVALUE, + strlen(TEST_KEYVALUE)) == 0) return -1; + if (put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE, + MAX_KEY_VALUE_LENGTH + 1) == 0) return -1; + return EXIT_SUCCESS; +} + +FUNC_BODY(get_key) +{ + int size; + unsigned char data[MAX_KEY_VALUE_LENGTH]; + + if (get_key(TEST_NAMESPACE, TEST_KEYNAME, data, &size) == 0) return -1; + + passwd(TEST_PASSWD); + put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE, + strlen(TEST_KEYVALUE)); + if (get_key(TEST_NAMESPACE, TEST_KEYNAME, data, &size) != 0) return -1; + if (memcmp(data, TEST_KEYVALUE, size) != 0) return -1; + + return EXIT_SUCCESS; +} + +FUNC_BODY(remove_key) +{ + if (remove_key(TEST_NAMESPACE, TEST_KEYNAME) == 0) return -1; + + passwd(TEST_PASSWD); + if (remove_key(TEST_NAMESPACE, TEST_KEYNAME) == 0) return -1; + + put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE, + strlen(TEST_KEYVALUE)); + if (remove_key(TEST_NAMESPACE, TEST_KEYNAME) != 0) return -1; + + return EXIT_SUCCESS; +} + +FUNC_BODY(list_keys) +{ + int i; + char buf[128]; + char reply[BUFFER_MAX]; + + for(i = 0; i < 100; i++) buf[i] = 'K'; + buf[i] = 0; + + if (list_keys(TEST_NAMESPACE, reply) == 0) return -1; + + passwd(TEST_PASSWD); + if (list_keys(buf, reply) == 0) return -1; + + if (list_keys(TEST_NAMESPACE, reply) != 0) return -1; + if (strcmp(reply, "") != 0) return -1; + + put_key(TEST_NAMESPACE, TEST_KEYNAME, (unsigned char *)TEST_KEYVALUE, + strlen(TEST_KEYVALUE)); + if (list_keys(TEST_NAMESPACE, reply) != 0) return -1; + if (strcmp(reply, TEST_KEYNAME) != 0) return -1; + + put_key(TEST_NAMESPACE, TEST_KEYNAME2, (unsigned char *)TEST_KEYVALUE, + strlen(TEST_KEYVALUE)); + + if (list_keys(TEST_NAMESPACE, reply) != 0) return -1; + sprintf(buf, "%s %s", TEST_KEYNAME2, TEST_KEYNAME); + if (strcmp(reply, buf) != 0) return -1; + + return EXIT_SUCCESS; +} + +TESTFUNC all_tests[] = { + FUNC_NAME(init_keystore), + FUNC_NAME(reset_keystore), + FUNC_NAME(get_state), + FUNC_NAME(passwd), + FUNC_NAME(lock), + FUNC_NAME(unlock), + FUNC_NAME(put_key), + FUNC_NAME(get_key), + FUNC_NAME(remove_key), + FUNC_NAME(list_keys), +}; + +int main(int argc, char **argv) { + int i, ret; + for (i = 0 ; i < (int)(sizeof(all_tests)/sizeof(TESTFUNC)) ; ++i) { + setup(); + if ((ret = all_tests[i].func()) != EXIT_SUCCESS) { + fprintf(stderr, "ERROR in function %s\n", all_tests[i].name); + return ret; + } else { + fprintf(stderr, "function %s PASSED!\n", all_tests[i].name); + } + teardown(); + } + return EXIT_SUCCESS; +} diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index a3456c756404f..79bd6e7f55b1c 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -163,6 +163,10 @@ public abstract class AccessibilityService extends Service { } } + /** + * Implement to return the implementation of the internal accessibility + * service interface. Subclasses should not override. + */ @Override public final IBinder onBind(Intent intent) { return new IEventListenerWrapper(this); diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index ba6cc32808d41..447512a01d103 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -1085,6 +1085,23 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeInt(result); return true; } + + case KILL_APPLICATION_WITH_UID_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + String pkg = data.readString(); + int uid = data.readInt(); + killApplicationWithUid(pkg, uid); + reply.writeNoException(); + return true; + } + + case CLOSE_SYSTEM_DIALOGS_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + String reason = data.readString(); + closeSystemDialogs(reason); + reply.writeNoException(); + return true; + } } return super.onTransact(code, data, reply, flags); @@ -2368,6 +2385,29 @@ class ActivityManagerProxy implements IActivityManager data.recycle(); return result; } + + public void killApplicationWithUid(String pkg, int uid) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeString(pkg); + data.writeInt(uid); + mRemote.transact(KILL_APPLICATION_WITH_UID_TRANSACTION, data, reply, 0); + reply.readException(); + data.recycle(); + reply.recycle(); + } + + public void closeSystemDialogs(String reason) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeString(reason); + mRemote.transact(CLOSE_SYSTEM_DIALOGS_TRANSACTION, data, reply, 0); + reply.readException(); + data.recycle(); + reply.recycle(); + } private IBinder mRemote; } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 76b47f1140c38..32a289122cf2b 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -177,11 +177,17 @@ public final class ActivityThread { synchronized (mPackages) { // Resources is app scale dependent. ResourcesKey key = new ResourcesKey(resDir, compInfo.applicationScale); - //Log.w(TAG, "getTopLevelResources: " + resDir); + if (false) { + Log.w(TAG, "getTopLevelResources: " + resDir + " / " + + compInfo.applicationScale); + } WeakReference wr = mActiveResources.get(key); Resources r = wr != null ? wr.get() : null; if (r != null && r.getAssets().isUpToDate()) { - //Log.w(TAG, "Returning cached resources " + r + " " + resDir); + if (false) { + Log.w(TAG, "Returning cached resources " + r + " " + resDir + + ": appScale=" + r.getCompatibilityInfo().applicationScale); + } return r; } @@ -198,7 +204,11 @@ public final class ActivityThread { //Log.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics); DisplayMetrics metrics = getDisplayMetricsLocked(false); r = new Resources(assets, metrics, getConfiguration(), compInfo); - //Log.i(TAG, "Created app resources " + r + ": " + r.getConfiguration()); + if (false) { + Log.i(TAG, "Created app resources " + resDir + " " + r + ": " + + r.getConfiguration() + " appScale=" + + r.getCompatibilityInfo().applicationScale); + } // XXX need to remove entries when weak references go away mActiveResources.put(key, new WeakReference(r)); return r; @@ -3624,7 +3634,7 @@ public final class ActivityThread { Locale.setDefault(config.locale); } - Resources.updateSystemConfiguration(config, null); + Resources.updateSystemConfiguration(config, dm); ApplicationContext.ApplicationPackageManager.configurationChanged(); //Log.i(TAG, "Configuration changed in " + currentPackageName()); @@ -3743,6 +3753,14 @@ public final class ActivityThread { data.info = getPackageInfoNoCheck(data.appInfo); + /** + * Switch this process to density compatibility mode if needed. + */ + if ((data.appInfo.flags&ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) + == 0) { + Bitmap.setDefaultDensity(DisplayMetrics.DENSITY_DEFAULT); + } + if (data.debugMode != IApplicationThread.DEBUG_OFF) { // XXX should have option to change the port. Debug.changeDebugPort(8100); diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java index afb2fe99c2e06..92929ea56748e 100644 --- a/core/java/android/app/ApplicationContext.java +++ b/core/java/android/app/ApplicationContext.java @@ -541,7 +541,10 @@ class ApplicationContext extends Context { if (fd != null) { Bitmap bm = BitmapFactory.decodeFileDescriptor(fd.getFileDescriptor()); if (bm != null) { - return new BitmapDrawable(bm); + // For now clear the density until we figure out how + // to deal with it for wallpapers. + bm.setDensity(0); + return new BitmapDrawable(getResources(), bm); } } } catch (RemoteException e) { @@ -1949,6 +1952,15 @@ class ApplicationContext extends Context { try { Resources r = getResourcesForApplication(appInfo); dr = r.getDrawable(resid); + if (false) { + RuntimeException e = new RuntimeException("here"); + e.fillInStackTrace(); + Log.w(TAG, "Getting drawable 0x" + Integer.toHexString(resid) + + " from package " + packageName + + ": app scale=" + r.getCompatibilityInfo().applicationScale + + ", caller scale=" + mContext.getResources().getCompatibilityInfo().applicationScale, + e); + } if (DEBUG_ICONS) Log.v(TAG, "Getting drawable 0x" + Integer.toHexString(resid) + " from " + r + ": " + dr); @@ -2036,10 +2048,9 @@ class ApplicationContext extends Context { if (app.packageName.equals("system")) { return mContext.mMainThread.getSystemContext().getResources(); } - ActivityThread.PackageInfo pi = mContext.mMainThread.getPackageInfoNoCheck(app); Resources r = mContext.mMainThread.getTopLevelResources( app.uid == Process.myUid() ? app.sourceDir - : app.publicSourceDir, pi); + : app.publicSourceDir, mContext.mPackageInfo); if (r != null) { return r; } diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 95b376cce673d..f6ef549d84277 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -266,7 +266,11 @@ public interface IActivityManager extends IInterface { Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, boolean onlyIfNeeded) throws RemoteException; - + + public void killApplicationWithUid(String pkg, int uid) throws RemoteException; + + public void closeSystemDialogs(String reason) throws RemoteException; + /* * Private non-Binder interfaces */ @@ -421,4 +425,6 @@ public interface IActivityManager extends IInterface { int REGISTER_ACTIVITY_WATCHER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+92; int UNREGISTER_ACTIVITY_WATCHER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+93; int START_ACTIVITY_IN_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+94; + int KILL_APPLICATION_WITH_UID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+95; + int CLOSE_SYSTEM_DIALOGS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+96; } diff --git a/core/java/android/app/IActivityWatcher.aidl b/core/java/android/app/IActivityWatcher.aidl index 5d36e3fdb5993..6737545de88f4 100644 --- a/core/java/android/app/IActivityWatcher.aidl +++ b/core/java/android/app/IActivityWatcher.aidl @@ -23,4 +23,5 @@ package android.app; */ oneway interface IActivityWatcher { void activityResuming(int activityId); + void closingSystemDialogs(String reason); } diff --git a/core/java/android/app/LauncherActivity.java b/core/java/android/app/LauncherActivity.java index accdda9ba599b..d788c43d7d632 100644 --- a/core/java/android/app/LauncherActivity.java +++ b/core/java/android/app/LauncherActivity.java @@ -297,7 +297,7 @@ public abstract class LauncherActivity extends ListActivity { icon.setBounds(x, y, x + width, y + height); icon.draw(canvas); icon.setBounds(mOldBounds); - icon = new BitmapDrawable(thumb); + icon = new BitmapDrawable(getResources(), thumb); } else if (iconWidth < width && iconHeight < height) { final Bitmap.Config c = Bitmap.Config.ARGB_8888; final Bitmap thumb = Bitmap.createBitmap(mIconWidth, mIconHeight, c); @@ -309,7 +309,7 @@ public abstract class LauncherActivity extends ListActivity { icon.setBounds(x, y, x + iconWidth, y + iconHeight); icon.draw(canvas); icon.setBounds(mOldBounds); - icon = new BitmapDrawable(thumb); + icon = new BitmapDrawable(getResources(), thumb); } } diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java index f9c38f998c35a..f7479bcdb8bf0 100644 --- a/core/java/android/app/PendingIntent.java +++ b/core/java/android/app/PendingIntent.java @@ -273,11 +273,6 @@ 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 * @@ -285,7 +280,7 @@ public final class PendingIntent implements Parcelable { * */ public IntentSender getIntentSender() { - return new IntentSenderWrapper(mTarget); + return new IntentSender(mTarget); } /** diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java index 27c637652d5ef..18e4a528ec46b 100644 --- a/core/java/android/app/SearchDialog.java +++ b/core/java/android/app/SearchDialog.java @@ -34,7 +34,10 @@ import android.graphics.drawable.Animatable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; import android.os.SystemClock; +import android.provider.Browser; import android.server.search.SearchableInfo; import android.speech.RecognizerIntent; import android.text.Editable; @@ -42,11 +45,13 @@ import android.text.InputType; import android.text.TextUtils; import android.text.TextWatcher; import android.text.util.Regex; +import android.util.AndroidRuntimeException; import android.util.AttributeSet; import android.util.Log; import android.view.ContextThemeWrapper; import android.view.Gravity; import android.view.KeyEvent; +import android.view.Menu; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; @@ -240,7 +245,12 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS } return success; } - + + private boolean isInRealAppSearch() { + return !mGlobalSearchMode + && (mPreviousComponents == null || mPreviousComponents.isEmpty()); + } + /** * Called in response to a press of the hard search button in * {@link #onKeyDown(int, KeyEvent)}, this method toggles between in-app @@ -260,6 +270,16 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS if (!mGlobalSearchMode) { mStoredComponentName = mLaunchComponent; mStoredAppSearchData = mAppSearchData; + + // If this is the browser, we have a special case to not show the icon to the left + // of the text field, for extra space for url entry (this should be reconciled in + // Eclair). So special case a second tap of the search button to remove any + // already-entered text so that we can be sure to show the "Quick Search Box" hint + // text to still make it clear to the user that we've jumped out to global search. + // + // TODO: When the browser icon issue is reconciled in Eclair, remove this special case. + if (isBrowserSearch()) currentSearchText = ""; + return doShow(currentSearchText, false, null, mAppSearchData, true); } else { if (mStoredComponentName != null) { @@ -531,12 +551,14 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS // we dismiss the entire dialog instead mSearchAutoComplete.setDropDownDismissedOnCompletion(false); - if (mGlobalSearchMode) { + if (!isInRealAppSearch()) { mSearchAutoComplete.setDropDownAlwaysVisible(true); // fill space until results come in } else { mSearchAutoComplete.setDropDownAlwaysVisible(false); } + mSearchAutoComplete.setForceIgnoreOutsideTouch(true); + // attach the suggestions adapter, if suggestions are available // The existence of a suggestions authority is the proxy for "suggestions available here" if (mSearchable.getSuggestAuthority() != null) { @@ -565,7 +587,11 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS } private void updateSearchAppIcon() { - if (mGlobalSearchMode) { + // In Donut, we special-case the case of the browser to hide the app icon as if it were + // global search, for extra space for url entry. + // + // TODO: Remove this special case once the issue has been reconciled in Eclair. + if (mGlobalSearchMode || isBrowserSearch()) { mAppIcon.setImageResource(0); mAppIcon.setVisibility(View.GONE); mSearchPlate.setPadding(SEARCH_PLATE_LEFT_PADDING_GLOBAL, @@ -657,6 +683,49 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS mVoiceButton.setVisibility(visibility); } + /** + * Hack to determine whether this is the browser, so we can remove the browser icon + * to the left of the search field, as a special requirement for Donut. + * + * TODO: For Eclair, reconcile this with the rest of the global search UI. + */ + private boolean isBrowserSearch() { + return mLaunchComponent.flattenToShortString().startsWith("com.android.browser/"); + } + + /* + * Menu. + */ + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Show search settings menu item if anyone handles the intent for it + Intent settingsIntent = new Intent(SearchManager.INTENT_ACTION_SEARCH_SETTINGS); + settingsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + PackageManager pm = getContext().getPackageManager(); + ActivityInfo activityInfo = settingsIntent.resolveActivityInfo(pm, 0); + if (activityInfo != null) { + settingsIntent.setClassName(activityInfo.applicationInfo.packageName, + activityInfo.name); + CharSequence label = activityInfo.loadLabel(getContext().getPackageManager()); + menu.add(Menu.NONE, Menu.NONE, Menu.NONE, label) + .setIcon(android.R.drawable.ic_menu_preferences) + .setAlphabeticShortcut('P') + .setIntent(settingsIntent); + return true; + } + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onMenuOpened(int featureId, Menu menu) { + // The menu shows up above the IME, regardless of whether it is in front + // of the drop-down or not. This looks weird when there is no IME, so + // we make sure it is visible. + mSearchAutoComplete.ensureImeVisible(); + return super.onMenuOpened(featureId, menu); + } + /** * Listeners of various types */ @@ -794,7 +863,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS if (!event.isSystem() && (keyCode != KeyEvent.KEYCODE_DPAD_UP) && - (keyCode != KeyEvent.KEYCODE_DPAD_DOWN) && (keyCode != KeyEvent.KEYCODE_DPAD_LEFT) && (keyCode != KeyEvent.KEYCODE_DPAD_RIGHT) && (keyCode != KeyEvent.KEYCODE_DPAD_CENTER)) { @@ -835,6 +903,12 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS getContext().startActivity(mVoiceWebSearchIntent); } else if (mSearchable.getVoiceSearchLaunchRecognizer()) { Intent appSearchIntent = createVoiceAppSearchIntent(mVoiceAppSearchIntent); + + // Stop the existing search before starting voice search, or else we'll end + // up showing the search dialog again once we return to the app. + ((SearchManager) getContext().getSystemService(Context.SEARCH_SERVICE)). + stopSearch(); + getContext().startActivity(appSearchIntent); } } catch (ActivityNotFoundException e) { @@ -1093,7 +1167,8 @@ 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, null, query, null, + String action = mGlobalSearchMode ? Intent.ACTION_WEB_SEARCH : Intent.ACTION_SEARCH; + Intent intent = createIntent(action, null, null, query, null, actionKey, actionMsg); launchIntent(intent); } @@ -1169,11 +1244,11 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS // ensure the icons will work for global search cv.put(SearchManager.SUGGEST_COLUMN_ICON_1, wrapIconForPackage( - source, + mSearchable.getSuggestPackage(), getColumnString(c, SearchManager.SUGGEST_COLUMN_ICON_1))); cv.put(SearchManager.SUGGEST_COLUMN_ICON_2, wrapIconForPackage( - source, + mSearchable.getSuggestPackage(), getColumnString(c, SearchManager.SUGGEST_COLUMN_ICON_2))); // the rest can be passed through directly @@ -1212,11 +1287,11 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS * Wraps an icon for a particular package. If the icon is a resource id, it is converted into * an android.resource:// URI. * - * @param source The source of the icon + * @param packageName The source of the icon * @param icon The icon retrieved from a suggestion column * @return An icon string appropriate for the package. */ - private String wrapIconForPackage(ComponentName source, String icon) { + private String wrapIconForPackage(String packageName, String icon) { if (icon == null || icon.length() == 0 || "0".equals(icon)) { // SearchManager specifies that null or zero can be returned to indicate // no icon. We also allow empty string. @@ -1224,7 +1299,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS } else if (!Character.isDigit(icon.charAt(0))){ return icon; } else { - String packageName = source.getPackageName(); return new Uri.Builder() .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE) .authority(packageName) @@ -1245,16 +1319,133 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS return; } Log.d(LOG_TAG, "launching " + intent); - getContext().startActivity(intent); - - // in global search mode, SearchDialogWrapper#performActivityResuming will handle hiding - // the dialog when the next activity starts, but for in-app search, we still need to - // dismiss the dialog. - if (!mGlobalSearchMode) { - dismiss(); + try { + // in global search mode, we send the activity straight to the original suggestion + // source. this is because GlobalSearch may not have permission to launch the + // intent, and to avoid the extra step of going through GlobalSearch. + if (mGlobalSearchMode) { + launchGlobalSearchIntent(intent); + } else { + // If the intent was created from a suggestion, it will always have an explicit + // component here. + Log.i(LOG_TAG, "Starting (as ourselves) " + intent.toURI()); + getContext().startActivity(intent); + // If the search switches to a different activity, + // SearchDialogWrapper#performActivityResuming + // will handle hiding the dialog when the next activity starts, but for + // real in-app search, we still need to dismiss the dialog. + if (isInRealAppSearch()) { + dismiss(); + } + } + } catch (RuntimeException ex) { + Log.e(LOG_TAG, "Failed launch activity: " + intent, ex); } } - + + private void launchGlobalSearchIntent(Intent intent) { + final String packageName; + // GlobalSearch puts the original source of the suggestion in the + // 'component name' column. If set, we send the intent to that activity. + // We trust GlobalSearch to always set this to the suggestion source. + String intentComponent = intent.getStringExtra(SearchManager.COMPONENT_NAME_KEY); + if (intentComponent != null) { + ComponentName componentName = ComponentName.unflattenFromString(intentComponent); + intent.setComponent(componentName); + intent.removeExtra(SearchManager.COMPONENT_NAME_KEY); + // Launch the intent as the suggestion source. + // This prevents sources from using the search dialog to launch + // intents that they don't have permission for themselves. + packageName = componentName.getPackageName(); + } else { + // If there is no component in the suggestion, it must be a built-in suggestion + // from GlobalSearch (e.g. "Search the web for") or the intent + // launched when pressing the search/go button in the search dialog. + // Launch the intent with the permissions of GlobalSearch. + packageName = mSearchable.getSearchActivity().getPackageName(); + } + + // Launch all global search suggestions as new tasks, since they don't relate + // to the current task. + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + setBrowserApplicationId(intent); + + startActivityInPackage(intent, packageName); + } + + /** + * If the intent is to open an HTTP or HTTPS URL, we set + * {@link Browser#EXTRA_APPLICATION_ID} so that any existing browser window that + * has been opened by us for the same URL will be reused. + */ + private void setBrowserApplicationId(Intent intent) { + Uri data = intent.getData(); + if (Intent.ACTION_VIEW.equals(intent.getAction()) && data != null) { + String scheme = data.getScheme(); + if (scheme != null && scheme.startsWith("http")) { + intent.putExtra(Browser.EXTRA_APPLICATION_ID, data.toString()); + } + } + } + + /** + * Starts an activity as if it had been started by the given package. + * + * @param intent The description of the activity to start. + * @param packageName + * @throws ActivityNotFoundException If the intent could not be resolved to + * and existing activity. + * @throws SecurityException If the package does not have permission to start + * start the activity. + * @throws AndroidRuntimeException If some other error occurs. + */ + private void startActivityInPackage(Intent intent, String packageName) { + try { + int uid = ActivityThread.getPackageManager().getPackageUid(packageName); + if (uid < 0) { + throw new AndroidRuntimeException("Package UID not found " + packageName); + } + String resolvedType = intent.resolveTypeIfNeeded(getContext().getContentResolver()); + IBinder resultTo = null; + String resultWho = null; + int requestCode = -1; + boolean onlyIfNeeded = false; + Log.i(LOG_TAG, "Starting (uid " + uid + ", " + packageName + ") " + intent.toURI()); + int result = ActivityManagerNative.getDefault().startActivityInPackage( + uid, intent, resolvedType, resultTo, resultWho, requestCode, onlyIfNeeded); + checkStartActivityResult(result, intent); + } catch (RemoteException ex) { + throw new AndroidRuntimeException(ex); + } + } + + // Stolen from Instrumentation.checkStartActivityResult() + private static void checkStartActivityResult(int res, Intent intent) { + if (res >= IActivityManager.START_SUCCESS) { + return; + } + switch (res) { + case IActivityManager.START_INTENT_NOT_RESOLVED: + case IActivityManager.START_CLASS_NOT_FOUND: + if (intent.getComponent() != null) + throw new ActivityNotFoundException( + "Unable to find explicit activity class " + + intent.getComponent().toShortString() + + "; have you declared this activity in your AndroidManifest.xml?"); + throw new ActivityNotFoundException( + "No Activity found to handle " + intent); + case IActivityManager.START_PERMISSION_DENIED: + throw new SecurityException("Not allowed to start activity " + + intent); + case IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT: + throw new AndroidRuntimeException( + "FORWARD_RESULT_FLAG used while also requesting a result"); + default: + throw new AndroidRuntimeException("Unknown error code " + + res + " when starting " + intent); + } + } + /** * Handles the special intent actions declared in {@link SearchManager}. * @@ -1284,13 +1475,13 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS return; } if (DBG) Log.d(LOG_TAG, "Switching to " + componentName); - - ComponentName previous = mLaunchComponent; + + pushPreviousComponent(mLaunchComponent); if (!show(componentName, mAppSearchData, false)) { Log.w(LOG_TAG, "Failed to switch to source " + componentName); + popPreviousComponent(); return; } - pushPreviousComponent(previous); String query = intent.getStringExtra(SearchManager.QUERY); setUserQuery(query); @@ -1460,8 +1651,10 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS intent.putExtra(SearchManager.ACTION_KEY, actionKey); intent.putExtra(SearchManager.ACTION_MSG, actionMsg); } - // attempt to enforce security requirement (no 3rd-party intents) - intent.setComponent(mSearchable.getSearchActivity()); + // Only allow 3rd-party intents from GlobalSearch + if (!mGlobalSearchMode) { + intent.setComponent(mSearchable.getSearchActivity()); + } return intent; } @@ -1582,6 +1775,12 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS if (mSearchDialog.backToPreviousComponent()) { return true; } + // If the drop-down obscures the keyboard, the user wouldn't see anything + // happening when pressing back, so we dismiss the entire dialog instead. + if (isInputMethodNotNeeded()) { + mSearchDialog.cancel(); + return true; + } return false; // will dismiss soft keyboard if necessary } return false; diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java index 0631ad58929ba..fd559d66cba1f 100644 --- a/core/java/android/app/SearchManager.java +++ b/core/java/android/app/SearchManager.java @@ -1214,19 +1214,14 @@ public class SearchManager public final static String POST_REFRESH_RECEIVE_DISPLAY_NOTIFY = "DialogCursorProtocol.POST_REFRESH.displayNotify"; - /** - * Just before closing the cursor. - */ - public final static int PRE_CLOSE = 1; - public final static String PRE_CLOSE_SEND_MAX_DISPLAY_POS - = "DialogCursorProtocol.PRE_CLOSE.sendDisplayPosition"; - /** * When a position has been clicked. */ public final static int CLICK = 2; public final static String CLICK_SEND_POSITION = "DialogCursorProtocol.CLICK.sendPosition"; + public final static String CLICK_SEND_MAX_DISPLAY_POS + = "DialogCursorProtocol.CLICK.sendDisplayPosition"; public final static String CLICK_RECEIVE_SELECTED_POS = "DialogCursorProtocol.CLICK.receiveSelectedPosition"; diff --git a/core/java/android/app/SuggestionsAdapter.java b/core/java/android/app/SuggestionsAdapter.java index 593b7b736cfaa..4a00e485f5670 100644 --- a/core/java/android/app/SuggestionsAdapter.java +++ b/core/java/android/app/SuggestionsAdapter.java @@ -27,6 +27,7 @@ import android.content.res.Resources; import android.database.Cursor; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; +import android.graphics.drawable.DrawableContainer; import android.graphics.drawable.StateListDrawable; import android.net.Uri; import android.os.Bundle; @@ -135,6 +136,8 @@ class SuggestionsAdapter extends ResourceCursorAdapter { private int mPreviousLength = 0; public long getPostingDelay(CharSequence constraint) { + if (constraint == null) return 0; + long delay = constraint.length() < mPreviousLength ? DELETE_KEY_POST_DELAY : 0; mPreviousLength = constraint.length(); return delay; @@ -191,35 +194,19 @@ class SuggestionsAdapter extends ResourceCursorAdapter { public void changeCursor(Cursor c) { if (DBG) Log.d(LOG_TAG, "changeCursor(" + c + ")"); - if (mCursor != null) { - callCursorPreClose(mCursor); + try { + super.changeCursor(c); + if (c != null) { + mFormatCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_FORMAT); + mText1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1); + mText2Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_2); + mIconName1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_1); + mIconName2Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_2); + mBackgroundColorCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_BACKGROUND_COLOR); + } + } catch (Exception e) { + Log.e(LOG_TAG, "error changing cursor and caching columns", e); } - - super.changeCursor(c); - if (c != null) { - mFormatCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_FORMAT); - mText1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1); - mText2Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_2); - mIconName1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_1); - mIconName2Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_2); - mBackgroundColorCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_BACKGROUND_COLOR); - } - } - - /** - * Handle sending and receiving information associated with - * {@link DialogCursorProtocol#PRE_CLOSE}. - * - * @param cursor The cursor to call. - */ - private void callCursorPreClose(Cursor cursor) { - if (!mGlobalSearchMode) return; - final Bundle request = new Bundle(); - request.putInt(DialogCursorProtocol.METHOD, DialogCursorProtocol.PRE_CLOSE); - request.putInt(DialogCursorProtocol.PRE_CLOSE_SEND_MAX_DISPLAY_POS, mMaxDisplayed); - final Bundle response = cursor.respond(request); - - mMaxDisplayed = -1; } @Override @@ -267,7 +254,9 @@ class SuggestionsAdapter extends ResourceCursorAdapter { final Bundle request = new Bundle(1); request.putInt(DialogCursorProtocol.METHOD, DialogCursorProtocol.CLICK); request.putInt(DialogCursorProtocol.CLICK_SEND_POSITION, position); + request.putInt(DialogCursorProtocol.CLICK_SEND_MAX_DISPLAY_POS, mMaxDisplayed); final Bundle response = cursor.respond(request); + mMaxDisplayed = -1; mListItemToSelect = response.getInt( DialogCursorProtocol.CLICK_RECEIVE_SELECTED_POS, SuggestionsAdapter.NONE); } diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 9e37ae448731c..25b5de37128f6 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -1283,7 +1283,8 @@ public abstract class Context { * Use with {@link #getSystemService} to retrieve an * {@blink android.backup.IBackupManager IBackupManager} for communicating * with the backup mechanism. - * + * @hide + * * @see #getSystemService */ public static final String BACKUP_SERVICE = "backup"; diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java index 45a082a9520ee..15612cefcc27a 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -135,6 +135,7 @@ public class ContextWrapper extends Context { return mBase.getPackageCodePath(); } + /** @hide */ @Override public File getSharedPrefsFile(String name) { return mBase.getSharedPrefsFile(name); diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index a5f298c5b7c9f..c62d66bc55329 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1683,53 +1683,7 @@ public class Intent implements Parcelable { @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_REBOOT = "android.intent.action.REBOOT"; - /** - * Broadcast Action: Triggers the platform Text-To-Speech engine to - * start the activity that installs the resource files on the device - * that are required for TTS to be operational. Since the installation - * of the data can be interrupted or declined by the user, the application - * shouldn't expect successful installation upon return from that intent, - * and if need be, should check installation status with - * {@link #ACTION_TTS_CHECK_TTS_DATA}. - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_TTS_INSTALL_TTS_DATA = - "android.intent.action.INSTALL_TTS_DATA"; - /** - * Broadcast Action: Starts the activity from the platform Text-To-Speech - * engine to verify the proper installation and availability of the - * resource files on the system. Upon completion, the activity will - * return one of the following codes: - * {@link android.speech.tts.TextToSpeech.Engine#CHECK_VOICE_DATA_PASS}, - * {@link android.speech.tts.TextToSpeech.Engine#CHECK_VOICE_DATA_FAIL}, - * {@link android.speech.tts.TextToSpeech.Engine#CHECK_VOICE_DATA_BAD_DATA}, - * {@link android.speech.tts.TextToSpeech.Engine#CHECK_VOICE_DATA_MISSING_DATA}, or - * {@link android.speech.tts.TextToSpeech.Engine#CHECK_VOICE_DATA_MISSING_VOLUME}. - *

Moreover, the data received in the activity result will contain the following - * fields: - *

    - *
  • {@link android.speech.tts.TextToSpeech.Engine#VOICE_DATA_ROOT_DIRECTORY} which - * indicates the path to the location of the resource files
  • , - *
  • {@link android.speech.tts.TextToSpeech.Engine#VOICE_DATA_FILES} which contains - * the list of all the resource files
  • , - *
  • and {@link android.speech.tts.TextToSpeech.Engine#VOICE_DATA_FILES_INFO} which - * contains, for each resource file, the description of the language covered by - * the file in the xxx-YYY format, where xxx is the 3-letter ISO language code, - * and YYY is the 3-letter ISO country code.
  • - *
- */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_TTS_CHECK_TTS_DATA = - "android.intent.action.CHECK_TTS_DATA"; - - /** - * Broadcast Action: The TextToSpeech synthesizer has completed processing - * all of the text in the speech queue. - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_TTS_QUEUE_PROCESSING_COMPLETED = - "android.intent.action.TTS_QUEUE_PROCESSING_COMPLETED"; // --------------------------------------------------------------------- // --------------------------------------------------------------------- @@ -2390,7 +2344,7 @@ public class Intent implements Parcelable { /** * Create an intent from a URI. This URI may encode the action, * category, and other intent fields, if it was returned by - * {@link #toUri}.. If the Intent was not generate by toUri(), its data + * {@link #toUri}. If the Intent was not generate by toUri(), its data * will be the entire URI and its action will be ACTION_VIEW. * *

The URI given here must not be relative -- that is, it must include diff --git a/core/java/android/content/IntentSender.java b/core/java/android/content/IntentSender.java index 4da49d974fd53..0e4d98498e8fe 100644 --- a/core/java/android/content/IntentSender.java +++ b/core/java/android/content/IntentSender.java @@ -52,6 +52,9 @@ import android.util.AndroidException; * categories, and components, and same flags), it will receive a IntentSender * representing the same token if that is still valid. * + *

Instances of this class can not be made directly, but rather must be + * created from an existing {@link android.app.PendingIntent} with + * {@link android.app.PendingIntent#getIntentSender() PendingIntent.getIntentSender()}. */ public class IntentSender implements Parcelable { private final IIntentSender mTarget; @@ -245,11 +248,13 @@ public class IntentSender implements Parcelable { return b != null ? new IntentSender(b) : null; } - protected IntentSender(IIntentSender target) { + /** @hide */ + public IntentSender(IIntentSender target) { mTarget = target; } - protected IntentSender(IBinder target) { + /** @hide */ + public IntentSender(IBinder target) { mTarget = IIntentSender.Stub.asInterface(target); } } diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 4a3137fc95a0f..0a42a6faf9f4b 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -131,8 +131,9 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { public static final int FLAG_UPDATED_SYSTEM_APP = 1<<7; /** - * Value for {@link #flags}: this is set of the application has set - * its android:targetSdkVersion to something >= the current SDK version. + * Value for {@link #flags}: this is set of the application has specified + * {@link android.R.styleable#AndroidManifestApplication_testOnly + * android:testOnly} to be true. */ public static final int FLAG_TEST_ONLY = 1<<8; @@ -168,21 +169,22 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { */ public static final int FLAG_RESIZEABLE_FOR_SCREENS = 1<<12; + /** + * Value for {@link #flags}: true when the application knows how to + * accomodate different screen densities. Corresponds to + * {@link android.R.styleable#AndroidManifestSupportsScreens_anyDensity + * android:anyDensity}. + */ + public static final int FLAG_SUPPORTS_SCREEN_DENSITIES = 1<<13; + /** * Value for {@link #flags}: this is false if the application has set * its android:allowBackup to false, true otherwise. * * {@hide} */ - public static final int FLAG_ALLOW_BACKUP = 1<<13; + public static final int FLAG_ALLOW_BACKUP = 1<<14; - /** - * Indicates that the application supports any densities; - * {@hide} - */ - public static final int ANY_DENSITY = -1; - static final int[] ANY_DENSITIES_ARRAY = { ANY_DENSITY }; - /** * Flags associated with the application. Any combination of * {@link #FLAG_SYSTEM}, {@link #FLAG_DEBUGGABLE}, {@link #FLAG_HAS_CODE}, @@ -227,13 +229,6 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { */ public int uid; - /** - * The list of densities in DPI that application supprots. This - * field is only set if the {@link PackageManager#GET_SUPPORTS_DENSITIES} flag was - * used when retrieving the structure. - */ - public int[] supportsDensities; - /** * 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 @@ -267,7 +262,6 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { pw.println(prefix + "enabled=" + enabled); pw.println(prefix + "manageSpaceActivityName="+manageSpaceActivityName); pw.println(prefix + "description=0x"+Integer.toHexString(descriptionRes)); - pw.println(prefix + "supportsDensities=" + supportsDensities); super.dumpBack(pw, prefix); } @@ -314,7 +308,6 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { enabled = orig.enabled; manageSpaceActivityName = orig.manageSpaceActivityName; descriptionRes = orig.descriptionRes; - supportsDensities = orig.supportsDensities; } @@ -346,7 +339,6 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { dest.writeString(manageSpaceActivityName); dest.writeString(backupAgentName); dest.writeInt(descriptionRes); - dest.writeIntArray(supportsDensities); } public static final Parcelable.Creator CREATOR @@ -377,7 +369,6 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { manageSpaceActivityName = source.readString(); backupAgentName = source.readString(); descriptionRes = source.readInt(); - supportsDensities = source.createIntArray(); } /** @@ -408,7 +399,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { */ public void disableCompatibilityMode() { flags |= (FLAG_SUPPORTS_LARGE_SCREENS | FLAG_SUPPORTS_NORMAL_SCREENS | - FLAG_SUPPORTS_SMALL_SCREENS | FLAG_RESIZEABLE_FOR_SCREENS); - supportsDensities = ANY_DENSITIES_ARRAY; + FLAG_SUPPORTS_SMALL_SCREENS | FLAG_RESIZEABLE_FOR_SCREENS | + FLAG_SUPPORTS_SCREEN_DENSITIES); } } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 941ca9e5bb74e..67bd1acd989c0 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -164,12 +164,6 @@ public abstract class PackageManager { */ public static final int GET_CONFIGURATIONS = 0x00004000; - /** - * {@link ApplicationInfo} flag: return the - * {@link ApplicationInfo#supportsDensities} that the package supports. - */ - public static final int GET_SUPPORTS_DENSITIES = 0x00008000; - /** * Resolution and querying flag: if set, only filters that support the * {@link android.content.Intent#CATEGORY_DEFAULT} will be considered for diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 93ba9599be061..33f4b52e2f94a 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -675,6 +675,7 @@ public class PackageParser { int supportsNormalScreens = 1; int supportsLargeScreens = 1; int resizeable = 1; + int anyDensity = 1; int outerDepth = parser.getDepth(); while ((type=parser.next()) != parser.END_DOCUMENT @@ -854,21 +855,6 @@ public class PackageParser { XmlUtils.skipCurrentTag(parser); - } else if (tagName.equals("supports-density")) { - sa = res.obtainAttributes(attrs, - com.android.internal.R.styleable.AndroidManifestSupportsDensity); - - int density = sa.getInteger( - com.android.internal.R.styleable.AndroidManifestSupportsDensity_density, -1); - - sa.recycle(); - - if (density != -1 && !pkg.supportsDensityList.contains(density)) { - pkg.supportsDensityList.add(density); - } - - XmlUtils.skipCurrentTag(parser); - } else if (tagName.equals("supports-screens")) { sa = res.obtainAttributes(attrs, com.android.internal.R.styleable.AndroidManifestSupportsScreens); @@ -887,6 +873,9 @@ public class PackageParser { resizeable = sa.getInteger( com.android.internal.R.styleable.AndroidManifestSupportsScreens_resizeable, supportsLargeScreens); + anyDensity = sa.getInteger( + com.android.internal.R.styleable.AndroidManifestSupportsScreens_anyDensity, + anyDensity); sa.recycle(); @@ -962,7 +951,7 @@ public class PackageParser { if (supportsSmallScreens < 0 || (supportsSmallScreens > 0 && pkg.applicationInfo.targetSdkVersion - >= android.os.Build.VERSION_CODES.CUR_DEVELOPMENT)) { + >= android.os.Build.VERSION_CODES.DONUT)) { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS; } if (supportsNormalScreens != 0) { @@ -970,32 +959,19 @@ public class PackageParser { } if (supportsLargeScreens < 0 || (supportsLargeScreens > 0 && pkg.applicationInfo.targetSdkVersion - >= android.os.Build.VERSION_CODES.CUR_DEVELOPMENT)) { + >= android.os.Build.VERSION_CODES.DONUT)) { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS; } if (resizeable < 0 || (resizeable > 0 && pkg.applicationInfo.targetSdkVersion - >= android.os.Build.VERSION_CODES.CUR_DEVELOPMENT)) { + >= android.os.Build.VERSION_CODES.DONUT)) { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS; } - int densities[] = null; - int size = pkg.supportsDensityList.size(); - if (size > 0) { - densities = pkg.supportsDensities = new int[size]; - List densityList = pkg.supportsDensityList; - for (int i = 0; i < size; i++) { - densities[i] = densityList.get(i); - } + if (anyDensity < 0 || (anyDensity > 0 + && pkg.applicationInfo.targetSdkVersion + >= android.os.Build.VERSION_CODES.DONUT)) { + pkg.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES; } - /** - * TODO: enable this before code freeze. b/1967935 - * * - if ((densities == null || densities.length == 0) - && (pkg.applicationInfo.targetSdkVersion - >= android.os.Build.VERSION_CODES.CUR_DEVELOPMENT)) { - pkg.supportsDensities = ApplicationInfo.ANY_DENSITIES_ARRAY; - } - */ return pkg; } @@ -2446,9 +2422,6 @@ public class PackageParser { // We store the application meta-data independently to avoid multiple unwanted references public Bundle mAppMetaData = null; - public final ArrayList supportsDensityList = new ArrayList(); - public int[] supportsDensities = null; - // If this is a 3rd party app, this is the path of the zip file. public String mPath; @@ -2630,10 +2603,6 @@ public class PackageParser { && p.usesLibraryFiles != null) { return true; } - if ((flags & PackageManager.GET_SUPPORTS_DENSITIES) != 0 - && p.supportsDensities != null) { - return true; - } return false; } @@ -2656,9 +2625,6 @@ public class PackageParser { if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0) { ai.sharedLibraryFiles = p.usesLibraryFiles; } - if ((flags & PackageManager.GET_SUPPORTS_DENSITIES) != 0) { - ai.supportsDensities = p.supportsDensities; - } if (!sCompatibilityModeEnabled) { ai.disableCompatibilityMode(); } diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index 5c7b01fa0ccb0..8ebe0932c2140 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -637,12 +637,13 @@ public final class AssetManager { * mRetData. */ private native final int loadResourceBagValue(int ident, int bagEntryId, TypedValue outValue, boolean resolve); - /*package*/ static final int STYLE_NUM_ENTRIES = 5; + /*package*/ static final int STYLE_NUM_ENTRIES = 6; /*package*/ static final int STYLE_TYPE = 0; /*package*/ static final int STYLE_DATA = 1; /*package*/ static final int STYLE_ASSET_COOKIE = 2; /*package*/ static final int STYLE_RESOURCE_ID = 3; /*package*/ static final int STYLE_CHANGING_CONFIGURATIONS = 4; + /*package*/ static final int STYLE_DENSITY = 5; /*package*/ native static final boolean applyStyle(int theme, int defStyleAttr, int defStyleRes, int xmlParser, int[] inAttrs, int[] outValues, int[] outIndices); diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java index 517551ec8e149..50faf57a096f7 100644 --- a/core/java/android/content/res/CompatibilityInfo.java +++ b/core/java/android/content/res/CompatibilityInfo.java @@ -131,41 +131,15 @@ public class CompatibilityInfo { mCompatibilityFlags |= EXPANDABLE | CONFIGURED_EXPANDABLE; } - float packageDensityScale = -1.0f; - int packageDensity = 0; - if (appInfo.supportsDensities != null) { - int minDiff = Integer.MAX_VALUE; - for (int density : appInfo.supportsDensities) { - if (density == ApplicationInfo.ANY_DENSITY) { - packageDensity = DisplayMetrics.DENSITY_DEVICE; - packageDensityScale = 1.0f; - break; - } - int tmpDiff = Math.abs(DisplayMetrics.DENSITY_DEVICE - density); - if (tmpDiff == 0) { - packageDensity = DisplayMetrics.DENSITY_DEVICE; - packageDensityScale = 1.0f; - break; - } - // prefer higher density (appScale>1.0), unless that's only option. - if (tmpDiff < minDiff && packageDensityScale < 1.0f) { - packageDensity = density; - packageDensityScale = DisplayMetrics.DENSITY_DEVICE / (float) density; - minDiff = tmpDiff; - } - } - } - if (packageDensityScale > 0.0f) { - applicationDensity = packageDensity; - applicationScale = packageDensityScale; + if ((appInfo.flags & ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES) != 0) { + applicationDensity = DisplayMetrics.DENSITY_DEVICE; + applicationScale = 1.0f; + applicationInvertedScale = 1.0f; } else { applicationDensity = DisplayMetrics.DENSITY_DEFAULT; - applicationScale = - DisplayMetrics.DENSITY_DEVICE / (float) DisplayMetrics.DENSITY_DEFAULT; - } - - applicationInvertedScale = 1.0f / applicationScale; - if (applicationScale != 1.0f) { + applicationScale = DisplayMetrics.DENSITY_DEVICE + / (float) DisplayMetrics.DENSITY_DEFAULT; + applicationInvertedScale = 1.0f / applicationScale; mCompatibilityFlags |= SCALING_REQUIRED; } } @@ -254,20 +228,11 @@ public class CompatibilityInfo { } /** - * Returns the translator which can translate the coordinates of the window. - * There are five different types of Translator. + * Returns the translator which translates the coordinates in compatibility mode. * @param params the window's parameter */ - public Translator getTranslator(WindowManager.LayoutParams params) { - if ( (mCompatibilityFlags & SCALING_EXPANDABLE_MASK) - == (EXPANDABLE|LARGE_SCREENS)) { - if (DBG) Log.d(TAG, "no translation required"); - return null; - } - if (!isScalingRequired()) { - return null; - } - return new Translator(); + public Translator getTranslator() { + return isScalingRequired() ? new Translator() : null; } /** diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java index 3a32c03122025..016ee7f4c7df2 100644 --- a/core/java/android/content/res/TypedArray.java +++ b/core/java/android/content/res/TypedArray.java @@ -654,6 +654,7 @@ public class TypedArray { outValue.assetCookie = data[index+AssetManager.STYLE_ASSET_COOKIE]; outValue.resourceId = data[index+AssetManager.STYLE_RESOURCE_ID]; outValue.changingConfigurations = data[index+AssetManager.STYLE_CHANGING_CONFIGURATIONS]; + outValue.density = data[index+AssetManager.STYLE_DENSITY]; if (type == TypedValue.TYPE_STRING) { outValue.string = loadStringValueAt(index); } diff --git a/core/java/android/database/MatrixCursor.java b/core/java/android/database/MatrixCursor.java index cf5a57358c986..d5c3a32d884d2 100644 --- a/core/java/android/database/MatrixCursor.java +++ b/core/java/android/database/MatrixCursor.java @@ -214,53 +214,64 @@ public class MatrixCursor extends AbstractCursor { // AbstractCursor implementation. + @Override public int getCount() { return rowCount; } + @Override public String[] getColumnNames() { return columnNames; } + @Override public String getString(int column) { - return String.valueOf(get(column)); + Object value = get(column); + if (value == null) return null; + return value.toString(); } + @Override public short getShort(int column) { Object value = get(column); - return (value instanceof String) - ? Short.valueOf((String) value) - : ((Number) value).shortValue(); + if (value == null) return 0; + if (value instanceof Number) return ((Number) value).shortValue(); + return Short.parseShort(value.toString()); } + @Override public int getInt(int column) { Object value = get(column); - return (value instanceof String) - ? Integer.valueOf((String) value) - : ((Number) value).intValue(); + if (value == null) return 0; + if (value instanceof Number) return ((Number) value).intValue(); + return Integer.parseInt(value.toString()); } + @Override public long getLong(int column) { Object value = get(column); - return (value instanceof String) - ? Long.valueOf((String) value) - : ((Number) value).longValue(); + if (value == null) return 0; + if (value instanceof Number) return ((Number) value).longValue(); + return Long.parseLong(value.toString()); } + @Override public float getFloat(int column) { Object value = get(column); - return (value instanceof String) - ? Float.valueOf((String) value) - : ((Number) value).floatValue(); + if (value == null) return 0.0f; + if (value instanceof Number) return ((Number) value).floatValue(); + return Float.parseFloat(value.toString()); } + @Override public double getDouble(int column) { Object value = get(column); - return (value instanceof String) - ? Double.valueOf((String) value) - : ((Number) value).doubleValue(); + if (value == null) return 0.0d; + if (value instanceof Number) return ((Number) value).doubleValue(); + return Double.parseDouble(value.toString()); } + @Override public boolean isNull(int column) { return get(column) == null; } diff --git a/core/java/android/gesture/GestureLibrary.java b/core/java/android/gesture/GestureLibrary.java index a29c2c83cfbf0..ec2e78c9df2f3 100644 --- a/core/java/android/gesture/GestureLibrary.java +++ b/core/java/android/gesture/GestureLibrary.java @@ -35,6 +35,7 @@ public abstract class GestureLibrary { return false; } + /** @hide */ public Learner getLearner() { return mStore.getLearner(); } diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java index 8b474d567ac90..9c9c14395f15a 100755 --- a/core/java/android/inputmethodservice/KeyboardView.java +++ b/core/java/android/inputmethodservice/KeyboardView.java @@ -32,6 +32,7 @@ import android.os.Handler; import android.os.Message; import android.os.SystemClock; import android.util.AttributeSet; +import android.util.TypedValue; import android.view.GestureDetector; import android.view.Gravity; import android.view.LayoutInflater; @@ -161,8 +162,8 @@ public class KeyboardView extends View implements View.OnClickListener { private static final int MSG_REMOVE_PREVIEW = 2; private static final int MSG_REPEAT = 3; private static final int MSG_LONGPRESS = 4; - - private static final int DELAY_BEFORE_PREVIEW = 70; + + private static final int DELAY_BEFORE_PREVIEW = 40; private static final int DELAY_AFTER_PREVIEW = 60; private int mVerticalCorrection; @@ -825,10 +826,10 @@ public class KeyboardView extends View implements View.OnClickListener { mPreviewText.setCompoundDrawables(null, null, null, null); mPreviewText.setText(getPreviewText(key)); if (key.label.length() > 1 && key.codes.length < 2) { - mPreviewText.setTextSize(mKeyTextSize); + mPreviewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mKeyTextSize); mPreviewText.setTypeface(Typeface.DEFAULT_BOLD); } else { - mPreviewText.setTextSize(mPreviewTextSizeLarge); + mPreviewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, mPreviewTextSizeLarge); mPreviewText.setTypeface(Typeface.DEFAULT); } } diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java index 7d03801d7bd10..afe219c8fe88d 100644 --- a/core/java/android/provider/CallLog.java +++ b/core/java/android/provider/CallLog.java @@ -151,34 +151,20 @@ public class CallLog { int presentation, int callType, long start, int duration) { final ContentResolver resolver = context.getContentResolver(); - // TODO(Moto): Which is correct: original code, this only changes the - // number if the number is empty and never changes the caller info name. - if (false) { - if (TextUtils.isEmpty(number)) { - if (presentation == Connection.PRESENTATION_RESTRICTED) { - number = CallerInfo.PRIVATE_NUMBER; - } else if (presentation == Connection.PRESENTATION_PAYPHONE) { - number = CallerInfo.PAYPHONE_NUMBER; - } else { - number = CallerInfo.UNKNOWN_NUMBER; - } - } - } else { - // NEWCODE: From Motorola - - //If this is a private number then set the number to Private, otherwise check - //if the number field is empty and set the number to Unavailable + // If this is a private number then set the number to Private, otherwise check + // if the number field is empty and set the number to Unavailable if (presentation == Connection.PRESENTATION_RESTRICTED) { number = CallerInfo.PRIVATE_NUMBER; - ci.name = ""; + if (ci != null) ci.name = ""; } else if (presentation == Connection.PRESENTATION_PAYPHONE) { number = CallerInfo.PAYPHONE_NUMBER; - ci.name = ""; - } else if (TextUtils.isEmpty(number) || presentation == Connection.PRESENTATION_UNKNOWN) { + if (ci != null) ci.name = ""; + } else if (TextUtils.isEmpty(number) + || presentation == Connection.PRESENTATION_UNKNOWN) { number = CallerInfo.UNKNOWN_NUMBER; - ci.name = ""; + if (ci != null) ci.name = ""; } - } + ContentValues values = new ContentValues(5); values.put(NUMBER, number); diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index b5440f2446261..9a9ddc9f39ae5 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -2916,6 +2916,13 @@ public final class Settings { */ public static final String VENDING_TOS_URL = "vending_tos_url"; + /** + * URL to navigate to in browser (not Market) when the terms of service + * for Vending Machine could not be accessed due to bad network + * connection. + */ + public static final String VENDING_TOS_MISSING_URL = "vending_tos_missing_url"; + /** * Whether to use sierraqa instead of sierra tokens for the purchase flow in * Vending Machine. diff --git a/core/java/android/server/search/SearchDialogWrapper.java b/core/java/android/server/search/SearchDialogWrapper.java index d3ef5de8634fb..49718cb0acd0f 100644 --- a/core/java/android/server/search/SearchDialogWrapper.java +++ b/core/java/android/server/search/SearchDialogWrapper.java @@ -63,6 +63,8 @@ implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener { private static final int MSG_STOP_SEARCH = 2; // arg1 is activity id private static final int MSG_ACTIVITY_RESUMING = 3; + // obj is the reason + private static final int MSG_CLOSING_SYSTEM_DIALOGS = 4; private static final String KEY_INITIAL_QUERY = "q"; private static final String KEY_LAUNCH_ACTIVITY = "a"; @@ -127,8 +129,7 @@ implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener { private void registerBroadcastReceiver() { if (!mReceiverRegistered) { IntentFilter filter = new IntentFilter( - Intent.ACTION_CLOSE_SYSTEM_DIALOGS); - filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); + Intent.ACTION_CONFIGURATION_CHANGED); mContext.registerReceiver(mBroadcastReceiver, filter, null, mSearchUiThread); mReceiverRegistered = true; @@ -149,12 +150,7 @@ implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); - if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) { - if (!"search".equals(intent.getStringExtra("reason"))) { - if (DBG) debug(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); - performStopSearch(); - } - } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) { + if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) { if (DBG) debug(Intent.ACTION_CONFIGURATION_CHANGED); performOnConfigurationChanged(); } @@ -190,6 +186,9 @@ implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener { msgData.putBundle(KEY_APP_SEARCH_DATA, appSearchData); msgData.putInt(KEY_IDENT, ident); mSearchUiThread.sendMessage(msg); + // be a little more eager in setting this so isVisible will return the correct value if + // called immediately after startSearch + mVisible = true; } /** @@ -199,6 +198,9 @@ implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener { public void stopSearch() { if (DBG) debug("stopSearch()"); mSearchUiThread.sendEmptyMessage(MSG_STOP_SEARCH); + // be a little more eager in setting this so isVisible will return the correct value if + // called immediately after stopSearch + mVisible = false; } /** @@ -213,6 +215,18 @@ implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener { mSearchUiThread.sendMessage(msg); } + /** + * Handles closing of system windows/dialogs + * Can be called from any thread. + */ + public void closingSystemDialogs(String reason) { + if (DBG) debug("closingSystemDialogs(reason=" + reason + ")"); + Message msg = Message.obtain(); + msg.what = MSG_CLOSING_SYSTEM_DIALOGS; + msg.obj = reason; + mSearchUiThread.sendMessage(msg); + } + // // Implementation methods that run on the search UI thread // @@ -238,6 +252,9 @@ implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener { case MSG_ACTIVITY_RESUMING: performActivityResuming(msg.arg1); break; + case MSG_CLOSING_SYSTEM_DIALOGS: + performClosingSystemDialogs((String)msg.obj); + break; } } @@ -323,6 +340,19 @@ implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener { } } + /** + * Updates due to system dialogs being closed + * This must be called on the search UI thread. + */ + void performClosingSystemDialogs(String reason) { + if (DBG) debug("performClosingSystemDialogs(): mStartedIdent=" + + mStartedIdent + ", reason: " + reason); + if (!"search".equals(reason)) { + if (DBG) debug(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); + performStopSearch(); + } + } + /** * Must be called from the search UI thread. */ diff --git a/core/java/android/server/search/SearchManagerService.java b/core/java/android/server/search/SearchManagerService.java index fdeb8f9e3fc23..afed4a4968ce2 100644 --- a/core/java/android/server/search/SearchManagerService.java +++ b/core/java/android/server/search/SearchManagerService.java @@ -138,6 +138,11 @@ public class SearchManagerService extends ISearchManager.Stub { if (mSearchDialog == null) return; mSearchDialog.activityResuming(activityId); } + public void closingSystemDialogs(String reason) { + if (DBG) Log.i("foo", "********************** closing dialogs: " + reason); + if (mSearchDialog == null) return; + mSearchDialog.closingSystemDialogs(reason); + } }; /** diff --git a/core/java/android/server/search/SearchableInfo.java b/core/java/android/server/search/SearchableInfo.java index 045b0c2f0874f..69ef98c0c3ce8 100644 --- a/core/java/android/server/search/SearchableInfo.java +++ b/core/java/android/server/search/SearchableInfo.java @@ -102,6 +102,14 @@ public final class SearchableInfo implements Parcelable { return mSuggestAuthority; } + /** + * Gets the name of the package where the suggestion provider lives, + * or {@code null}. + */ + public String getSuggestPackage() { + return mSuggestProviderPackage; + } + /** * Gets the component name of the searchable activity. */ diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java index bb6b4b0385d84..b033c6a7cdc23 100755 --- a/core/java/android/speech/tts/TextToSpeech.java +++ b/core/java/android/speech/tts/TextToSpeech.java @@ -18,6 +18,8 @@ package android.speech.tts; import android.speech.tts.ITts; import android.speech.tts.ITtsCallback; +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -41,51 +43,60 @@ public class TextToSpeech { /** * Denotes a successful operation. */ - public static final int TTS_SUCCESS = 0; + public static final int SUCCESS = 0; /** * Denotes a generic operation failure. */ - public static final int TTS_ERROR = -1; + public static final int ERROR = -1; /** * 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; + public static final int 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; + public static final int QUEUE_ADD = 1; /** * Denotes the language is available exactly as specified by the locale */ - public static final int TTS_LANG_COUNTRY_VAR_AVAILABLE = 2; + public static final int LANG_COUNTRY_VAR_AVAILABLE = 2; /** * Denotes the language is available for the language and country specified * by the locale, but not the variant. */ - public static final int TTS_LANG_COUNTRY_AVAILABLE = 1; + public static final int LANG_COUNTRY_AVAILABLE = 1; /** * Denotes the language is available for the language by the locale, * but not the country and variant. */ - public static final int TTS_LANG_AVAILABLE = 0; + public static final int LANG_AVAILABLE = 0; /** * Denotes the language data is missing. */ - public static final int TTS_LANG_MISSING_DATA = -1; + public static final int LANG_MISSING_DATA = -1; /** * Denotes the language is not supported by the current TTS engine. */ - public static final int TTS_LANG_NOT_SUPPORTED = -2; + public static final int LANG_NOT_SUPPORTED = -2; + + + /** + * Broadcast Action: The TextToSpeech synthesizer has completed processing + * of all the text in the speech queue. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_TTS_QUEUE_PROCESSING_COMPLETED = + "android.speech.tts.TTS_QUEUE_PROCESSING_COMPLETED"; /** @@ -119,126 +130,167 @@ public class TextToSpeech { /** * {@hide} */ - public static final int FALLBACK_TTS_DEFAULT_RATE = 100; // 1x + public static final int DEFAULT_RATE = 100; // 1x /** * {@hide} */ - public static final int FALLBACK_TTS_DEFAULT_PITCH = 100;// 1x + public static final int DEFAULT_PITCH = 100;// 1x /** * {@hide} */ - public static final int FALLBACK_TTS_USE_DEFAULTS = 0; // false + public static final int USE_DEFAULTS = 0; // false /** * {@hide} */ - public static final String FALLBACK_TTS_DEFAULT_SYNTH = "com.svox.pico"; + public static final String DEFAULT_SYNTH = "com.svox.pico"; // default values for rendering - public static final int TTS_DEFAULT_STREAM = AudioManager.STREAM_MUSIC; + public static final int DEFAULT_STREAM = AudioManager.STREAM_MUSIC; // return codes for a TTS engine's check data activity /** * Indicates success when checking the installation status of the resources used by the - * text-to-speech engine with the android.intent.action.CHECK_TTS_DATA intent. + * text-to-speech engine with the {@link #ACTION_CHECK_TTS_DATA} intent. */ public static final int CHECK_VOICE_DATA_PASS = 1; /** * Indicates failure when checking the installation status of the resources used by the - * text-to-speech engine with the android.intent.action.CHECK_TTS_DATA intent. + * text-to-speech engine with the {@link #ACTION_CHECK_TTS_DATA} intent. */ public static final int CHECK_VOICE_DATA_FAIL = 0; /** * Indicates erroneous data when checking the installation status of the resources used by - * the text-to-speech engine with the android.intent.action.CHECK_TTS_DATA intent. + * the text-to-speech engine with the {@link #ACTION_CHECK_TTS_DATA} intent. */ public static final int CHECK_VOICE_DATA_BAD_DATA = -1; /** * Indicates missing resources when checking the installation status of the resources used - * by the text-to-speech engine with the android.intent.action.CHECK_TTS_DATA intent. + * by the text-to-speech engine with the {@link #ACTION_CHECK_TTS_DATA} intent. */ public static final int CHECK_VOICE_DATA_MISSING_DATA = -2; /** * Indicates missing storage volume when checking the installation status of the resources - * used by the text-to-speech engine with the android.intent.action.CHECK_TTS_DATA intent. + * used by the text-to-speech engine with the {@link #ACTION_CHECK_TTS_DATA} intent. */ public static final int CHECK_VOICE_DATA_MISSING_VOLUME = -3; - // return codes for a TTS engine's check data activity + // intents to ask engine to install data or check its data /** - * Extra information received with the android.intent.action.CHECK_TTS_DATA intent where + * Broadcast Action: Triggers the platform Text-To-Speech engine to + * start the activity that installs the resource files on the device + * that are required for TTS to be operational. Since the installation + * of the data can be interrupted or declined by the user, the application + * shouldn't expect successful installation upon return from that intent, + * and if need be, should check installation status with + * {@link #ACTION_CHECK_TTS_DATA}. + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_INSTALL_TTS_DATA = + "android.speech.tts.engine.INSTALL_TTS_DATA"; + + /** + * Broadcast Action: Starts the activity from the platform Text-To-Speech + * engine to verify the proper installation and availability of the + * resource files on the system. Upon completion, the activity will + * return one of the following codes: + * {@link #CHECK_VOICE_DATA_PASS}, + * {@link #CHECK_VOICE_DATA_FAIL}, + * {@link #CHECK_VOICE_DATA_BAD_DATA}, + * {@link #CHECK_VOICE_DATA_MISSING_DATA}, or + * {@link #CHECK_VOICE_DATA_MISSING_VOLUME}. + *

Moreover, the data received in the activity result will contain the following + * fields: + *

    + *
  • {@link #EXTRA_VOICE_DATA_ROOT_DIRECTORY} which + * indicates the path to the location of the resource files
  • , + *
  • {@link #EXTRA_VOICE_DATA_FILES} which contains + * the list of all the resource files
  • , + *
  • and {@link #EXTRA_VOICE_DATA_FILES_INFO} which + * contains, for each resource file, the description of the language covered by + * the file in the xxx-YYY format, where xxx is the 3-letter ISO language code, + * and YYY is the 3-letter ISO country code.
  • + *
+ */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_CHECK_TTS_DATA = + "android.speech.tts.engine.CHECK_TTS_DATA"; + + // extras for a TTS engine's check data activity + /** + * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where * the text-to-speech engine specifies the path to its resources. */ - public static final String VOICE_DATA_ROOT_DIRECTORY = "dataRoot"; + public static final String EXTRA_VOICE_DATA_ROOT_DIRECTORY = "dataRoot"; /** - * Extra information received with the android.intent.action.CHECK_TTS_DATA intent where + * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where * the text-to-speech engine specifies the file names of its resources under the * resource path. */ - public static final String VOICE_DATA_FILES = "dataFiles"; + public static final String EXTRA_VOICE_DATA_FILES = "dataFiles"; /** - * Extra information received with the android.intent.action.CHECK_TTS_DATA intent where + * Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where * the text-to-speech engine specifies the locale associated with each resource file. */ - public static final String VOICE_DATA_FILES_INFO = "dataFilesInfo"; + public static final String EXTRA_VOICE_DATA_FILES_INFO = "dataFilesInfo"; // keys for the parameters passed with speak commands. Hidden keys are used internally // to maintain engine state for each TextToSpeech instance. /** * {@hide} */ - public static final String TTS_KEY_PARAM_RATE = "rate"; + public static final String KEY_PARAM_RATE = "rate"; /** * {@hide} */ - public static final String TTS_KEY_PARAM_LANGUAGE = "language"; + public static final String KEY_PARAM_LANGUAGE = "language"; /** * {@hide} */ - public static final String TTS_KEY_PARAM_COUNTRY = "country"; + public static final String KEY_PARAM_COUNTRY = "country"; /** * {@hide} */ - public static final String TTS_KEY_PARAM_VARIANT = "variant"; + public static final String KEY_PARAM_VARIANT = "variant"; /** * Parameter key to specify the audio stream type to be used when speaking text * or playing back a file. */ - public static final String TTS_KEY_PARAM_STREAM = "streamType"; + public static final String KEY_PARAM_STREAM = "streamType"; /** * Parameter key to identify an utterance in the completion listener after text has been * spoken, a file has been played back or a silence duration has elapsed. */ - public static final String TTS_KEY_PARAM_UTTERANCE_ID = "utteranceId"; + public static final String KEY_PARAM_UTTERANCE_ID = "utteranceId"; // key positions in the array of cached parameters /** * {@hide} */ - protected static final int TTS_PARAM_POSITION_RATE = 0; + protected static final int PARAM_POSITION_RATE = 0; /** * {@hide} */ - protected static final int TTS_PARAM_POSITION_LANGUAGE = 2; + protected static final int PARAM_POSITION_LANGUAGE = 2; /** * {@hide} */ - protected static final int TTS_PARAM_POSITION_COUNTRY = 4; + protected static final int PARAM_POSITION_COUNTRY = 4; /** * {@hide} */ - protected static final int TTS_PARAM_POSITION_VARIANT = 6; + protected static final int PARAM_POSITION_VARIANT = 6; /** * {@hide} */ - protected static final int TTS_PARAM_POSITION_STREAM = 8; + protected static final int PARAM_POSITION_STREAM = 8; /** * {@hide} */ - protected static final int TTS_PARAM_POSITION_UTTERANCE_ID = 10; + protected static final int PARAM_POSITION_UTTERANCE_ID = 10; /** * {@hide} */ - protected static final int TTS_NB_CACHED_PARAMS = 6; + protected static final int NB_CACHED_PARAMS = 6; } /** @@ -273,25 +325,25 @@ public class TextToSpeech { mPackageName = mContext.getPackageName(); mInitListener = listener; - mCachedParams = new String[2*Engine.TTS_NB_CACHED_PARAMS]; // store key and value - mCachedParams[Engine.TTS_PARAM_POSITION_RATE] = Engine.TTS_KEY_PARAM_RATE; - mCachedParams[Engine.TTS_PARAM_POSITION_LANGUAGE] = Engine.TTS_KEY_PARAM_LANGUAGE; - mCachedParams[Engine.TTS_PARAM_POSITION_COUNTRY] = Engine.TTS_KEY_PARAM_COUNTRY; - mCachedParams[Engine.TTS_PARAM_POSITION_VARIANT] = Engine.TTS_KEY_PARAM_VARIANT; - mCachedParams[Engine.TTS_PARAM_POSITION_STREAM] = Engine.TTS_KEY_PARAM_STREAM; - mCachedParams[Engine.TTS_PARAM_POSITION_UTTERANCE_ID] = Engine.TTS_KEY_PARAM_UTTERANCE_ID; + mCachedParams = new String[2*Engine.NB_CACHED_PARAMS]; // store key and value + mCachedParams[Engine.PARAM_POSITION_RATE] = Engine.KEY_PARAM_RATE; + mCachedParams[Engine.PARAM_POSITION_LANGUAGE] = Engine.KEY_PARAM_LANGUAGE; + mCachedParams[Engine.PARAM_POSITION_COUNTRY] = Engine.KEY_PARAM_COUNTRY; + mCachedParams[Engine.PARAM_POSITION_VARIANT] = Engine.KEY_PARAM_VARIANT; + mCachedParams[Engine.PARAM_POSITION_STREAM] = Engine.KEY_PARAM_STREAM; + mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID] = Engine.KEY_PARAM_UTTERANCE_ID; - mCachedParams[Engine.TTS_PARAM_POSITION_RATE + 1] = - String.valueOf(Engine.FALLBACK_TTS_DEFAULT_RATE); + mCachedParams[Engine.PARAM_POSITION_RATE + 1] = + String.valueOf(Engine.DEFAULT_RATE); // initialize the language cached parameters with the current Locale Locale defaultLoc = Locale.getDefault(); - mCachedParams[Engine.TTS_PARAM_POSITION_LANGUAGE + 1] = defaultLoc.getISO3Language(); - mCachedParams[Engine.TTS_PARAM_POSITION_COUNTRY + 1] = defaultLoc.getISO3Country(); - mCachedParams[Engine.TTS_PARAM_POSITION_VARIANT + 1] = defaultLoc.getVariant(); + mCachedParams[Engine.PARAM_POSITION_LANGUAGE + 1] = defaultLoc.getISO3Language(); + mCachedParams[Engine.PARAM_POSITION_COUNTRY + 1] = defaultLoc.getISO3Country(); + mCachedParams[Engine.PARAM_POSITION_VARIANT + 1] = defaultLoc.getVariant(); - mCachedParams[Engine.TTS_PARAM_POSITION_STREAM + 1] = - String.valueOf(Engine.TTS_DEFAULT_STREAM); - mCachedParams[Engine.TTS_PARAM_POSITION_UTTERANCE_ID + 1] = ""; + mCachedParams[Engine.PARAM_POSITION_STREAM + 1] = + String.valueOf(Engine.DEFAULT_STREAM); + mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID + 1] = ""; initTts(); } @@ -308,7 +360,7 @@ public class TextToSpeech { mStarted = true; if (mInitListener != null) { // TODO manage failures and missing resources - mInitListener.onInit(TTS_SUCCESS); + mInitListener.onInit(SUCCESS); } } } @@ -349,8 +401,7 @@ public class TextToSpeech { /** * Adds a mapping between a string of text and a sound resource in a * package. - * - * @see #TTS.speak(String text, int queueMode, String[] params) + * @see #speak(String, int, HashMap) * * @param text * Example: "south_south_east"
@@ -371,16 +422,16 @@ public class TextToSpeech { * @param resourceId * Example: R.raw.south_south_east * - * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS. + * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. */ public int addSpeech(String text, String packagename, int resourceId) { synchronized(mStartLock) { if (!mStarted) { - return TTS_ERROR; + return ERROR; } try { mITts.addSpeech(mPackageName, text, packagename, resourceId); - return TTS_SUCCESS; + return SUCCESS; } catch (RemoteException e) { // TTS died; restart it. Log.e("TextToSpeech.java - addSpeech", "RemoteException"); @@ -400,7 +451,7 @@ public class TextToSpeech { mStarted = false; initTts(); } - return TTS_ERROR; + return ERROR; } } @@ -415,16 +466,16 @@ public class TextToSpeech { * The full path to the sound file (for example: * "/sdcard/mysounds/hello.wav") * - * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS. + * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. */ public int addSpeech(String text, String filename) { synchronized (mStartLock) { if (!mStarted) { - return TTS_ERROR; + return ERROR; } try { mITts.addSpeechFile(mPackageName, text, filename); - return TTS_SUCCESS; + return SUCCESS; } catch (RemoteException e) { // TTS died; restart it. Log.e("TextToSpeech.java - addSpeech", "RemoteException"); @@ -444,7 +495,7 @@ public class TextToSpeech { mStarted = false; initTts(); } - return TTS_ERROR; + return ERROR; } } @@ -453,7 +504,7 @@ public class TextToSpeech { * Adds a mapping between a string of text and a sound resource in a * package. * - * @see #TTS.playEarcon(String earcon, int queueMode, String[] params) + * @see #playEarcon(String, int, HashMap) * * @param earcon The name of the earcon * Example: "[tick]"
@@ -474,16 +525,16 @@ public class TextToSpeech { * @param resourceId * Example: R.raw.tick_snd * - * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS. + * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. */ public int addEarcon(String earcon, String packagename, int resourceId) { synchronized(mStartLock) { if (!mStarted) { - return TTS_ERROR; + return ERROR; } try { mITts.addEarcon(mPackageName, earcon, packagename, resourceId); - return TTS_SUCCESS; + return SUCCESS; } catch (RemoteException e) { // TTS died; restart it. Log.e("TextToSpeech.java - addEarcon", "RemoteException"); @@ -503,7 +554,7 @@ public class TextToSpeech { mStarted = false; initTts(); } - return TTS_ERROR; + return ERROR; } } @@ -518,16 +569,16 @@ public class TextToSpeech { * The full path to the sound file (for example: * "/sdcard/mysounds/tick.wav") * - * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS. + * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. */ public int addEarcon(String earcon, String filename) { synchronized (mStartLock) { if (!mStarted) { - return TTS_ERROR; + return ERROR; } try { mITts.addEarconFile(mPackageName, earcon, filename); - return TTS_SUCCESS; + return SUCCESS; } catch (RemoteException e) { // TTS died; restart it. Log.e("TextToSpeech.java - addEarcon", "RemoteException"); @@ -547,7 +598,7 @@ public class TextToSpeech { mStarted = false; initTts(); } - return TTS_ERROR; + return ERROR; } } @@ -563,29 +614,29 @@ public class TextToSpeech { * The string of text to be spoken. * @param queueMode * The queuing strategy to use. - * See TTS_QUEUE_ADD and TTS_QUEUE_FLUSH. + * See QUEUE_ADD and QUEUE_FLUSH. * @param params * The hashmap of speech parameters to be used. * - * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS. + * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. */ public int speak(String text, int queueMode, HashMap params) { synchronized (mStartLock) { - int result = TTS_ERROR; + int result = ERROR; Log.i("TTS received: ", text); if (!mStarted) { return result; } try { if ((params != null) && (!params.isEmpty())) { - String extra = params.get(Engine.TTS_KEY_PARAM_STREAM); + String extra = params.get(Engine.KEY_PARAM_STREAM); if (extra != null) { - mCachedParams[Engine.TTS_PARAM_POSITION_STREAM + 1] = extra; + mCachedParams[Engine.PARAM_POSITION_STREAM + 1] = extra; } - extra = params.get(Engine.TTS_KEY_PARAM_UTTERANCE_ID); + extra = params.get(Engine.KEY_PARAM_UTTERANCE_ID); if (extra != null) { - mCachedParams[Engine.TTS_PARAM_POSITION_UTTERANCE_ID + 1] = extra; + mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID + 1] = extra; } } result = mITts.speak(mPackageName, text, queueMode, mCachedParams); @@ -621,28 +672,28 @@ public class TextToSpeech { * @param earcon * The earcon that should be played * @param queueMode - * See TTS_QUEUE_ADD and TTS_QUEUE_FLUSH. + * See QUEUE_ADD and QUEUE_FLUSH. * @param params * The hashmap of parameters to be used. * - * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS. + * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. */ public int playEarcon(String earcon, int queueMode, HashMap params) { synchronized (mStartLock) { - int result = TTS_ERROR; + int result = ERROR; if (!mStarted) { return result; } try { if ((params != null) && (!params.isEmpty())) { - String extra = params.get(Engine.TTS_KEY_PARAM_STREAM); + String extra = params.get(Engine.KEY_PARAM_STREAM); if (extra != null) { - mCachedParams[Engine.TTS_PARAM_POSITION_STREAM + 1] = extra; + mCachedParams[Engine.PARAM_POSITION_STREAM + 1] = extra; } - extra = params.get(Engine.TTS_KEY_PARAM_UTTERANCE_ID); + extra = params.get(Engine.KEY_PARAM_UTTERANCE_ID); if (extra != null) { - mCachedParams[Engine.TTS_PARAM_POSITION_UTTERANCE_ID + 1] = extra; + mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID + 1] = extra; } } result = mITts.playEarcon(mPackageName, earcon, queueMode, null); @@ -678,21 +729,21 @@ public class TextToSpeech { * @param durationInMs * A long that indicates how long the silence should last. * @param queueMode - * See TTS_QUEUE_ADD and TTS_QUEUE_FLUSH. + * See QUEUE_ADD and QUEUE_FLUSH. * - * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS. + * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. */ public int playSilence(long durationInMs, int queueMode, HashMap params) { synchronized (mStartLock) { - int result = TTS_ERROR; + int result = ERROR; if (!mStarted) { return result; } try { if ((params != null) && (!params.isEmpty())) { - String extra = params.get(Engine.TTS_KEY_PARAM_UTTERANCE_ID); + String extra = params.get(Engine.KEY_PARAM_UTTERANCE_ID); if (extra != null) { - mCachedParams[Engine.TTS_PARAM_POSITION_UTTERANCE_ID + 1] = extra; + mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID + 1] = extra; } } result = mITts.playSilence(mPackageName, durationInMs, queueMode, mCachedParams); @@ -760,11 +811,11 @@ public class TextToSpeech { /** * Stops speech from the TTS. * - * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS. + * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. */ public int stop() { synchronized (mStartLock) { - int result = TTS_ERROR; + int result = ERROR; if (!mStarted) { return result; } @@ -808,24 +859,24 @@ public class TextToSpeech { * 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). * - * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS. + * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. */ public int setSpeechRate(float speechRate) { synchronized (mStartLock) { - int result = TTS_ERROR; + int result = ERROR; if (!mStarted) { return result; } try { if (speechRate > 0) { int rate = (int)(speechRate*100); - mCachedParams[Engine.TTS_PARAM_POSITION_RATE + 1] = String.valueOf(rate); + mCachedParams[Engine.PARAM_POSITION_RATE + 1] = String.valueOf(rate); // the rate is not set here, instead it is cached so it will be associated // with all upcoming utterances. if (speechRate > 0.0f) { - result = TTS_SUCCESS; + result = SUCCESS; } else { - result = TTS_ERROR; + result = ERROR; } } } catch (NullPointerException e) { @@ -860,11 +911,11 @@ public class TextToSpeech { * lower values lower the tone of the synthesized voice, * greater values increase it. * - * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS. + * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. */ public int setPitch(float pitch) { synchronized (mStartLock) { - int result = TTS_ERROR; + int result = ERROR; if (!mStarted) { return result; } @@ -907,25 +958,27 @@ public class TextToSpeech { * @param loc * The locale describing the language to be used. * - * @return code indicating the support status for the locale. See {@link #TTS_LANG_AVAILABLE}, - * {@link #TTS_LANG_COUNTRY_AVAILABLE}, {@link #TTS_LANG_COUNTRY_VAR_AVAILABLE}, - * {@link #TTS_LANG_MISSING_DATA} and {@link #TTS_LANG_NOT_SUPPORTED}. + * @return code indicating the support status for the locale. See {@link #LANG_AVAILABLE}, + * {@link #LANG_COUNTRY_AVAILABLE}, {@link #LANG_COUNTRY_VAR_AVAILABLE}, + * {@link #LANG_MISSING_DATA} and {@link #LANG_NOT_SUPPORTED}. */ public int setLanguage(Locale loc) { synchronized (mStartLock) { - int result = TTS_LANG_NOT_SUPPORTED; + int result = LANG_NOT_SUPPORTED; if (!mStarted) { return result; } try { - mCachedParams[Engine.TTS_PARAM_POSITION_LANGUAGE + 1] = loc.getISO3Language(); - mCachedParams[Engine.TTS_PARAM_POSITION_COUNTRY + 1] = loc.getISO3Country(); - mCachedParams[Engine.TTS_PARAM_POSITION_VARIANT + 1] = loc.getVariant(); - - result = mITts.setLanguage(mPackageName, - mCachedParams[Engine.TTS_PARAM_POSITION_LANGUAGE + 1], - mCachedParams[Engine.TTS_PARAM_POSITION_COUNTRY + 1], - mCachedParams[Engine.TTS_PARAM_POSITION_VARIANT + 1] ); + mCachedParams[Engine.PARAM_POSITION_LANGUAGE + 1] = loc.getISO3Language(); + mCachedParams[Engine.PARAM_POSITION_COUNTRY + 1] = loc.getISO3Country(); + mCachedParams[Engine.PARAM_POSITION_VARIANT + 1] = loc.getVariant(); + // the language is not set here, instead it is cached so it will be associated + // with all upcoming utterances. But we still need to report the language support, + // which is achieved by calling isLanguageAvailable() + result = mITts.isLanguageAvailable( + mCachedParams[Engine.PARAM_POSITION_LANGUAGE + 1], + mCachedParams[Engine.PARAM_POSITION_COUNTRY + 1], + mCachedParams[Engine.PARAM_POSITION_VARIANT + 1] ); } catch (RemoteException e) { // TTS died; restart it. Log.e("TextToSpeech.java - setLanguage", "RemoteException"); @@ -997,13 +1050,13 @@ public class TextToSpeech { * @param loc * The Locale describing the language to be used. * - * @return code indicating the support status for the locale. See {@link #TTS_LANG_AVAILABLE}, - * {@link #TTS_LANG_COUNTRY_AVAILABLE}, {@link #TTS_LANG_COUNTRY_VAR_AVAILABLE}, - * {@link #TTS_LANG_MISSING_DATA} and {@link #TTS_LANG_NOT_SUPPORTED}. + * @return code indicating the support status for the locale. See {@link #LANG_AVAILABLE}, + * {@link #LANG_COUNTRY_AVAILABLE}, {@link #LANG_COUNTRY_VAR_AVAILABLE}, + * {@link #LANG_MISSING_DATA} and {@link #LANG_NOT_SUPPORTED}. */ public int isLanguageAvailable(Locale loc) { synchronized (mStartLock) { - int result = TTS_LANG_NOT_SUPPORTED; + int result = LANG_NOT_SUPPORTED; if (!mStarted) { return result; } @@ -1046,25 +1099,25 @@ public class TextToSpeech { * The string that gives the full output filename; it should be * something like "/sdcard/myappsounds/mysound.wav". * - * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS. + * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. */ public int synthesizeToFile(String text, HashMap params, String filename) { synchronized (mStartLock) { - int result = TTS_ERROR; + int result = ERROR; if (!mStarted) { return result; } try { if ((params != null) && (!params.isEmpty())) { // no need to read the stream type here - String extra = params.get(Engine.TTS_KEY_PARAM_UTTERANCE_ID); + String extra = params.get(Engine.KEY_PARAM_UTTERANCE_ID); if (extra != null) { - mCachedParams[Engine.TTS_PARAM_POSITION_UTTERANCE_ID + 1] = extra; + mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID + 1] = extra; } } if (mITts.synthesizeToFile(mPackageName, text, mCachedParams, filename)){ - result = TTS_SUCCESS; + result = SUCCESS; } } catch (RemoteException e) { // TTS died; restart it. @@ -1097,9 +1150,9 @@ public class TextToSpeech { * if they are not persistent between calls to the service. */ private void resetCachedParams() { - mCachedParams[Engine.TTS_PARAM_POSITION_STREAM + 1] = - String.valueOf(Engine.TTS_DEFAULT_STREAM); - mCachedParams[Engine.TTS_PARAM_POSITION_UTTERANCE_ID+ 1] = ""; + mCachedParams[Engine.PARAM_POSITION_STREAM + 1] = + String.valueOf(Engine.DEFAULT_STREAM); + mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID+ 1] = ""; } /** @@ -1108,12 +1161,12 @@ public class TextToSpeech { * @param listener * The OnUtteranceCompletedListener * - * @return Code indicating success or failure. See TTS_ERROR and TTS_SUCCESS. + * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}. */ public int setOnUtteranceCompletedListener( final OnUtteranceCompletedListener listener) { synchronized (mStartLock) { - int result = TTS_ERROR; + int result = ERROR; if (!mStarted) { return result; } diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java index 3d10f171538c5..524f9418c00b8 100644 --- a/core/java/android/text/format/DateFormat.java +++ b/core/java/android/text/format/DateFormat.java @@ -284,6 +284,12 @@ public class DateFormat { */ public static java.text.DateFormat getDateFormatForSetting(Context context, String value) { + String format = getDateFormatStringForSetting(context, value); + + return new java.text.SimpleDateFormat(format); + } + + private static String getDateFormatStringForSetting(Context context, String value) { if (value != null) { int month = value.indexOf('M'); int day = value.indexOf('d'); @@ -291,7 +297,7 @@ public class DateFormat { if (month >= 0 && day >= 0 && year >= 0) { String template = context.getString(R.string.numeric_date_template); - if (year < month) { + if (year < month && year < day) { if (month < day) { value = String.format(template, "yyyy", "MM", "dd"); } else { @@ -311,7 +317,7 @@ public class DateFormat { } } - return new java.text.SimpleDateFormat(value); + return value; } } @@ -321,7 +327,7 @@ public class DateFormat { * so that we get a four-digit year instead a two-digit year. */ value = context.getString(R.string.numeric_date_format); - return new java.text.SimpleDateFormat(value); + return value; } /** @@ -347,7 +353,11 @@ public class DateFormat { /** * Gets the current date format stored as a char array. The array will contain * 3 elements ({@link #DATE}, {@link #MONTH}, and {@link #YEAR}) in the order - * preferred by the user. + * specified by the user's format preference. Note that this order is + * only appropriate for all-numeric dates; spelled-out (MEDIUM and LONG) + * dates will generally contain other punctuation, spaces, or words, + * not just the day, month, and year, and not necessarily in the same + * order returned here. */ public static final char[] getDateFormatOrder(Context context) { char[] order = new char[] {DATE, MONTH, YEAR}; @@ -380,22 +390,10 @@ public class DateFormat { } private static String getDateFormatString(Context context) { - java.text.DateFormat df; - df = java.text.DateFormat.getDateInstance(java.text.DateFormat.SHORT); - if (df instanceof SimpleDateFormat) { - return ((SimpleDateFormat) df).toPattern(); - } - String value = Settings.System.getString(context.getContentResolver(), Settings.System.DATE_FORMAT); - if (value == null || value.length() < 6) { - /* - * No need to localize -- this is an emergency fallback in case - * the setting is missing, but it should always be set. - */ - value = "MM-dd-yyyy"; - } - return value; + + return getDateFormatStringForSetting(context, value); } /** diff --git a/core/java/android/text/style/ImageSpan.java b/core/java/android/text/style/ImageSpan.java index 29c0c76ad1b11..86ef5f68bc7c0 100644 --- a/core/java/android/text/style/ImageSpan.java +++ b/core/java/android/text/style/ImageSpan.java @@ -33,17 +33,34 @@ public class ImageSpan extends DynamicDrawableSpan { private Context mContext; private String mSource; + /** + * @deprecated Use {@link #ImageSpan(Context, Bitmap)} instead. + */ public ImageSpan(Bitmap b) { - this(b, ALIGN_BOTTOM); + this(null, b, ALIGN_BOTTOM); + } + + /** + * @deprecated Use {@link #ImageSpan(Context, Bitmap, int) instead. + */ + public ImageSpan(Bitmap b, int verticalAlignment) { + this(null, b, verticalAlignment); + } + + public ImageSpan(Context context, Bitmap b) { + this(context, b, ALIGN_BOTTOM); } /** * @param verticalAlignment one of {@link DynamicDrawableSpan#ALIGN_BOTTOM} or * {@link DynamicDrawableSpan#ALIGN_BASELINE}. */ - public ImageSpan(Bitmap b, int verticalAlignment) { + public ImageSpan(Context context, Bitmap b, int verticalAlignment) { super(verticalAlignment); - mDrawable = new BitmapDrawable(b); + mContext = context; + mDrawable = context != null + ? new BitmapDrawable(context.getResources(), b) + : new BitmapDrawable(b); int width = mDrawable.getIntrinsicWidth(); int height = mDrawable.getIntrinsicHeight(); mDrawable.setBounds(0, 0, width > 0 ? width : 0, height > 0 ? height : 0); @@ -117,7 +134,7 @@ public class ImageSpan extends DynamicDrawableSpan { InputStream is = mContext.getContentResolver().openInputStream( mContentUri); bitmap = BitmapFactory.decodeStream(is); - drawable = new BitmapDrawable(bitmap); + drawable = new BitmapDrawable(mContext.getResources(), bitmap); drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); is.close(); diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java index 061f98a5a53ed..dd5a4401c4d51 100644 --- a/core/java/android/util/DisplayMetrics.java +++ b/core/java/android/util/DisplayMetrics.java @@ -79,6 +79,11 @@ public class DisplayMetrics { * @see #DENSITY_DEFAULT */ public float density; + /** + * The screen density expressed as dots-per-inch. May be either + * {@link #DENSITY_LOW}, {@link #DENSITY_MEDIUM}, or {@link #DENSITY_HIGH}. + */ + public int densityDpi; /** * A scaling factor for fonts displayed on the display. This is the same * as {@link #density}, except that it may be adjusted in smaller @@ -101,6 +106,7 @@ public class DisplayMetrics { widthPixels = o.widthPixels; heightPixels = o.heightPixels; density = o.density; + densityDpi = o.densityDpi; scaledDensity = o.scaledDensity; xdpi = o.xdpi; ydpi = o.ydpi; @@ -110,6 +116,7 @@ public class DisplayMetrics { widthPixels = 0; heightPixels = 0; density = DENSITY_DEVICE / (float) DENSITY_DEFAULT; + densityDpi = DENSITY_DEVICE; scaledDensity = density; xdpi = DENSITY_DEVICE; ydpi = DENSITY_DEVICE; @@ -186,9 +193,11 @@ public class DisplayMetrics { heightPixels = defaultHeight; } } + if (compatibilityInfo.isScalingRequired()) { float invertedRatio = compatibilityInfo.applicationInvertedScale; density *= invertedRatio; + densityDpi = (int)((density*DisplayMetrics.DENSITY_DEFAULT)+.5f); scaledDensity *= invertedRatio; xdpi *= invertedRatio; ydpi *= invertedRatio; diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java index 5551f64bcde34..b055d51c1b40a 100644 --- a/core/java/android/view/Display.java +++ b/core/java/android/view/Display.java @@ -94,6 +94,7 @@ public class Display outMetrics.widthPixels = getWidth(); outMetrics.heightPixels = getHeight(); outMetrics.density = mDensity; + outMetrics.densityDpi = (int)((mDensity*DisplayMetrics.DENSITY_DEFAULT)+.5f); outMetrics.scaledDensity= outMetrics.density; outMetrics.xdpi = mDpiX; outMetrics.ydpi = mDpiY; diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java index 83c30e1855f96..5100fff2b5938 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -16,6 +16,7 @@ package android.view; +import android.content.res.CompatibilityInfo.Translator; import android.graphics.*; import android.os.Parcelable; import android.os.Parcel; @@ -106,8 +107,14 @@ public class Surface implements Parcelable { public static final int SURFACE_HIDDEN = 0x01; /** Freeze the surface. Equivalent to calling freeze() */ + public static final int SURFACE_FROZEN = 0x02; + + /** + * @deprecated use {@link #SURFACE_FROZEN} instead. + */ + @Deprecated public static final int SURACE_FROZEN = 0x02; - + /** Enable dithering when compositing this surface */ public static final int SURFACE_DITHER = 0x04; @@ -133,8 +140,12 @@ public class Surface implements Parcelable { private Canvas mCanvas; // The display metrics used to provide the pseudo canvas size for applications - // running in compatibility mode. This is set to null for regular mode. - private DisplayMetrics mDisplayMetrics; + // running in compatibility mode. This is set to null for non compatibility mode. + private DisplayMetrics mCompatibleDisplayMetrics; + + // A matrix to scale the matrix set by application. This is set to null for + // non compatibility mode. + private Matrix mCompatibleMatrix; /** * Exception thrown when a surface couldn't be created or resized @@ -172,23 +183,70 @@ public class Surface implements Parcelable { * {@hide} */ public Surface() { - mCanvas = new Canvas() { - @Override - public int getWidth() { - return mDisplayMetrics == null ? super.getWidth() : mDisplayMetrics.widthPixels; - } - @Override - public int getHeight() { - return mDisplayMetrics == null ? super.getHeight() : mDisplayMetrics.heightPixels; - } - }; + mCanvas = new CompatibleCanvas(); } + /** + * A Canvas class that can handle the compatibility mode. This does two things differently. + *
    + *
  • Returns the width and height of the target metrics, rather than native. + * For example, the canvas returns 320x480 even if an app is running in WVGA high density. + *
  • Scales the matrix in setMatrix by the application scale, except if the matrix looks + * like obtained from getMatrix. This is a hack to handle the case that an application + * uses getMatrix to keep the original matrix, set matrix of its own, then set the original + * matrix back. There is no perfect solution that works for all cases, and there are a lot of + * cases that this model dose not work, but we hope this works for many apps. + *
+ */ + private class CompatibleCanvas extends Canvas { + // A temp matrix to remember what an application obtained via {@link getMatrix} + private Matrix mOrigMatrix = null; + + @Override + public int getWidth() { + return mCompatibleDisplayMetrics == null ? + super.getWidth() : mCompatibleDisplayMetrics.widthPixels; + } + + @Override + public int getHeight() { + return mCompatibleDisplayMetrics == null ? + super.getHeight() : mCompatibleDisplayMetrics.heightPixels; + } + + @Override + public void setMatrix(Matrix matrix) { + if (mCompatibleMatrix == null || mOrigMatrix == null || mOrigMatrix.equals(matrix)) { + // don't scale the matrix if it's not compatibility mode, or + // the matrix was obtained from getMatrix. + super.setMatrix(matrix); + } else { + Matrix m = new Matrix(mCompatibleMatrix); + m.preConcat(matrix); + super.setMatrix(m); + } + } + + @Override + public void getMatrix(Matrix m) { + super.getMatrix(m); + if (mOrigMatrix == null) { + mOrigMatrix = new Matrix(); + } + mOrigMatrix.set(m); + } + }; + /** * Sets the display metrics used to provide canva's width/height in comaptibility mode. */ - void setCompatibleDisplayMetrics(DisplayMetrics metrics) { - mDisplayMetrics = metrics; + void setCompatibleDisplayMetrics(DisplayMetrics metrics, Translator translator) { + mCompatibleDisplayMetrics = metrics; + if (translator != null) { + float appScale = translator.applicationScale; + mCompatibleMatrix = new Matrix(); + mCompatibleMatrix.setScale(appScale, appScale); + } } /** diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 95bba97c75977..9cf7092491c4b 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -140,7 +140,7 @@ public class SurfaceView extends View { int mType = -1; final Rect mSurfaceFrame = new Rect(); private Translator mTranslator; - + public SurfaceView(Context context) { super(context); setWillNotDraw(true); @@ -252,23 +252,6 @@ public class SurfaceView extends View { super.draw(canvas); } - @Override - public boolean dispatchTouchEvent(MotionEvent event) { - // SurfaceView uses pre-scaled size unless fixed size is requested. This hook - // scales the event back to the pre-scaled coordinates for such surface. - if (mScaled) { - MotionEvent scaledBack = MotionEvent.obtain(event); - mTranslator.translateEventInScreenToAppWindow(event); - try { - return super.dispatchTouchEvent(scaledBack); - } finally { - scaledBack.recycle(); - } - } else { - return super.dispatchTouchEvent(event); - } - } - @Override protected void dispatchDraw(Canvas canvas) { // if SKIP_DRAW is cleared, draw() has already punched a hole @@ -291,8 +274,6 @@ public class SurfaceView extends View { mWindowType = type; } - boolean mScaled = false; - private void updateWindow(boolean force) { if (!mHaveFrame) { return; @@ -300,11 +281,9 @@ public class SurfaceView extends View { ViewRoot viewRoot = (ViewRoot) getRootView().getParent(); mTranslator = viewRoot.mTranslator; - float appScale = mTranslator == null ? 1.0f : mTranslator.applicationScale; - Resources res = getContext().getResources(); if (mTranslator != null || !res.getCompatibilityInfo().supportsScreen()) { - mSurface.setCompatibleDisplayMetrics(res.getDisplayMetrics()); + mSurface.setCompatibleDisplayMetrics(res.getDisplayMetrics(), mTranslator); } int myWidth = mRequestedWidth; @@ -312,16 +291,6 @@ public class SurfaceView extends View { int myHeight = mRequestedHeight; if (myHeight <= 0) myHeight = getHeight(); - // Use original size if the app specified the size of the view, - // and let the flinger to scale up. - if (mRequestedWidth <= 0 && mTranslator != null) { - myWidth = (int) (myWidth * appScale + 0.5f); - myHeight = (int) (myHeight * appScale + 0.5f); - mScaled = true; - } else { - mScaled = false; - } - getLocationInWindow(mLocation); final boolean creating = mWindow == null; final boolean formatChanged = mFormat != mRequestedFormat; @@ -394,10 +363,17 @@ public class SurfaceView extends View { if (localLOGV) Log.i(TAG, "New surface: " + mSurface + ", vis=" + visible + ", frame=" + mWinFrame); + mSurfaceFrame.left = 0; mSurfaceFrame.top = 0; - mSurfaceFrame.right = mWinFrame.width(); - mSurfaceFrame.bottom = mWinFrame.height(); + if (mTranslator == null) { + mSurfaceFrame.right = mWinFrame.width(); + mSurfaceFrame.bottom = mWinFrame.height(); + } else { + float appInvertedScale = mTranslator.applicationInvertedScale; + mSurfaceFrame.right = (int) (mWinFrame.width() * appInvertedScale + 0.5f); + mSurfaceFrame.bottom = (int) (mWinFrame.height() * appInvertedScale + 0.5f); + } mSurfaceLock.unlock(); try { @@ -641,10 +617,6 @@ public class SurfaceView extends View { if (localLOGV) Log.i(TAG, "Returned canvas: " + c); if (c != null) { mLastLockTime = SystemClock.uptimeMillis(); - if (mScaled) { - mSaveCount = c.save(); - mTranslator.translateCanvas(c); - } return c; } @@ -667,9 +639,6 @@ public class SurfaceView extends View { } public void unlockCanvasAndPost(Canvas canvas) { - if (mScaled) { - canvas.restoreToCount(mSaveCount); - } mSurface.unlockCanvasAndPost(canvas); mSurfaceLock.unlock(); } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index ff8868bb0f2fb..7ed2712dc7503 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -46,6 +46,7 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.util.AttributeSet; import android.util.Config; +import android.util.DisplayMetrics; import android.util.EventLog; import android.util.Log; import android.util.Pool; @@ -5976,6 +5977,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility try { bitmap = Bitmap.createBitmap(width, height, quality); + bitmap.setDensity(getResources().getDisplayMetrics().densityDpi); if (autoScale) { mDrawingCache = new SoftReference(bitmap); } else { diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java index 46aea022912be..4baf61211feef 100644 --- a/core/java/android/view/ViewDebug.java +++ b/core/java/android/view/ViewDebug.java @@ -16,6 +16,7 @@ package android.view; +import android.util.Config; import android.util.Log; import android.util.DisplayMetrics; import android.content.res.Resources; @@ -140,7 +141,9 @@ public class ViewDebug { public static boolean consistencyCheckEnabled = false; static { - Debug.setFieldsOn(ViewDebug.class, true); + if (Config.DEBUG) { + Debug.setFieldsOn(ViewDebug.class, true); + } } /** diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index 2f92b32e53f1c..f7cb06b226547 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -21,7 +21,6 @@ import com.android.internal.view.IInputMethodSession; import android.graphics.Canvas; import android.graphics.PixelFormat; -import android.graphics.Point; import android.graphics.PorterDuff; import android.graphics.Rect; import android.graphics.Region; @@ -187,7 +186,7 @@ public final class ViewRoot extends Handler implements ViewParent, */ AudioManager mAudioManager; - private final float mDensity; + private final int mDensity; public ViewRoot(Context context) { super(); @@ -229,7 +228,7 @@ public final class ViewRoot extends Handler implements ViewParent, mAdded = false; mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, this); mViewConfiguration = ViewConfiguration.get(context); - mDensity = context.getResources().getDisplayMetrics().density; + mDensity = context.getResources().getDisplayMetrics().densityDpi; } @Override @@ -389,10 +388,11 @@ public final class ViewRoot extends Handler implements ViewParent, attrs = mWindowAttributes; Resources resources = mView.getContext().getResources(); CompatibilityInfo compatibilityInfo = resources.getCompatibilityInfo(); - mTranslator = compatibilityInfo.getTranslator(attrs); + mTranslator = compatibilityInfo.getTranslator(); if (mTranslator != null || !compatibilityInfo.supportsScreen()) { - mSurface.setCompatibleDisplayMetrics(resources.getDisplayMetrics()); + mSurface.setCompatibleDisplayMetrics(resources.getDisplayMetrics(), + mTranslator); } boolean restore = false; @@ -1212,6 +1212,8 @@ public final class ViewRoot extends Handler implements ViewParent, if (mTranslator != null) { mTranslator.translateCanvas(canvas); } + canvas.setScreenDensity(scalingRequired + ? DisplayMetrics.DENSITY_DEVICE : 0); mView.draw(canvas); if (Config.DEBUG && ViewDebug.consistencyCheckEnabled) { mView.dispatchConsistencyCheck(ViewDebug.CONSISTENCY_DRAWING); @@ -1269,7 +1271,7 @@ public final class ViewRoot extends Handler implements ViewParent, } // TODO: Do this in native - canvas.setDensityScale(mDensity); + canvas.setDensity(mDensity); } catch (Surface.OutOfResourcesException e) { Log.e("ViewRoot", "OutOfResourcesException locking surface", e); // TODO: we should ask the window manager to do something! @@ -1320,6 +1322,8 @@ public final class ViewRoot extends Handler implements ViewParent, if (mTranslator != null) { mTranslator.translateCanvas(canvas); } + canvas.setScreenDensity(scalingRequired + ? DisplayMetrics.DENSITY_DEVICE : 0); mView.draw(canvas); } finally { mAttachInfo.mIgnoreDirtyState = false; diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java index 474fa82db2d74..9ca2909483115 100644 --- a/core/java/android/webkit/LoadListener.java +++ b/core/java/android/webkit/LoadListener.java @@ -31,7 +31,6 @@ import android.os.Message; import android.security.CertTool; import android.util.Log; import android.webkit.CacheManager.CacheResult; -import android.widget.Toast; import com.android.internal.R; @@ -77,6 +76,7 @@ class LoadListener extends Handler implements EventHandler { static { sCertificateMimeTypeMap = new HashSet(); sCertificateMimeTypeMap.add("application/x-x509-ca-cert"); + sCertificateMimeTypeMap.add("application/x-x509-user-cert"); sCertificateMimeTypeMap.add("application/x-pkcs12"); } @@ -1016,8 +1016,6 @@ class LoadListener extends Handler implements EventHandler { mDataBuilder.releaseChunk(c); } CertTool.getInstance().addCertificate(cert, mContext); - Toast.makeText(mContext, R.string.certificateSaved, - Toast.LENGTH_SHORT).show(); mBrowserFrame.stopLoading(); return; } diff --git a/core/java/android/webkit/MimeTypeMap.java b/core/java/android/webkit/MimeTypeMap.java index fdbc692bf271d..9fdde6192e672 100644 --- a/core/java/android/webkit/MimeTypeMap.java +++ b/core/java/android/webkit/MimeTypeMap.java @@ -357,6 +357,7 @@ public /* package */ class MimeTypeMap { sMimeTypeMap.loadEntry( "application/x-webarchive", "webarchive", false); // added sMimeTypeMap.loadEntry("application/x-x509-ca-cert", "crt", false); + sMimeTypeMap.loadEntry("application/x-x509-user-cert", "crt", false); sMimeTypeMap.loadEntry("application/x-xcf", "xcf", false); sMimeTypeMap.loadEntry("application/x-xfig", "fig", false); sMimeTypeMap.loadEntry("audio/basic", "snd", false); diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index fcf946f7d12a7..69364350690b1 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -545,7 +545,6 @@ public class WebView extends AbsoluteLayout private ZoomButtonsController mZoomButtonsController; private ImageView mZoomOverviewButton; - private ImageView mZoomFitPageButton; // These keep track of the center point of the zoom. They are used to // determine the point around which we should zoom. @@ -617,6 +616,16 @@ public class WebView extends AbsoluteLayout // Create the buttons controller mZoomButtonsController = new ZoomButtonsController(this); mZoomButtonsController.setOnZoomListener(mZoomListener); + // ZoomButtonsController positions the buttons at the bottom, but in + // the middle. Change their layout parameters so they appear on the + // right. + View controls = mZoomButtonsController.getZoomControls(); + ViewGroup.LayoutParams params = controls.getLayoutParams(); + if (params instanceof FrameLayout.LayoutParams) { + FrameLayout.LayoutParams frameParams = (FrameLayout.LayoutParams) + params; + frameParams.gravity = Gravity.RIGHT; + } // Create the accessory buttons LayoutInflater inflater = @@ -636,15 +645,6 @@ public class WebView extends AbsoluteLayout } } }); - mZoomFitPageButton = - (ImageView) container.findViewById(com.android.internal.R.id.zoom_fit_page); - mZoomFitPageButton.setOnClickListener( - new View.OnClickListener() { - public void onClick(View v) { - zoomWithPreview(mDefaultScale); - updateZoomButtonsEnabled(); - } - }); } private void updateZoomButtonsEnabled() { @@ -654,17 +654,14 @@ public class WebView extends AbsoluteLayout // Hide the zoom in and out buttons, as well as the fit to page // button, if the page cannot zoom mZoomButtonsController.getZoomControls().setVisibility(View.GONE); - mZoomFitPageButton.setVisibility(View.GONE); } else { // Bring back the hidden zoom controls. mZoomButtonsController.getZoomControls() .setVisibility(View.VISIBLE); - mZoomFitPageButton.setVisibility(View.VISIBLE); // Set each one individually, as a page may be able to zoom in // or out. mZoomButtonsController.setZoomInEnabled(canZoomIn); mZoomButtonsController.setZoomOutEnabled(canZoomOut); - mZoomFitPageButton.setEnabled(mActualScale != mDefaultScale); } mZoomOverviewButton.setVisibility(canZoomScrollOut() ? View.VISIBLE: View.GONE); diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 777beed7ed138..eea97dc2dbd1a 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -1535,6 +1535,9 @@ public abstract class AbsListView extends AdapterView implements Te protected void onDetachedFromWindow() { super.onDetachedFromWindow(); + // Dismiss the popup in case onSaveInstanceState() was not invoked + dismissPopup(); + final ViewTreeObserver treeObserver = getViewTreeObserver(); if (treeObserver != null) { treeObserver.removeOnTouchModeChangeListener(this); diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java index 4bc00de33e815..456f8ed845a42 100644 --- a/core/java/android/widget/AutoCompleteTextView.java +++ b/core/java/android/widget/AutoCompleteTextView.java @@ -104,6 +104,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe private View mDropDownAnchorView; // view is retrieved lazily from id once needed private int mDropDownWidth; private int mDropDownHeight; + private final Rect mTempRect = new Rect(); private Drawable mDropDownListHighlight; @@ -116,6 +117,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe private boolean mDropDownAlwaysVisible = false; private boolean mDropDownDismissedOnCompletion = true; + + private boolean mForceIgnoreOutsideTouch = false; private int mLastKeyCode = KeyEvent.KEYCODE_UNKNOWN; private boolean mOpenBefore; @@ -205,11 +208,9 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe * Private hook into the on click event, dispatched from {@link PassThroughClickListener} */ private void onClickImpl() { - // if drop down should always visible, bring it back in front of the soft - // keyboard when the user touches the text field - if (mDropDownAlwaysVisible - && mPopup.isShowing() - && mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED) { + // If the dropdown is showing, bring it back in front of the soft + // keyboard when the user touches the text field. + if (mPopup.isShowing() && isInputMethodNotNeeded()) { ensureImeVisible(); } } @@ -1101,6 +1102,13 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe showDropDown(); } + /** + * @hide internal used only here and SearchDialog + */ + public boolean isInputMethodNotNeeded() { + return mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED; + } + /** *

Displays the drop down on screen.

*/ @@ -1110,7 +1118,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe int widthSpec = 0; int heightSpec = 0; - boolean noInputMethod = mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED; + boolean noInputMethod = isInputMethodNotNeeded(); if (mPopup.isShowing()) { if (mDropDownWidth == ViewGroup.LayoutParams.FILL_PARENT) { @@ -1143,6 +1151,8 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe heightSpec = mDropDownHeight; } + mPopup.setOutsideTouchable(mForceIgnoreOutsideTouch ? false : !mDropDownAlwaysVisible); + mPopup.update(getDropDownAnchorView(), mDropDownHorizontalOffset, mDropDownVerticalOffset, widthSpec, heightSpec); } else { @@ -1171,7 +1181,7 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe // use outside touchable to dismiss drop down when touching outside of it, so // only set this if the dropdown is not always visible - mPopup.setOutsideTouchable(!mDropDownAlwaysVisible); + mPopup.setOutsideTouchable(mForceIgnoreOutsideTouch ? false : !mDropDownAlwaysVisible); mPopup.setTouchInterceptor(new PopupTouchIntercepter()); mPopup.showAsDropDown(getDropDownAnchorView(), mDropDownHorizontalOffset, mDropDownVerticalOffset); @@ -1180,6 +1190,17 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe post(mHideSelector); } } + + /** + * Forces outside touches to be ignored. Normally if {@link #isDropDownAlwaysVisible()} is + * false, we allow outside touch to dismiss the dropdown. If this is set to true, then we + * ignore outside touch even when the drop down is not set to always visible. + * + * @hide used only by SearchDialog + */ + public void setForceIgnoreOutsideTouch(boolean forceIgnoreOutsideTouch) { + mForceIgnoreOutsideTouch = forceIgnoreOutsideTouch; + } /** *

Builds the popup window's content and returns the height the popup @@ -1303,7 +1324,15 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe getDropDownAnchorView(), mDropDownVerticalOffset, ignoreBottomDecorations); if (mDropDownAlwaysVisible) { - return maxHeight; + // getMaxAvailableHeight() subtracts the padding, so we put it back, + // to get the available height for the whole window + int padding = 0; + Drawable background = mPopup.getBackground(); + if (background != null) { + background.getPadding(mTempRect); + padding = mTempRect.top + mTempRect.bottom; + } + return maxHeight + padding; } return mDropDownList.measureHeightOfChildren(MeasureSpec.UNSPECIFIED, diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java index 3b9f1de4c66c9..5e76cc3a28af9 100644 --- a/core/java/android/widget/DatePicker.java +++ b/core/java/android/widget/DatePicker.java @@ -31,6 +31,7 @@ import com.android.internal.widget.NumberPicker; import com.android.internal.widget.NumberPicker.OnChangedListener; import java.text.DateFormatSymbols; +import java.text.SimpleDateFormat; import java.util.Calendar; /** @@ -101,7 +102,8 @@ public class DatePicker extends FrameLayout { mMonthPicker = (NumberPicker) findViewById(R.id.month); mMonthPicker.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER); DateFormatSymbols dfs = new DateFormatSymbols(); - mMonthPicker.setRange(1, 12, dfs.getShortMonths()); + String[] months = dfs.getShortMonths(); + mMonthPicker.setRange(1, 12, months); mMonthPicker.setSpeed(200); mMonthPicker.setOnChangeListener(new OnChangedListener() { public void onChanged(NumberPicker picker, int oldVal, int newVal) { @@ -146,7 +148,7 @@ public class DatePicker extends FrameLayout { init(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH), null); // re-order the number pickers to match the current date format - reorderPickers(); + reorderPickers(months); if (!isEnabled()) { setEnabled(false); @@ -161,29 +163,69 @@ public class DatePicker extends FrameLayout { mYearPicker.setEnabled(enabled); } - private void reorderPickers() { - char[] order = DateFormat.getDateFormatOrder(mContext); - - /* Default order is month, date, year so if that's the order then - * do nothing. + private void reorderPickers(String[] months) { + java.text.DateFormat format; + String order; + + /* + * If the user is in a locale where the medium date format is + * still numeric (Japanese and Czech, for example), respect + * the date format order setting. Otherwise, use the order + * that the locale says is appropriate for a spelled-out date. */ - if ((order[0] == DateFormat.MONTH) && (order[1] == DateFormat.DATE)) { - return; + + if (months[0].startsWith("1")) { + format = DateFormat.getDateFormat(getContext()); + } else { + format = DateFormat.getMediumDateFormat(getContext()); } - + + if (format instanceof SimpleDateFormat) { + order = ((SimpleDateFormat) format).toPattern(); + } else { + // Shouldn't happen, but just in case. + order = new String(DateFormat.getDateFormatOrder(getContext())); + } + /* Remove the 3 pickers from their parent and then add them back in the * required order. */ LinearLayout parent = (LinearLayout) findViewById(R.id.parent); parent.removeAllViews(); - for (char c : order) { - if (c == DateFormat.DATE) { - parent.addView(mDayPicker); - } else if (c == DateFormat.MONTH) { - parent.addView(mMonthPicker); - } else { - parent.addView (mYearPicker); + + boolean quoted = false; + boolean didDay = false, didMonth = false, didYear = false; + + for (int i = 0; i < order.length(); i++) { + char c = order.charAt(i); + + if (c == '\'') { + quoted = !quoted; } + + if (!quoted) { + if (c == DateFormat.DATE && !didDay) { + parent.addView(mDayPicker); + didDay = true; + } else if ((c == DateFormat.MONTH || c == 'L') && !didMonth) { + parent.addView(mMonthPicker); + didMonth = true; + } else if (c == DateFormat.YEAR && !didYear) { + parent.addView (mYearPicker); + didYear = true; + } + } + } + + // Shouldn't happen, but just in case. + if (!didMonth) { + parent.addView(mMonthPicker); + } + if (!didDay) { + parent.addView(mDayPicker); + } + if (!didYear) { + parent.addView(mYearPicker); } } @@ -192,6 +234,7 @@ public class DatePicker extends FrameLayout { mMonth = monthOfYear; mDay = dayOfMonth; updateSpinners(); + reorderPickers(new DateFormatSymbols().getShortMonths()); } private static class SavedState extends BaseSavedState { diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java index 27967742a135d..b8f0a7e16f73b 100644 --- a/core/java/android/widget/ImageView.java +++ b/core/java/android/widget/ImageView.java @@ -317,7 +317,7 @@ public class ImageView extends View { public void setImageBitmap(Bitmap bm) { // if this is used frequently, may handle bitmaps explicitly // to reduce the intermediate drawable object - setImageDrawable(new BitmapDrawable(bm)); + setImageDrawable(new BitmapDrawable(mContext.getResources(), bm)); } public void setImageState(int[] state, boolean merge) { @@ -463,6 +463,7 @@ public class ImageView extends View { if (matrix == null && !mMatrix.isIdentity() || matrix != null && !mMatrix.equals(matrix)) { mMatrix.set(matrix); + configureBounds(); invalidate(); } } diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java index 24c0e2a4a2d9b..e19a93dc64ea5 100644 --- a/core/java/android/widget/RelativeLayout.java +++ b/core/java/android/widget/RelativeLayout.java @@ -432,7 +432,7 @@ public class RelativeLayout extends ViewGroup { width = resolveSize(width, widthMeasureSpec); if (offsetHorizontalAxis) { - for (int i = 0; i < count; i++) { + for (int i = 0; i < count; i++) { View child = getChildAt(i); if (child.getVisibility() != GONE) { LayoutParams params = (LayoutParams) child.getLayoutParams(); @@ -486,10 +486,14 @@ public class RelativeLayout extends ViewGroup { View child = getChildAt(i); if (child.getVisibility() != GONE && child != ignore) { LayoutParams params = (LayoutParams) child.getLayoutParams(); - params.mLeft += horizontalOffset; - params.mRight += horizontalOffset; - params.mTop += verticalOffset; - params.mBottom += verticalOffset; + if (horizontalGravity) { + params.mLeft += horizontalOffset; + params.mRight += horizontalOffset; + } + if (verticalGravity) { + params.mTop += verticalOffset; + params.mBottom += verticalOffset; + } } } } diff --git a/core/java/android/widget/TabWidget.java b/core/java/android/widget/TabWidget.java index a26bfa23eff81..47f5c6c264da2 100644 --- a/core/java/android/widget/TabWidget.java +++ b/core/java/android/widget/TabWidget.java @@ -277,7 +277,7 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener { if (child.getLayoutParams() == null) { final LinearLayout.LayoutParams lp = new LayoutParams( 0, - ViewGroup.LayoutParams.WRAP_CONTENT, 1); + ViewGroup.LayoutParams.FILL_PARENT, 1.0f); lp.setMargins(0, 0, 0, 0); child.setLayoutParams(lp); } @@ -289,10 +289,10 @@ public class TabWidget extends LinearLayout implements OnFocusChangeListener { // If we have dividers between the tabs and we already have at least one // tab, then add a divider before adding the next tab. if (mDividerDrawable != null && getTabCount() > 0) { - View divider = new View(mContext); + ImageView divider = new ImageView(mContext); final LinearLayout.LayoutParams lp = new LayoutParams( mDividerDrawable.getIntrinsicWidth(), - mDividerDrawable.getIntrinsicHeight()); + LayoutParams.FILL_PARENT); lp.setMargins(0, 0, 0, 0); divider.setLayoutParams(lp); divider.setBackgroundDrawable(mDividerDrawable); diff --git a/core/java/com/android/internal/widget/EditStyledText.java b/core/java/com/android/internal/widget/EditStyledText.java index f0ad7b3bb3b51..82197c0151f21 100644 --- a/core/java/com/android/internal/widget/EditStyledText.java +++ b/core/java/com/android/internal/widget/EditStyledText.java @@ -1242,7 +1242,8 @@ public class EditStyledText extends EditText { try { InputStream is = mEST.getContext().getContentResolver().openInputStream(uri); Bitmap bitmap = BitmapFactory.decodeStream(is); - Drawable drawable = new BitmapDrawable(bitmap); + Drawable drawable = new BitmapDrawable( + getContext().getResources(), bitmap); drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp index 93d68cbfe0aea..1c2e055cfcf93 100644 --- a/core/jni/android/graphics/Canvas.cpp +++ b/core/jni/android/graphics/Canvas.cpp @@ -462,17 +462,27 @@ public: static void drawBitmap__BitmapFFPaint(JNIEnv* env, jobject jcanvas, SkCanvas* canvas, SkBitmap* bitmap, jfloat left, jfloat top, - SkPaint* paint, - jboolean autoScale, jfloat densityScale) { + SkPaint* paint, jint canvasDensity, + jint screenDensity, jint bitmapDensity) { SkScalar left_ = SkFloatToScalar(left); SkScalar top_ = SkFloatToScalar(top); - if (!autoScale || densityScale <= 0.0f) { - canvas->drawBitmap(*bitmap, left_, top_, paint); + if (canvasDensity == bitmapDensity || canvasDensity == 0 + || bitmapDensity == 0) { + if (screenDensity != 0 && screenDensity != bitmapDensity) { + SkPaint filteredPaint; + if (paint) { + filteredPaint = *paint; + } + filteredPaint.setFilterBitmap(true); + canvas->drawBitmap(*bitmap, left_, top_, &filteredPaint); + } else { + canvas->drawBitmap(*bitmap, left_, top_, paint); + } } else { canvas->save(); - SkScalar canvasScale = GraphicsJNI::getCanvasDensityScale(env, jcanvas); - SkScalar scale = canvasScale / SkFloatToScalar(densityScale); + SkScalar scale = SkFloatToScalar(canvasDensity / (float)bitmapDensity); + canvas->translate(left_, top_); canvas->scale(scale, scale); SkPaint filteredPaint; @@ -481,37 +491,52 @@ public: } filteredPaint.setFilterBitmap(true); - canvas->drawBitmap(*bitmap, left_, top_, &filteredPaint); + canvas->drawBitmap(*bitmap, 0, 0, &filteredPaint); canvas->restore(); } } static void doDrawBitmap(JNIEnv* env, SkCanvas* canvas, SkBitmap* bitmap, - jobject srcIRect, const SkRect& dst, SkPaint* paint) { + jobject srcIRect, const SkRect& dst, SkPaint* paint, + jint screenDensity, jint bitmapDensity) { SkIRect src, *srcPtr = NULL; if (NULL != srcIRect) { GraphicsJNI::jrect_to_irect(env, srcIRect, &src); srcPtr = &src; } - canvas->drawBitmapRect(*bitmap, srcPtr, dst, paint); + + if (screenDensity != 0 && screenDensity != bitmapDensity) { + SkPaint filteredPaint; + if (paint) { + filteredPaint = *paint; + } + filteredPaint.setFilterBitmap(true); + canvas->drawBitmapRect(*bitmap, srcPtr, dst, &filteredPaint); + } else { + canvas->drawBitmapRect(*bitmap, srcPtr, dst, paint); + } } static void drawBitmapRF(JNIEnv* env, jobject, SkCanvas* canvas, SkBitmap* bitmap, jobject srcIRect, - jobject dstRectF, SkPaint* paint) { + jobject dstRectF, SkPaint* paint, + jint screenDensity, jint bitmapDensity) { SkRect dst; GraphicsJNI::jrectf_to_rect(env, dstRectF, &dst); - doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint); + doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint, + screenDensity, bitmapDensity); } static void drawBitmapRR(JNIEnv* env, jobject, SkCanvas* canvas, SkBitmap* bitmap, jobject srcIRect, - jobject dstRect, SkPaint* paint) { + jobject dstRect, SkPaint* paint, + jint screenDensity, jint bitmapDensity) { SkRect dst; GraphicsJNI::jrect_to_rect(env, dstRect, &dst); - doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint); + doDrawBitmap(env, canvas, bitmap, srcIRect, dst, paint, + screenDensity, bitmapDensity); } static void drawBitmapArray(JNIEnv* env, jobject, SkCanvas* canvas, @@ -905,11 +930,11 @@ static JNINativeMethod gCanvasMethods[] = { {"native_drawRoundRect","(ILandroid/graphics/RectF;FFI)V", (void*) SkCanvasGlue::drawRoundRect}, {"native_drawPath","(III)V", (void*) SkCanvasGlue::drawPath}, - {"native_drawBitmap","(IIFFIZF)V", + {"native_drawBitmap","(IIFFIIII)V", (void*) SkCanvasGlue::drawBitmap__BitmapFFPaint}, - {"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/RectF;I)V", + {"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/RectF;III)V", (void*) SkCanvasGlue::drawBitmapRF}, - {"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/Rect;I)V", + {"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/Rect;III)V", (void*) SkCanvasGlue::drawBitmapRR}, {"native_drawBitmap", "(I[IIIFFIIZI)V", (void*)SkCanvasGlue::drawBitmapArray}, diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp index 6e159a8853d59..ca1cb7d652019 100644 --- a/core/jni/android/graphics/Graphics.cpp +++ b/core/jni/android/graphics/Graphics.cpp @@ -163,7 +163,6 @@ static jfieldID gBitmapConfig_nativeInstanceID; static jclass gCanvas_class; static jfieldID gCanvas_nativeInstanceID; -static jfieldID gCanvas_densityScaleID; static jclass gPaint_class; static jfieldID gPaint_nativeInstanceID; @@ -320,13 +319,6 @@ SkCanvas* GraphicsJNI::getNativeCanvas(JNIEnv* env, jobject canvas) { return c; } -SkScalar GraphicsJNI::getCanvasDensityScale(JNIEnv* env, jobject canvas) { - SkASSERT(env); - SkASSERT(canvas); - SkASSERT(env->IsInstanceOf(canvas, gCanvas_class)); - return SkFloatToScalar(env->GetFloatField(canvas, gCanvas_densityScaleID)); -} - SkPaint* GraphicsJNI::getNativePaint(JNIEnv* env, jobject paint) { SkASSERT(env); SkASSERT(paint); @@ -557,7 +549,6 @@ int register_android_graphics_Graphics(JNIEnv* env) gCanvas_class = make_globalref(env, "android/graphics/Canvas"); gCanvas_nativeInstanceID = getFieldIDCheck(env, gCanvas_class, "mNativeCanvas", "I"); - gCanvas_densityScaleID = getFieldIDCheck(env, gCanvas_class, "mDensityScale", "F"); gPaint_class = make_globalref(env, "android/graphics/Paint"); gPaint_nativeInstanceID = getFieldIDCheck(env, gPaint_class, "mNativePaint", "I"); diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h index 16925e41ab4f3..f8b60a805e1ba 100644 --- a/core/jni/android/graphics/GraphicsJNI.h +++ b/core/jni/android/graphics/GraphicsJNI.h @@ -38,7 +38,6 @@ public: static SkBitmap* getNativeBitmap(JNIEnv*, jobject bitmap); static SkPicture* getNativePicture(JNIEnv*, jobject picture); static SkRegion* getNativeRegion(JNIEnv*, jobject region); - static SkScalar getCanvasDensityScale(JNIEnv*, jobject canvas); /** Return the corresponding native config from the java Config enum, or kNo_Config if the java object is null. diff --git a/core/jni/android/graphics/MaskFilter.cpp b/core/jni/android/graphics/MaskFilter.cpp index e6048cdcea6a2..0f8dff1210551 100644 --- a/core/jni/android/graphics/MaskFilter.cpp +++ b/core/jni/android/graphics/MaskFilter.cpp @@ -4,15 +4,23 @@ #include +static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) { + if (NULL == ptr) { + doThrowIAE(env); + } +} + class SkMaskFilterGlue { public: static void destructor(JNIEnv* env, jobject, SkMaskFilter* filter) { - SkASSERT(filter); - filter->unref(); + filter->safeUnref(); } static SkMaskFilter* createBlur(JNIEnv* env, jobject, float radius, int blurStyle) { - return SkBlurMaskFilter::Create(SkFloatToScalar(radius), (SkBlurMaskFilter::BlurStyle)blurStyle); + SkMaskFilter* filter = SkBlurMaskFilter::Create(SkFloatToScalar(radius), + (SkBlurMaskFilter::BlurStyle)blurStyle); + ThrowIAE_IfNull(env, filter); + return filter; } static SkMaskFilter* createEmboss(JNIEnv* env, jobject, jfloatArray dirArray, float ambient, float specular, float radius) { @@ -24,8 +32,12 @@ public: direction[i] = SkFloatToScalar(values[i]); } - return SkBlurMaskFilter::CreateEmboss(direction, SkFloatToScalar(ambient), - SkFloatToScalar(specular), SkFloatToScalar(radius)); + SkMaskFilter* filter = SkBlurMaskFilter::CreateEmboss(direction, + SkFloatToScalar(ambient), + SkFloatToScalar(specular), + SkFloatToScalar(radius)); + ThrowIAE_IfNull(env, filter); + return filter; } }; diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp index b11edfc07436e..fd5271e4c18b0 100644 --- a/core/jni/android/graphics/NinePatch.cpp +++ b/core/jni/android/graphics/NinePatch.cpp @@ -1,5 +1,6 @@ #include +#include "SkCanvas.h" #include "SkRegion.h" #include "GraphicsJNI.h" @@ -45,7 +46,8 @@ public: } static void draw(JNIEnv* env, SkCanvas* canvas, SkRect& bounds, - const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint) + const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint, + jint destDensity, jint srcDensity) { size_t chunkSize = env->GetArrayLength(chunkObj); void* storage = alloca(chunkSize); @@ -56,13 +58,32 @@ public: Res_png_9patch* chunk = static_cast(storage); assert(chunkSize == chunk->serializedSize()); // this relies on deserialization being done in place - Res_png_9patch::deserialize(chunk); - NinePatch_Draw(canvas, bounds, *bitmap, *chunk, paint, NULL); + Res_png_9patch::deserialize(chunk); + + if (destDensity == srcDensity || destDensity == 0 + || srcDensity == 0) { + NinePatch_Draw(canvas, bounds, *bitmap, *chunk, paint, NULL); + } else { + canvas->save(); + + SkScalar scale = SkFloatToScalar(destDensity / (float)srcDensity); + canvas->translate(bounds.fLeft, bounds.fTop); + canvas->scale(scale, scale); + + bounds.fRight = SkScalarDiv(bounds.fRight-bounds.fLeft, scale); + bounds.fBottom = SkScalarDiv(bounds.fBottom-bounds.fTop, scale); + bounds.fLeft = bounds.fTop = 0; + + NinePatch_Draw(canvas, bounds, *bitmap, *chunk, paint, NULL); + + canvas->restore(); + } } } static void drawF(JNIEnv* env, jobject, SkCanvas* canvas, jobject boundsRectF, - const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint) + const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint, + jint destDensity, jint srcDensity) { SkASSERT(canvas); SkASSERT(boundsRectF); @@ -73,11 +94,12 @@ public: SkRect bounds; GraphicsJNI::jrectf_to_rect(env, boundsRectF, &bounds); - draw(env, canvas, bounds, bitmap, chunkObj, paint); + draw(env, canvas, bounds, bitmap, chunkObj, paint, destDensity, srcDensity); } static void drawI(JNIEnv* env, jobject, SkCanvas* canvas, jobject boundsRect, - const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint) + const SkBitmap* bitmap, jbyteArray chunkObj, const SkPaint* paint, + jint destDensity, jint srcDensity) { SkASSERT(canvas); SkASSERT(boundsRect); @@ -87,7 +109,7 @@ public: SkRect bounds; GraphicsJNI::jrect_to_rect(env, boundsRect, &bounds); - draw(env, canvas, bounds, bitmap, chunkObj, paint); + draw(env, canvas, bounds, bitmap, chunkObj, paint, destDensity, srcDensity); } static jint getTransparentRegion(JNIEnv* env, jobject, @@ -126,8 +148,8 @@ public: static JNINativeMethod gNinePatchMethods[] = { { "isNinePatchChunk", "([B)Z", (void*)SkNinePatchGlue::isNinePatchChunk }, { "validateNinePatchChunk", "(I[B)V", (void*)SkNinePatchGlue::validateNinePatchChunk }, - { "nativeDraw", "(ILandroid/graphics/RectF;I[BI)V", (void*)SkNinePatchGlue::drawF }, - { "nativeDraw", "(ILandroid/graphics/Rect;I[BI)V", (void*)SkNinePatchGlue::drawI }, + { "nativeDraw", "(ILandroid/graphics/RectF;I[BIII)V", (void*)SkNinePatchGlue::drawF }, + { "nativeDraw", "(ILandroid/graphics/Rect;I[BIII)V", (void*)SkNinePatchGlue::drawI }, { "nativeGetTransparentRegion", "(I[BLandroid/graphics/Rect;)I", (void*)SkNinePatchGlue::getTransparentRegion } }; diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp index b28eb900242cd..b09c62b7d2b3e 100644 --- a/core/jni/android/graphics/Shader.cpp +++ b/core/jni/android/graphics/Shader.cpp @@ -43,25 +43,23 @@ static int Color_HSVToColor(JNIEnv* env, jobject, int alpha, jfloatArray hsvArra static void Shader_destructor(JNIEnv* env, jobject, SkShader* shader) { - SkASSERT(shader != NULL); - shader->unref(); + shader->safeUnref(); } static bool Shader_getLocalMatrix(JNIEnv* env, jobject, const SkShader* shader, SkMatrix* matrix) { - SkASSERT(shader != NULL); - return shader->getLocalMatrix(matrix); + return shader ? shader->getLocalMatrix(matrix) : false; } static void Shader_setLocalMatrix(JNIEnv* env, jobject, SkShader* shader, const SkMatrix* matrix) { - SkASSERT(shader != NULL); - - if (NULL == matrix) { - shader->resetLocalMatrix(); - } - else { - shader->setLocalMatrix(*matrix); + if (shader) { + if (NULL == matrix) { + shader->resetLocalMatrix(); + } + else { + shader->setLocalMatrix(*matrix); + } } } diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index 59f40670c41bb..66b250670fee3 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -74,12 +74,13 @@ static void doThrow(JNIEnv* env, const char* exc, const char* msg = NULL) } enum { - STYLE_NUM_ENTRIES = 5, + STYLE_NUM_ENTRIES = 6, STYLE_TYPE = 0, STYLE_DATA = 1, STYLE_ASSET_COOKIE = 2, STYLE_RESOURCE_ID = 3, - STYLE_CHANGING_CONFIGURATIONS = 4 + STYLE_CHANGING_CONFIGURATIONS = 4, + STYLE_DENSITY = 5 }; static jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table, @@ -896,6 +897,7 @@ static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject cla ResTable::Theme* theme = (ResTable::Theme*)themeToken; const ResTable& res = theme->getResTable(); ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken; + ResTable_config config; Res_value value; const jsize NI = env->GetArrayLength(attrs); @@ -995,6 +997,7 @@ static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject cla value.dataType = Res_value::TYPE_NULL; value.data = 0; typeSetFlags = 0; + config.density = 0; // Skip through XML attributes until the end or the next possible match. while (ix < NX && curIdent > curXmlAttr) { @@ -1042,7 +1045,8 @@ static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject cla if (value.dataType != Res_value::TYPE_NULL) { // Take care of resolving the found resource to its final value. //printf("Resolving attribute reference\n"); - ssize_t newBlock = theme->resolveAttributeReference(&value, block, &resid, &typeSetFlags); + ssize_t newBlock = theme->resolveAttributeReference(&value, block, + &resid, &typeSetFlags, &config); if (newBlock >= 0) block = newBlock; } else { // If we still don't have a value for this attribute, try to find @@ -1051,7 +1055,8 @@ static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject cla ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags); if (newBlock >= 0) { //printf("Resolving resource reference\n"); - newBlock = res.resolveReference(&value, block, &resid, &typeSetFlags); + newBlock = res.resolveReference(&value, block, &resid, + &typeSetFlags, &config); if (newBlock >= 0) block = newBlock; } } @@ -1070,6 +1075,7 @@ static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject cla block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1; dest[STYLE_RESOURCE_ID] = resid; dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags; + dest[STYLE_DENSITY] = config.density; if (indices != NULL && value.dataType != Res_value::TYPE_NULL) { indicesIdx++; @@ -1108,6 +1114,7 @@ static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, job } const ResTable& res(am->getResources()); ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken; + ResTable_config config; Res_value value; const jsize NI = env->GetArrayLength(attrs); @@ -1160,6 +1167,7 @@ static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, job value.dataType = Res_value::TYPE_NULL; value.data = 0; typeSetFlags = 0; + config.density = 0; // Skip through XML attributes until the end or the next possible match. while (ix < NX && curIdent > curXmlAttr) { @@ -1179,7 +1187,8 @@ static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, job if (value.dataType != Res_value::TYPE_NULL) { // Take care of resolving the found resource to its final value. //printf("Resolving attribute reference\n"); - ssize_t newBlock = res.resolveReference(&value, block, &resid, &typeSetFlags); + ssize_t newBlock = res.resolveReference(&value, block, &resid, + &typeSetFlags, &config); if (newBlock >= 0) block = newBlock; } @@ -1197,6 +1206,7 @@ static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, job block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1; dest[STYLE_RESOURCE_ID] = resid; dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags; + dest[STYLE_DENSITY] = config.density; if (indices != NULL && value.dataType != Res_value::TYPE_NULL) { indicesIdx++; @@ -1250,6 +1260,7 @@ static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject claz return JNI_FALSE; } const ResTable& res(am->getResources()); + ResTable_config config; Res_value value; ssize_t block; @@ -1276,13 +1287,15 @@ static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject claz while (i < NV && arrayEnt < endArrayEnt) { block = arrayEnt->stringBlock; typeSetFlags = arrayTypeSetFlags; + config.density = 0; value = arrayEnt->map.value; uint32_t resid = 0; if (value.dataType != Res_value::TYPE_NULL) { // Take care of resolving the found resource to its final value. //printf("Resolving attribute reference\n"); - ssize_t newBlock = res.resolveReference(&value, block, &resid, &typeSetFlags); + ssize_t newBlock = res.resolveReference(&value, block, &resid, + &typeSetFlags, &config); if (newBlock >= 0) block = newBlock; } @@ -1299,6 +1312,7 @@ static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject claz dest[STYLE_ASSET_COOKIE] = (jint)res.getTableCookie(block); dest[STYLE_RESOURCE_ID] = resid; dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags; + dest[STYLE_DENSITY] = config.density; dest += STYLE_NUM_ENTRIES; i+= STYLE_NUM_ENTRIES; arrayEnt++; diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 00d9cf6152e49..4558660899c83 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -209,7 +209,7 @@ - - + to put the higher-level system there into a shutdown state. + @hide --> + critical UI such as the home screen. + @hide --> u9=Nq-jB_zB%&R?#fWt2^ zXQ!v9ZzLrprCSkT7P7dw=*!Q~{~gt*hue0+TT0X3TK5NYJwfn4Myx7Cb!w4k8i2!q4num(le-rg>C zb#>zR`?vZO*v3BkD1T!-ImvBRL^c*9(pXeLQXNs+9qEO9!WGCw~rt*x!h1sYgq8~f-(U-KZyNp7oY+s=2q zv9X~+Ey}L0E~&4tm$|t)LE;jR$0KcRZCan#>y^yROj%i3(S*=VBm5>LPDZ(G{$qGsHjLfJ3F;{V`HOCOiX-pva0ofnOUu9Vr2BC`lpFfwUqXxOSp%9aGV$f9#Gue++2d3keZj5myFE0U%$#NBR_=3$H)C0 z9UUWR8s)VPc($VeD|bwTbEI1whyw%r$C(p_)&1Q-BS$T{_nUqxd80000< KMNUMnLSTXb9~$8R delta 1091 zcmV-J1ibtH2>l3U?#R!MW)q)gh0R+bW`cV zmDWvgQL@Ochz|tgqLpsC5>dMkSp@>oU=|_JMHQ1mqzr+?Q6!?#n51K8oQKcx(eJyt zcY3**8IOr!T;#y#e>~^^zxmGVKj+%yO*xd*l|wuKproZrL4O*GjaE`zY;p?9M-it= zg#8_M^QSOH0BtVd(7QH)FyIG#IC1_H7l9uyhWUaR8yjn>L@6jJIG>Y~Q^5X6B=RrH zi)Sd!&CR3mUqtgF#Qbw4x4cOdM+x{6re<<-@~7(R>PwlKnT}Yd(PQBg^WWXw-JF@3 zc~oCt|2zJD3V)y3B-}@ffKx5Z#f621U!6|pc}3Bh4Fm!&Dk>^|M)hyRJbot;aQGVL z+oh$Y-?Fo_ohkyXLN+!w0%c`o*HC?c*eCJ)Y)MF5Fqgbu?=M+dS)2bM@B}zPft(JGDZ^*iAEj|)ZS13u;ct#7C%IKc6eAH8TLpA=b&1F0kx(ckJv}|LzP=voW1Vg6qYr(pLdZ#O zRS|g(hkxU&l_WPeSBi>?#N~3y+S;1*_VzLtXkeXf?4u8Tt%D#ZxmDA)oojq>aG=51 zltV*9(%#-KtE;Pm#3eqTPx|`$v_8MzFNKALva_?J38C-u^78+=z-BXe?5Z;n#poi2 z2m>oCD;jx8Nr`N4Z}aGB)?8;FedueACnvd8MSp}b+JJF14H8Z*$+64D?RLx7))sfY z2G-feKKjttJd*@D^_x~n#H-oa*){7(2wYBrG%mx#!_wH;sQoy>I@{PspLnt4B)8Hn ziZ!f*`Eg=m;z~wFMy7c*=6j*4s!9e22eo=Ccv>gwvMtRjqpkx55KN35PGTN30Vr_QbRop_ zz@w(7rhCWnBLtn-)mK-|Qd%ZEw!FH~Z$Jk$4pFVPaH9MMF3B#5Bbusr#u zZ;ms%%Z};WV;%nC5BBk+lZWL5%g1lgQ};o9m}X9gDJcI5FaUsAQ!pK>?6?2`002ov JPDHLkV1iZPBlZ9Q diff --git a/core/res/res/drawable/expander_ic_minimized.9.png b/core/res/res/drawable/expander_ic_minimized.9.png index 5235c18f31af5b0f54acde3d52524b4eb2dc8ee9..9967ecbd6c1e32cc74d7289e7ae6d028f9b2c7da 100644 GIT binary patch delta 1109 zcmV-b1giU#36BYoNq;d(L_t(|+U!?bOJi3QUeTa4(I(y!$c)zNJfv!2kb(~__)?(- z>4O(6{Q-R|iYQ7!iWH>}qIfC#6G{u!Vv+Wtg(9}#$RLH*`-qC;h}vi-aU6}8e&6mn zG$W2dAKv*BZ%oU_(4b*u{?Xzi<(Fxd-MoVr*=z_8vxVZtmU8%*=b;o*K^Vc{pZ`~|VUCnN$7@4&n_KR@4vx%bjXS3txI0IZcK zB_$;txb*`#wi2nB<>TYyA7y1_c~4JIg*ZDqi$Fs|gMZZ3)kz=_xb%!Lw&dmI ziP!6u-Q8VjZf;f?iRVu)a*|tD#H&R`MFk8Fhr zjVC9$b$>;8uoyk@1Q7i9{r&yo@pzPwoSYn4T3V8xo}Rcu$VqNp5iW}%)1RE=))f)l+S=MT3sfvZ zZqJU64z(ar2UOZ|u1Hf;li&=C@HKhJX`HlLBDNP67WS^nLRVLp`2Buyxm;>0^7Hf6 zy_J=fxH04;x2}lg?(Xi{qobn}lfYU5d0k#!F6rs%Dgy-t1u{H5EE^jem;B6la*>nV zx_=^g(5%hO%&f=c^E^->&di?}ebQMh9=;-K&C`K;p z+?p{J6&31wc6L@}#Cm#~hZlFn-rioIwzl?5-2Mh}KPGaDazB3nyfZN|@jg1J+p&bi zI=-y}uz-)MtE<1m?Vo_J5EIZoMGa>LKYswp_o$Fh?RLAW1th-;^r0_f7)uUvMGMgC zwh{CM=4;^R`uh5Br>3ShkoK@C#yQ zw#-D!cgtwyo^Nh$h87nW1HHYybGXF{_7M2>N&z}OX4D#S8;!|5;EwUzX}COPt4N;z&3WA|34RjhkIb&Ax1_fa| ziuU*sT2)omF#K0=dj(>)&gGVuiQ+r~w_!@g$HzY_E-o%hNl9_M$}~nS_q*8+4-cQu z%*;F}FE783uYZ5RXYQ;#ajpnB-G#ZgyuAEnW@hG1P0`8*0)fYcg@s?>@*!gWcr6id zxC8Uv>gwuOX=!PhIs#&a?CtFZ^7HdQ$K`K`{qsU1(0K#q!`a!{4$QrmKDq*;9sppi zJSi$FYQwFcz_Af8Z6|7_qobprW@Kb|kB*LnI6gj(LVsOdoz&FSNH7>Y)km0dDWaS$e82BJLIr(}b(#_3H z$;rtPuh%Qv+uPFE*r-M%kw3Y}Np4*cZx<940Ja*lYh#=dAO%aI@3WcP#wN;QyRDTdhr=p@lT3TA-`jeB~x*|dw8yf*L zLB%8F_H1iwQwtJ#Kn*+26=`T_5S(FAz9tVjjgwYO#OB=G+|F5}(9zK$e!pK_E|;2$ z+}vDsZ)s^MVGKFRtt(=&v$J!0e}DhbB(P>cUYC}ZN@{AV8iBmLJQ*Aul(n_BQ+{SV zxqrw>Ze0;PXjZ1CrdH!k2g#e8o7KaKp`jr)1soCUgRRp+E^->&di4ZWbOlV!@bK^_ zNJcK}+?p|EWo7DmdU{%oi1qX|4=?VDot>Rvb#?XExcwdCe!j>l%KiK?@c!7?*hi?K zuE!G+@A$R~zyjW{tgQS2w|@b?K}=Bl6n{0G8T~t8F{ZU%)6$2&jA1M}46c7wV|roUWtj&QH8nLA z`+PnZwq-g>zH3G)_xJkxdU$?*KG@yeJ%d}!U=M-c&lI3jW5%ozw^5kf0&W=Jol}O( zGnV=QE2l?XuSV$~Jh%F~NZn`z@m(Xs^3IWJbRAgUJ$Atv(k=lnD&qh8Yv9eh=#>$1 g+5cCm_KyGq05_YE=IYVNumAu607*qoM6N<$f*ji;GXMYp diff --git a/core/res/res/drawable/rate_star_small_half.png b/core/res/res/drawable/rate_star_small_half.png index a81449bcab03235012240d6c7cf23833392ff285..437a11c0f1a115475ce4bb0e0a16d416dbbd3af3 100644 GIT binary patch delta 477 zcmV<30V4jH1e^qrNq@dcL_t(|+KiIFO9EjS$Dj8+>rS#fYDrC@NYsOVQ9_`DIJ6WE zPW=HTv^TUiM1w6Y4Y~CXG&BT3V-Xaz+EOZ)VyRuFUa9x?JYo{n&qcXKE4=5#vu&<^}Zkh#^*%y2lokM{CUfq#gXeq;`rMBFQ@i$nJQ zJ|;;Li$o$0#@IaGSCI-K4v!98`DdJhf68m|dOd7mDJnLh-Yyl7$9sJ~U$9gv@oYBB zbGe);+7v-Zq*Tc>yuzR>Xtbbpts+#{6+^p4V7XtblcQ^XM*1~zSn5pwh;T;|y^zH`AVUuig!M(y$hXT=YK2XFaIk@u)~$^o`i*B z;Vol-u#261WKA*ohP>kG>BW_K8%lv4I%LoIX5F%^Gwz>8*lx}_^QK)CCOvpr7xN2q z%xfZW^WL6n=%V=YR04TTJewon{YC+f8lfmdndaA}&n^lbC+8hAI2MsqrCKRH@SF1D zXkR~h{49y&XnzaF)-1Zf_f1nqY(`A#yn0>=f}orb!LmLzyQPH#=!T$8bj#qj)vC1; z$0_rtR}+i_7JU%EH#Q6lAqS)HM!&>-zHb& zWoBGK*Sk2_s-yC)5whc|x>P^ioLA;8R~gSzclhtI6jNq06DoAF2p?Hn#F9ino*o^=K0BF(fz~u6U Qi2wiq07*qoM6N<$f^k>o4gdfE diff --git a/core/res/res/drawable/rate_star_small_off.png b/core/res/res/drawable/rate_star_small_off.png index 618766fba81d65c9fb82a0e962077c720b9014bc..6fb0a36a85b95f1124d73b6c4c1ae88367d5e2fc 100644 GIT binary patch delta 384 zcmV-`0e}9$0>1;0NPhugNkl%Q9fj7wOV=Gw)33t-GHy0;D0>ZqSS0QONBx~0%YW; zsNZsXz??y~TJ1sCb=fcs(lm`s(^S~Nv0N^t;c&Q~PN%~6eGvq~M&&PcyWOKiln&+^ zjfTSccsv%a>#mf=Vxf#iqw{*bPL)c94$PE@f1)UQCSEK0yebxpcfDRu&E7Pd&4lAP zYlxqq_2MmY0(pY|Xp2x=v1Yec+@N9bT{{>uMluJGhbEW)aj}6#{eE8z27^zC%I$Vr zvMh_RLD};>4Z4qHhH|x9y${2XSNQ_&6&&|x!g#%1@gw+eO5PHiaC|YDd0V;doH0+? e$M;|S3NQe*)1VBoFEh;m0000u+r_DF*~e|13j zvKPJbg&!=r$UMyh2s8v5xCXbyS>Y^z26zG9fGx1)ND6tfNO_T<*akW0(jp_Ts;kGr z5@WbRi|igjYouE%X6G1Jc6}0e;KHVE%@aoSDHU0cx0_HjtPNutu% z#qdxR1)T&j=qLsrf(`|qyGD8KoCifxhzJx1!VYCy=(5_Z%ed>ft~2{FGyUIXg{3aO z!|#2c`Tw8iedb{#`hP{h7>I%Ibb>WGJu{Je{A6?&@%Tv!)_;FmORk>&P(l3pUsD2| zpdXBa`;W#)2JhUvDTkC6ZWxC0O;5H%zXDWHV&}WmT%xZ-N?eTx;_(ao_Q>$*h}yw? zxTdx3FU&2MQmM4J@ikTbp&Ksi?$fN7AFqd6RgKA{Q8Tqs6NSmgESt2UXWZvEJ{=YJE6*4@hr!bp zH8?f1GAPTT0Bam_Z`<}?-1=e{t;#FBzUJ7Dz$^srdpS`j=O$2;Hz z#0J`87efK3=n{%3pK-*@q_sCOE-{9#ie0EyA(cgeFmx|R6K8mC$EL+MDQ|5qlSR_G zfrl}E?Lm~`GAX&5zl6N(@uzl&qq2u25Aj-Nq^8uL_t(|+FVjSXcR#d{x+^S3#-g2;x0zaf`5l8Vrj5iurP2< zKtaLEDmIoDrji4}-o_>={He4NA}XAn7J?U0xGo#mgE{bU7jt-Hj2XYTm&ln1-@G^P zeQ)P`GwV6$Fm6H3J4UxatPcyfjJ+leyP$bW||Ie*9a?s&c8>}i-FsaV_i z;6CRsoC>inxp9t92~$kY2uM!mug~cqR0zTZ^EcCzFQ2!T$jMk=6?ngX12f35@~Q>X&CqEZWM2%t`X%j}uT$u-MpA?t#A_(779|Q8MkP954HmDg zVBg@oJ@oO7xqo2zj#6tpVCsOnoM4x$cLjn zhgS**In;h`HhnI?iL=pZRgqdt8QSl9-zf3uY$L(!)o2KDoge#Do?-vm=&?dfN9UB& zlaR-H%-m)8xW@RIp4`bR9G5>qh89@?6X)#~wkhc+_uEpeYCbjj_`$2|%0RmfqVK?t l7yI+CVPu;!tH}Q=zyO$g(bwB?X59b)002ovPDHLkV1l&8_VEA! diff --git a/core/res/res/layout/zoom_browser_accessory_buttons.xml b/core/res/res/layout/zoom_browser_accessory_buttons.xml index 4bf2bdf8a1583..69afca9003d39 100644 --- a/core/res/res/layout/zoom_browser_accessory_buttons.xml +++ b/core/res/res/layout/zoom_browser_accessory_buttons.xml @@ -18,18 +18,11 @@ */ --> - - diff --git a/core/res/res/values-bg-rBG/donottranslate-cldr.xml b/core/res/res/values-bg-rBG/donottranslate-cldr.xml index b8b50cccdd789..527cdb9a7db50 100644 --- a/core/res/res/values-bg-rBG/donottranslate-cldr.xml +++ b/core/res/res/values-bg-rBG/donottranslate-cldr.xml @@ -111,7 +111,7 @@ %-e %b %b %b %Y - %1$s - %2$s + %1$s-%2$s %2$s - %5$s %3$s.%2$s - %8$s.%7$s %3$s.%2$s, %1$s - %8$s.%7$s, %6$s diff --git a/core/res/res/values-cs-rCZ/donottranslate-cldr.xml b/core/res/res/values-cs-rCZ/donottranslate-cldr.xml deleted file mode 100644 index 41f5dea81f009..0000000000000 --- a/core/res/res/values-cs-rCZ/donottranslate-cldr.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - leden - únor - březen - duben - květen - červen - červenec - srpen - září - říjen - listopad - prosinec - - ledna - února - března - dubna - května - června - července - srpna - září - října - listopadu - prosince - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - - l - ú - b - d - k - č - č - s - z - ř - l - p - - neděle - pondělí - úterý - středa - čtvrtek - pátek - sobota - - ne - po - út - st - čt - - so - - ne - po - út - st - čt - - so - - N - P - Ú - S - Č - P - S - - dop. - odp. - Včera - Dnes - Zítra - - %-k:%M - %-l:%M %p - %-l:%M %^p - h:mm a - H:mm - %-e.%-m.%Y - d.M.yyyy - "%s.%s.%s" - %-e. %B %Y - %-k:%M:%S - %-k:%M:%S %-e.%-m.%Y - %2$s %1$s - %1$s %3$s - %-e.%-m.%Y - %-e. %B - %-B - %-B %Y - %-e.%-m - %-B - %-B %Y - %1$s - %2$s - %2$s - %5$s - %3$s.%2$s. - %8$s.%7$s. - %1$s, %3$s.%2$s. - %6$s, %8$s.%7$s. - %3$s.%2$s.%4$s - %8$s.%7$s.%9$s - %1$s, %3$s.%2$s.%4$s - %6$s, %8$s.%7$s.%9$s - %5$s %1$s, %3$s.%2$s.%4$s - %10$s %6$s, %8$s.%7$s.%9$s - %5$s %3$s.%2$s - %10$s %8$s.%7$s - %5$s %1$s, %3$s.%2$s. - %10$s %6$s, %8$s.%7$s. - %5$s %3$s.%2$s.%4$s - %10$s %8$s.%7$s.%9$s - %3$s %1$s, %2$s - %6$s %4$s, %5$s - %1$s, %2$s - %4$s, %5$s - %3$s %2$s - %6$s %5$s - %1$s %2$s, %3$s - %2$s, %3$s - %1$s %2$s - %3$s. %2$s - %8$s. %7$s - %1$s, %3$s. %2$s - %6$s, %8$s. %7$s - %5$s %3$s. %2$s - %10$s %8$s. %7$s - %5$s %3$s. %2$s - %10$s %8$s. %7$s - %5$s %1$s, %3$s. %2$s - %10$s %6$s, %8$s. %7$s - %5$s %1$s, %3$s. %2$s - %10$s %6$s, %8$s. %7$s - %5$s %3$s. %2$s %4$s - %10$s %8$s. %7$s %9$s - %5$s %3$s. %2$s %4$s - %10$s %8$s. %7$s %9$s - %5$s %1$s, %3$s. %2$s %4$s - %10$s %6$s, %8$s. %7$s %9$s - %5$s %1$s, %3$s. %2$s %4$s - %10$s %6$s, %8$s. %7$s %9$s - %1$s, %3$s. %2$s %4$s - %6$s, %8$s. %7$s %9$s - %3$s.-%8$s. %2$s - %1$s, %3$s. %2$s - %6$s, %8$s. %7$s - %3$s. %2$s - %8$s. %7$s %9$s - %3$s.-%8$s. %2$s %9$s - %1$s, %3$s. %2$s - %6$s, %8$s. %7$s %9$s - %B - diff --git a/core/res/res/values-cs/donottranslate-cldr.xml b/core/res/res/values-cs/donottranslate-cldr.xml index 41f5dea81f009..53dc3121b4ad9 100644 --- a/core/res/res/values-cs/donottranslate-cldr.xml +++ b/core/res/res/values-cs/donottranslate-cldr.xml @@ -27,18 +27,18 @@ listopadu prosince - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 + 1. + 2. + 3. + 4. + 5. + 6. + 7. + 8. + 9. + 10. + 11. + 12. l ú @@ -96,52 +96,52 @@ %-l:%M %^p h:mm a H:mm - %-e.%-m.%Y - d.M.yyyy - "%s.%s.%s" + %-e. %-m. %Y + d. M. yyyy + "%s. %s. %s" %-e. %B %Y %-k:%M:%S - %-k:%M:%S %-e.%-m.%Y + %-k:%M:%S %-e. %-m. %Y %2$s %1$s %1$s %3$s - %-e.%-m.%Y + %-e. %-m. %Y %-e. %B %-B %-B %Y - %-e.%-m + %-e. %-m. %-B %-B %Y - %1$s - %2$s + %1$s-%2$s %2$s - %5$s - %3$s.%2$s. - %8$s.%7$s. - %1$s, %3$s.%2$s. - %6$s, %8$s.%7$s. - %3$s.%2$s.%4$s - %8$s.%7$s.%9$s - %1$s, %3$s.%2$s.%4$s - %6$s, %8$s.%7$s.%9$s - %5$s %1$s, %3$s.%2$s.%4$s - %10$s %6$s, %8$s.%7$s.%9$s - %5$s %3$s.%2$s - %10$s %8$s.%7$s - %5$s %1$s, %3$s.%2$s. - %10$s %6$s, %8$s.%7$s. - %5$s %3$s.%2$s.%4$s - %10$s %8$s.%7$s.%9$s - %3$s %1$s, %2$s - %6$s %4$s, %5$s - %1$s, %2$s - %4$s, %5$s + %3$s. %2$s. - %8$s. %7$s. + %1$s %3$s. %2$s. - %6$s %8$s. %7$s. + %3$s. %2$s. %4$s - %8$s. %7$s. %9$s + %1$s %3$s. %2$s. %4$s - %6$s %8$s. %7$s. %9$s + %5$s %1$s %3$s. %2$s. %4$s - %10$s %6$s %8$s. %7$s. %9$s + %5$s %3$s. %2$s. - %10$s %8$s. %7$s. + %5$s %1$s %3$s. %2$s. - %10$s %6$s %8$s. %7$s. + %5$s %3$s. %2$s. %4$s - %10$s %8$s. %7$s. %9$s + %3$s %1$s %2$s - %6$s %4$s %5$s + %1$s %2$s - %4$s %5$s %3$s %2$s - %6$s %5$s - %1$s %2$s, %3$s - %2$s, %3$s + %1$s %2$s %3$s + %2$s %3$s %1$s %2$s %3$s. %2$s - %8$s. %7$s - %1$s, %3$s. %2$s - %6$s, %8$s. %7$s + %1$s %3$s. %2$s - %6$s %8$s. %7$s %5$s %3$s. %2$s - %10$s %8$s. %7$s %5$s %3$s. %2$s - %10$s %8$s. %7$s - %5$s %1$s, %3$s. %2$s - %10$s %6$s, %8$s. %7$s - %5$s %1$s, %3$s. %2$s - %10$s %6$s, %8$s. %7$s + %5$s %1$s %3$s. %2$s - %10$s %6$s %8$s. %7$s + %5$s %1$s %3$s. %2$s - %10$s %6$s %8$s. %7$s %5$s %3$s. %2$s %4$s - %10$s %8$s. %7$s %9$s %5$s %3$s. %2$s %4$s - %10$s %8$s. %7$s %9$s - %5$s %1$s, %3$s. %2$s %4$s - %10$s %6$s, %8$s. %7$s %9$s - %5$s %1$s, %3$s. %2$s %4$s - %10$s %6$s, %8$s. %7$s %9$s - %1$s, %3$s. %2$s %4$s - %6$s, %8$s. %7$s %9$s + %5$s %1$s %3$s. %2$s %4$s - %10$s %6$s %8$s. %7$s %9$s + %5$s %1$s %3$s. %2$s %4$s - %10$s %6$s %8$s. %7$s %9$s + %1$s %3$s. %2$s %4$s - %6$s %8$s. %7$s %9$s %3$s.-%8$s. %2$s - %1$s, %3$s. %2$s - %6$s, %8$s. %7$s + %1$s %3$s. %2$s - %6$s %8$s. %7$s %3$s. %2$s - %8$s. %7$s %9$s %3$s.-%8$s. %2$s %9$s - %1$s, %3$s. %2$s - %6$s, %8$s. %7$s %9$s - %B + %1$s %3$s. %2$s - %6$s %8$s. %7$s %9$s + %b diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 7160b41f49301..35a169f85cad7 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -111,7 +111,6 @@ "K souboru nelze získat přístup." "Požadovaný soubor nebyl nalezen." "Je zpracováváno příliš mnoho požadavků. Opakujte akci později." - "Certifikát je uložen v systémovém úložišti klíčů." "Synchronizace" "Synchronizace" "Příliš mnoho smazaných položek služby %s." diff --git a/core/res/res/values-da-rDK/donottranslate-cldr.xml b/core/res/res/values-da-rDK/donottranslate-cldr.xml deleted file mode 100644 index 2d0db938a69f7..0000000000000 --- a/core/res/res/values-da-rDK/donottranslate-cldr.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - januar - februar - marts - april - maj - juni - juli - august - september - oktober - november - december - - januar - februar - marts - april - maj - juni - juli - august - september - oktober - november - december - - jan. - feb. - mar. - apr. - maj - jun. - jul. - aug. - sep. - okt. - nov. - dec. - - J - F - M - A - M - J - J - A - S - O - N - D - - søndag - mandag - tirsdag - onsdag - torsdag - fredag - lørdag - - søn - man - tir - ons - tor - fre - lør - - søn - man - tir - ons - tor - fre - lør - - S - M - T - O - T - F - L - - f.m. - e.m. - i går - i dag - i morgen - - %H.%M - %-l.%M %p - %-l.%M %^p - h.mm a - HH.mm - %d/%m/%Y - dd/MM/yyyy - "%s/%s/%s" - %-e. %b %Y - %H.%M.%S - %H.%M.%S %d/%m/%Y - %2$s %1$s - %1$s %3$s - %d/%m/%Y - %-e. %B - %B - %B %Y - %-e. %b - %b - %b %Y - %1$s - %2$s - %2$s - %5$s - %3$s/%2$s - %8$s/%7$s - %1$s %3$s/%2$s - %6$s %8$s/%7$s - %3$s/%2$s/%4$s - %8$s/%7$s/%9$s - %1$s %3$s/%2$s/%4$s - %6$s %8$s/%7$s/%9$s - %5$s %1$s. %3$s-%2$s-%4$s - %10$s %6$s. %8$s-%7$s-%9$s - %5$s %3$s/%2$s - %10$s %8$s/%7$s - %5$s %1$s. %3$s-%2$s - %10$s %6$s. %8$s-%7$s - %5$s %3$s/%2$s/%4$s - %10$s %8$s/%7$s/%9$s - %3$s %1$s den %2$s - %6$s %4$s den %5$s - %1$s den %2$s - %4$s den %5$s - %3$s %2$s - %6$s %5$s - %1$s %2$s den %3$s - %2$s den %3$s - %1$s %2$s - %3$s. %2$s - %8$s. %7$s - %1$s %3$s %2$s - %6$s %8$s %7$s - %5$s %3$s. %2$s - %10$s %8$s. %7$s - %5$s %3$s. %2$s - %10$s %8$s. %7$s - %5$s %1$s %3$s %2$s - %10$s %6$s %8$s %7$s - %5$s %1$s %3$s %2$s - %10$s %6$s %8$s %7$s - %5$s %3$s. %2$s %4$s - %10$s %8$s. %7$s %9$s - %5$s %3$s. %2$s %4$s - %10$s %8$s. %7$s %9$s - %5$s %1$s. %3$s. %2$s %4$s - %10$s %6$s. %8$s. %7$s %9$s - %5$s %1$s. %3$s. %2$s %4$s - %10$s %6$s. %8$s. %7$s %9$s - %1$s. %3$s. %2$s %4$s - %6$s. %8$s. %7$s %9$s - %3$s.-%8$s. %2$s - %1$s %3$s %2$s - %6$s %8$s %7$s - %3$s. %2$s - %8$s. %7$s %9$s - %3$s.-%8$s. %2$s %9$s - %1$s den %3$s. %2$s - %6$s den %8$s. %7$s %9$s - %b - diff --git a/core/res/res/values-da/donottranslate-cldr.xml b/core/res/res/values-da/donottranslate-cldr.xml index 2d0db938a69f7..a4faca278cdda 100644 --- a/core/res/res/values-da/donottranslate-cldr.xml +++ b/core/res/res/values-da/donottranslate-cldr.xml @@ -61,21 +61,21 @@ fredag lørdag - søn - man - tir - ons - tor - fre - lør + søn. + man. + tir. + ons. + tor. + fre. + lør. - søn - man - tir - ons - tor - fre - lør + søn. + man. + tir. + ons. + tor. + fre. + lør. S M @@ -91,20 +91,20 @@ i dag i morgen - %H.%M + %H:%M %-l.%M %p %-l.%M %^p h.mm a - HH.mm + HH:mm %d/%m/%Y dd/MM/yyyy "%s/%s/%s" - %-e. %b %Y - %H.%M.%S - %H.%M.%S %d/%m/%Y - %2$s %1$s - %1$s %3$s - %d/%m/%Y + %-e. %B %Y + %H:%M:%S + %H:%M:%S, %-e. %b %Y + %2$s, %1$s + %1$s, %3$s + %-e. %b %Y %-e. %B %B %B %Y @@ -117,31 +117,31 @@ %1$s %3$s/%2$s - %6$s %8$s/%7$s %3$s/%2$s/%4$s - %8$s/%7$s/%9$s %1$s %3$s/%2$s/%4$s - %6$s %8$s/%7$s/%9$s - %5$s %1$s. %3$s-%2$s-%4$s - %10$s %6$s. %8$s-%7$s-%9$s - %5$s %3$s/%2$s - %10$s %8$s/%7$s - %5$s %1$s. %3$s-%2$s - %10$s %6$s. %8$s-%7$s - %5$s %3$s/%2$s/%4$s - %10$s %8$s/%7$s/%9$s - %3$s %1$s den %2$s - %6$s %4$s den %5$s - %1$s den %2$s - %4$s den %5$s - %3$s %2$s - %6$s %5$s - %1$s %2$s den %3$s - %2$s den %3$s - %1$s %2$s + %5$s, %1$s %3$s/%2$s/%4$s - %10$s, %6$s %8$s/%7$s/%9$s + %5$s, %3$s/%2$s - %10$s, %8$s/%7$s + %5$s, %1$s %3$s/%2$s - %10$s, %6$s %8$s/%7$s + %5$s, %3$s/%2$s/%4$s - %10$s, %8$s/%7$s/%9$s + %3$s, %1$s %2$s - %6$s, %4$s %5$s + %1$s %2$s - %4$s %5$s + %3$s, %2$s - %6$s, %5$s + %1$s, %2$s %3$s + %2$s %3$s + %1$s, %2$s %3$s. %2$s - %8$s. %7$s - %1$s %3$s %2$s - %6$s %8$s %7$s - %5$s %3$s. %2$s - %10$s %8$s. %7$s - %5$s %3$s. %2$s - %10$s %8$s. %7$s - %5$s %1$s %3$s %2$s - %10$s %6$s %8$s %7$s - %5$s %1$s %3$s %2$s - %10$s %6$s %8$s %7$s - %5$s %3$s. %2$s %4$s - %10$s %8$s. %7$s %9$s - %5$s %3$s. %2$s %4$s - %10$s %8$s. %7$s %9$s - %5$s %1$s. %3$s. %2$s %4$s - %10$s %6$s. %8$s. %7$s %9$s - %5$s %1$s. %3$s. %2$s %4$s - %10$s %6$s. %8$s. %7$s %9$s - %1$s. %3$s. %2$s %4$s - %6$s. %8$s. %7$s %9$s + %1$s %3$s. %2$s - %6$s %8$s. %7$s + %5$s, %3$s. %2$s - %10$s, %8$s. %7$s + %5$s, %3$s. %2$s - %10$s, %8$s. %7$s + %5$s, %1$s %3$s. %2$s - %10$s, %6$s %8$s. %7$s + %5$s, %1$s %3$s. %2$s - %10$s, %6$s %8$s. %7$s + %5$s, %3$s. %2$s %4$s - %10$s, %8$s. %7$s %9$s + %5$s, %3$s. %2$s %4$s - %10$s, %8$s. %7$s %9$s + %5$s, %1$s %3$s. %2$s %4$s - %10$s, %6$s %8$s. %7$s %9$s + %5$s, %1$s %3$s. %2$s %4$s - %10$s, %6$s %8$s. %7$s %9$s + %1$s %3$s. %2$s %4$s - %6$s %8$s. %7$s %9$s %3$s.-%8$s. %2$s - %1$s %3$s %2$s - %6$s %8$s %7$s + %1$s %3$s. %2$s - %6$s %8$s. %7$s %3$s. %2$s - %8$s. %7$s %9$s %3$s.-%8$s. %2$s %9$s - %1$s den %3$s. %2$s - %6$s den %8$s. %7$s %9$s + %1$s d. %3$s. %2$s - %6$s d. %8$s. %7$s %9$s %b diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index a3e8dc5d06f3d..33925466d45f1 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -134,8 +134,6 @@ "Der kunne ikke oprettes adgang til filen." "Den anmodede fil blev ikke fundet." "Der behandles for mange anmodninger. Prøv igen senere." - - "Synkroniser" "Synkroniser" "For mange %s sletninger" diff --git a/core/res/res/values-de-rAT/donottranslate-cldr.xml b/core/res/res/values-de-rAT/donottranslate-cldr.xml deleted file mode 100644 index 27624a36ab426..0000000000000 --- a/core/res/res/values-de-rAT/donottranslate-cldr.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - Jänner - Februar - März - April - Mai - Juni - Juli - August - September - Oktober - November - Dezember - - Jänner - Februar - März - April - Mai - Juni - Juli - August - September - Oktober - November - Dezember - - Jän - Feb - Mär - Apr - Mai - Jun - Jul - Aug - Sep - Okt - Nov - Dez - - J - F - M - A - M - J - J - A - S - O - N - D - - Sonntag - Montag - Dienstag - Mittwoch - Donnerstag - Freitag - Samstag - - So. - Mo. - Di. - Mi. - Do. - Fr. - Sa. - - So. - Mo. - Di. - Mi. - Do. - Fr. - Sa. - - S - M - D - M - D - F - S - - vorm. - nachm. - Gestern - Heute - Morgen - - %-k:%M - %-l:%M %p - %-l:%M %^p - h:mm a - H:mm - %d.%m.%Y - dd.MM.yyyy - "%s.%s.%s" - %d. %B %Y - %H:%M:%S - %H:%M:%S %d.%m.%Y - %2$s %1$s - %1$s %3$s - %d.%m.%Y - %-e. %B - %-B - %B %Y - %d. %b - %-b - %b %Y - %1$s - %2$s - %2$s - %5$s - %3$s.%2$s. - %8$s.%7$s. - %1$s, %3$s.%2$s. - %6$s, %8$s.%7$s. - %3$s.%2$s.%4$s - %8$s.%7$s.%9$s - %1$s, %3$s.%2$s.%4$s - %6$s, %8$s.%7$s.%9$s - %5$s %1$s, %3$s.%2$s.%4$s - %10$s %6$s, %8$s.%7$s.%9$s - %5$s %3$s.%2$s. - %10$s %8$s.%7$s. - %5$s %1$s, %3$s.%2$s. - %10$s %6$s, %8$s.%7$s. - %5$s %3$s.%2$s.%4$s - %10$s %8$s.%7$s.%9$s - %3$s %1$s, %2$s - %6$s %4$s, %5$s - %1$s, %2$s - %4$s, %5$s - %3$s %2$s - %6$s %5$s - %1$s %2$s, %3$s - %2$s, %3$s - %1$s %2$s - %3$s. %2$s - %8$s. %7$s - %1$s, %3$s. %2$s - %6$s, %8$s. %7$s - %5$s %3$s. %2$s - %10$s %8$s. %7$s - %5$s %3$s. %2$s - %10$s %8$s. %7$s - %5$s %1$s, %3$s. %2$s - %10$s %6$s, %8$s. %7$s - %5$s %1$s, %3$s. %2$s - %10$s %6$s, %8$s. %7$s - %5$s %3$s. %2$s %4$s - %10$s %8$s. %7$s %9$s - %5$s %3$s. %2$s %4$s - %10$s %8$s. %7$s %9$s - %5$s %1$s, %3$s. %2$s %4$s - %10$s %6$s, %8$s. %7$s %9$s - %5$s %1$s, %3$s. %2$s %4$s - %10$s %6$s, %8$s. %7$s %9$s - %1$s, %3$s. %2$s %4$s - %6$s, %8$s. %7$s %9$s - %3$s.-%8$s. %2$s - %1$s, %3$s. %2$s - %6$s, %8$s. %7$s - %3$s. %2$s - %8$s. %7$s %9$s - %3$s.-%8$s. %2$s %9$s - %1$s, %3$s. %2$s - %6$s, %8$s. %7$s %9$s - %b - diff --git a/core/res/res/values-de-rCH/donottranslate-cldr.xml b/core/res/res/values-de-rCH/donottranslate-cldr.xml deleted file mode 100644 index f32095bd336e5..0000000000000 --- a/core/res/res/values-de-rCH/donottranslate-cldr.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - Januar - Februar - März - April - Mai - Juni - Juli - August - September - Oktober - November - Dezember - - Januar - Februar - März - April - Mai - Juni - Juli - August - September - Oktober - November - Dezember - - Jan - Feb - Mär - Apr - Mai - Jun - Jul - Aug - Sep - Okt - Nov - Dez - - J - F - M - A - M - J - J - A - S - O - N - D - - Sonntag - Montag - Dienstag - Mittwoch - Donnerstag - Freitag - Samstag - - So. - Mo. - Di. - Mi. - Do. - Fr. - Sa. - - So. - Mo. - Di. - Mi. - Do. - Fr. - Sa. - - S - M - D - M - D - F - S - - vorm. - nachm. - Gestern - Heute - Morgen - - %-k:%M - %-l:%M %p - %-l:%M %^p - h:mm a - H:mm - %d.%m.%Y - dd.MM.yyyy - "%s.%s.%s" - %-e. %B %Y - %H:%M:%S - %H:%M:%S %d.%m.%Y - %2$s %1$s - %1$s %3$s - %d.%m.%Y - %-e. %B - %-B - %B %Y - %-e. %b - %-b - %b %Y - %1$s - %2$s - %2$s - %5$s - %3$s.%2$s. - %8$s.%7$s. - %1$s, %3$s.%2$s. - %6$s, %8$s.%7$s. - %3$s.%2$s.%4$s - %8$s.%7$s.%9$s - %1$s, %3$s.%2$s.%4$s - %6$s, %8$s.%7$s.%9$s - %5$s %1$s, %3$s.%2$s.%4$s - %10$s %6$s, %8$s.%7$s.%9$s - %5$s %3$s.%2$s. - %10$s %8$s.%7$s. - %5$s %1$s, %3$s.%2$s. - %10$s %6$s, %8$s.%7$s. - %5$s %3$s.%2$s.%4$s - %10$s %8$s.%7$s.%9$s - %3$s %1$s %2$s - %6$s %4$s %5$s - %1$s %2$s - %4$s %5$s - %3$s %2$s - %6$s %5$s - %1$s %2$s %3$s - %2$s %3$s - %1$s %2$s - %3$s. %2$s - %8$s. %7$s - %1$s %3$s. %2$s - %6$s %8$s. %7$s - %5$s %3$s. %2$s - %10$s %8$s. %7$s - %5$s %3$s. %2$s - %10$s %8$s. %7$s - %5$s %1$s %3$s. %2$s - %10$s %6$s %8$s. %7$s - %5$s %1$s %3$s. %2$s - %10$s %6$s %8$s. %7$s - %5$s %3$s. %2$s %4$s - %10$s %8$s. %7$s %9$s - %5$s %3$s. %2$s %4$s - %10$s %8$s. %7$s %9$s - %5$s %1$s, %3$s. %2$s %4$s - %10$s %6$s, %8$s. %7$s %9$s - %5$s %1$s, %3$s. %2$s %4$s - %10$s %6$s, %8$s. %7$s %9$s - %1$s, %3$s. %2$s %4$s - %6$s, %8$s. %7$s %9$s - %3$s.-%8$s. %2$s - %1$s %3$s. %2$s - %6$s %8$s. %7$s - %3$s. %2$s - %8$s. %7$s %9$s - %3$s.-%8$s. %2$s %9$s - %1$s, %3$s. %2$s - %6$s, %8$s. %7$s %9$s - %b - diff --git a/core/res/res/values-de-rDE/donottranslate-cldr.xml b/core/res/res/values-de-rDE/donottranslate-cldr.xml deleted file mode 100644 index f32095bd336e5..0000000000000 --- a/core/res/res/values-de-rDE/donottranslate-cldr.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - Januar - Februar - März - April - Mai - Juni - Juli - August - September - Oktober - November - Dezember - - Januar - Februar - März - April - Mai - Juni - Juli - August - September - Oktober - November - Dezember - - Jan - Feb - Mär - Apr - Mai - Jun - Jul - Aug - Sep - Okt - Nov - Dez - - J - F - M - A - M - J - J - A - S - O - N - D - - Sonntag - Montag - Dienstag - Mittwoch - Donnerstag - Freitag - Samstag - - So. - Mo. - Di. - Mi. - Do. - Fr. - Sa. - - So. - Mo. - Di. - Mi. - Do. - Fr. - Sa. - - S - M - D - M - D - F - S - - vorm. - nachm. - Gestern - Heute - Morgen - - %-k:%M - %-l:%M %p - %-l:%M %^p - h:mm a - H:mm - %d.%m.%Y - dd.MM.yyyy - "%s.%s.%s" - %-e. %B %Y - %H:%M:%S - %H:%M:%S %d.%m.%Y - %2$s %1$s - %1$s %3$s - %d.%m.%Y - %-e. %B - %-B - %B %Y - %-e. %b - %-b - %b %Y - %1$s - %2$s - %2$s - %5$s - %3$s.%2$s. - %8$s.%7$s. - %1$s, %3$s.%2$s. - %6$s, %8$s.%7$s. - %3$s.%2$s.%4$s - %8$s.%7$s.%9$s - %1$s, %3$s.%2$s.%4$s - %6$s, %8$s.%7$s.%9$s - %5$s %1$s, %3$s.%2$s.%4$s - %10$s %6$s, %8$s.%7$s.%9$s - %5$s %3$s.%2$s. - %10$s %8$s.%7$s. - %5$s %1$s, %3$s.%2$s. - %10$s %6$s, %8$s.%7$s. - %5$s %3$s.%2$s.%4$s - %10$s %8$s.%7$s.%9$s - %3$s %1$s %2$s - %6$s %4$s %5$s - %1$s %2$s - %4$s %5$s - %3$s %2$s - %6$s %5$s - %1$s %2$s %3$s - %2$s %3$s - %1$s %2$s - %3$s. %2$s - %8$s. %7$s - %1$s %3$s. %2$s - %6$s %8$s. %7$s - %5$s %3$s. %2$s - %10$s %8$s. %7$s - %5$s %3$s. %2$s - %10$s %8$s. %7$s - %5$s %1$s %3$s. %2$s - %10$s %6$s %8$s. %7$s - %5$s %1$s %3$s. %2$s - %10$s %6$s %8$s. %7$s - %5$s %3$s. %2$s %4$s - %10$s %8$s. %7$s %9$s - %5$s %3$s. %2$s %4$s - %10$s %8$s. %7$s %9$s - %5$s %1$s, %3$s. %2$s %4$s - %10$s %6$s, %8$s. %7$s %9$s - %5$s %1$s, %3$s. %2$s %4$s - %10$s %6$s, %8$s. %7$s %9$s - %1$s, %3$s. %2$s %4$s - %6$s, %8$s. %7$s %9$s - %3$s.-%8$s. %2$s - %1$s %3$s. %2$s - %6$s %8$s. %7$s - %3$s. %2$s - %8$s. %7$s %9$s - %3$s.-%8$s. %2$s %9$s - %1$s, %3$s. %2$s - %6$s, %8$s. %7$s %9$s - %b - diff --git a/core/res/res/values-de-rLI/donottranslate-cldr.xml b/core/res/res/values-de-rLI/donottranslate-cldr.xml deleted file mode 100644 index f32095bd336e5..0000000000000 --- a/core/res/res/values-de-rLI/donottranslate-cldr.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - Januar - Februar - März - April - Mai - Juni - Juli - August - September - Oktober - November - Dezember - - Januar - Februar - März - April - Mai - Juni - Juli - August - September - Oktober - November - Dezember - - Jan - Feb - Mär - Apr - Mai - Jun - Jul - Aug - Sep - Okt - Nov - Dez - - J - F - M - A - M - J - J - A - S - O - N - D - - Sonntag - Montag - Dienstag - Mittwoch - Donnerstag - Freitag - Samstag - - So. - Mo. - Di. - Mi. - Do. - Fr. - Sa. - - So. - Mo. - Di. - Mi. - Do. - Fr. - Sa. - - S - M - D - M - D - F - S - - vorm. - nachm. - Gestern - Heute - Morgen - - %-k:%M - %-l:%M %p - %-l:%M %^p - h:mm a - H:mm - %d.%m.%Y - dd.MM.yyyy - "%s.%s.%s" - %-e. %B %Y - %H:%M:%S - %H:%M:%S %d.%m.%Y - %2$s %1$s - %1$s %3$s - %d.%m.%Y - %-e. %B - %-B - %B %Y - %-e. %b - %-b - %b %Y - %1$s - %2$s - %2$s - %5$s - %3$s.%2$s. - %8$s.%7$s. - %1$s, %3$s.%2$s. - %6$s, %8$s.%7$s. - %3$s.%2$s.%4$s - %8$s.%7$s.%9$s - %1$s, %3$s.%2$s.%4$s - %6$s, %8$s.%7$s.%9$s - %5$s %1$s, %3$s.%2$s.%4$s - %10$s %6$s, %8$s.%7$s.%9$s - %5$s %3$s.%2$s. - %10$s %8$s.%7$s. - %5$s %1$s, %3$s.%2$s. - %10$s %6$s, %8$s.%7$s. - %5$s %3$s.%2$s.%4$s - %10$s %8$s.%7$s.%9$s - %3$s %1$s %2$s - %6$s %4$s %5$s - %1$s %2$s - %4$s %5$s - %3$s %2$s - %6$s %5$s - %1$s %2$s %3$s - %2$s %3$s - %1$s %2$s - %3$s. %2$s - %8$s. %7$s - %1$s %3$s. %2$s - %6$s %8$s. %7$s - %5$s %3$s. %2$s - %10$s %8$s. %7$s - %5$s %3$s. %2$s - %10$s %8$s. %7$s - %5$s %1$s %3$s. %2$s - %10$s %6$s %8$s. %7$s - %5$s %1$s %3$s. %2$s - %10$s %6$s %8$s. %7$s - %5$s %3$s. %2$s %4$s - %10$s %8$s. %7$s %9$s - %5$s %3$s. %2$s %4$s - %10$s %8$s. %7$s %9$s - %5$s %1$s, %3$s. %2$s %4$s - %10$s %6$s, %8$s. %7$s %9$s - %5$s %1$s, %3$s. %2$s %4$s - %10$s %6$s, %8$s. %7$s %9$s - %1$s, %3$s. %2$s %4$s - %6$s, %8$s. %7$s %9$s - %3$s.-%8$s. %2$s - %1$s %3$s. %2$s - %6$s %8$s. %7$s - %3$s. %2$s - %8$s. %7$s %9$s - %3$s.-%8$s. %2$s %9$s - %1$s, %3$s. %2$s - %6$s, %8$s. %7$s %9$s - %b - diff --git a/core/res/res/values-de/donottranslate-cldr.xml b/core/res/res/values-de/donottranslate-cldr.xml index f32095bd336e5..babf1a0581b42 100644 --- a/core/res/res/values-de/donottranslate-cldr.xml +++ b/core/res/res/values-de/donottranslate-cldr.xml @@ -27,18 +27,18 @@ November Dezember - Jan - Feb - Mär - Apr - Mai - Jun - Jul - Aug - Sep - Okt - Nov - Dez + Jan. + Feb. + Mär. + Apr. + Mai. + Jun. + Jul. + Aug. + Sep. + Okt. + Nov. + Dez. J F @@ -91,19 +91,19 @@ Heute Morgen - %-k:%M + %-k:%M h %-l:%M %p %-l:%M %^p h:mm a - H:mm + H:mm \'h\' %d.%m.%Y dd.MM.yyyy "%s.%s.%s" %-e. %B %Y - %H:%M:%S - %H:%M:%S %d.%m.%Y - %2$s %1$s - %1$s %3$s + %H:%M:%S h + %d.%m.%Y, %H:%M:%S h + %1$s, %2$s + %3$s, %1$s %d.%m.%Y %-e. %B %-B @@ -111,37 +111,37 @@ %-e. %b %-b %b %Y - %1$s - %2$s - %2$s - %5$s - %3$s.%2$s. - %8$s.%7$s. - %1$s, %3$s.%2$s. - %6$s, %8$s.%7$s. - %3$s.%2$s.%4$s - %8$s.%7$s.%9$s - %1$s, %3$s.%2$s.%4$s - %6$s, %8$s.%7$s.%9$s - %5$s %1$s, %3$s.%2$s.%4$s - %10$s %6$s, %8$s.%7$s.%9$s - %5$s %3$s.%2$s. - %10$s %8$s.%7$s. - %5$s %1$s, %3$s.%2$s. - %10$s %6$s, %8$s.%7$s. - %5$s %3$s.%2$s.%4$s - %10$s %8$s.%7$s.%9$s - %3$s %1$s %2$s - %6$s %4$s %5$s - %1$s %2$s - %4$s %5$s - %3$s %2$s - %6$s %5$s - %1$s %2$s %3$s - %2$s %3$s - %1$s %2$s - %3$s. %2$s - %8$s. %7$s - %1$s %3$s. %2$s - %6$s %8$s. %7$s - %5$s %3$s. %2$s - %10$s %8$s. %7$s - %5$s %3$s. %2$s - %10$s %8$s. %7$s - %5$s %1$s %3$s. %2$s - %10$s %6$s %8$s. %7$s - %5$s %1$s %3$s. %2$s - %10$s %6$s %8$s. %7$s - %5$s %3$s. %2$s %4$s - %10$s %8$s. %7$s %9$s - %5$s %3$s. %2$s %4$s - %10$s %8$s. %7$s %9$s - %5$s %1$s, %3$s. %2$s %4$s - %10$s %6$s, %8$s. %7$s %9$s - %5$s %1$s, %3$s. %2$s %4$s - %10$s %6$s, %8$s. %7$s %9$s - %1$s, %3$s. %2$s %4$s - %6$s, %8$s. %7$s %9$s - %3$s.-%8$s. %2$s - %1$s %3$s. %2$s - %6$s %8$s. %7$s - %3$s. %2$s - %8$s. %7$s %9$s - %3$s.-%8$s. %2$s %9$s - %1$s, %3$s. %2$s - %6$s, %8$s. %7$s %9$s + %1$s bis %2$s + %2$s bis %5$s + %3$s.%2$s. bis %8$s.%7$s. + %1$s, %3$s.%2$s. bis %6$s, %8$s.%7$s. + %3$s.%2$s.%4$s bis %8$s.%7$s.%9$s + %1$s, %3$s.%2$s.%4$s bis %6$s, %8$s.%7$s.%9$s + %1$s, %3$s.%2$s.%4$s, %5$s bis %6$s, %8$s.%7$s.%9$s, %10$s + %3$s.%2$s., %5$s bis %8$s.%7$s., %10$s + %1$s, %3$s.%2$s., %5$s bis %6$s, %8$s.%7$s., %10$s + %3$s.%2$s.%4$s, %5$s bis %8$s.%7$s.%9$s, %10$s + %1$s, %2$s, %3$s bis %4$s, %5$s, %6$s + %1$s, %2$s bis %4$s, %5$s + %2$s, %3$s bis %5$s, %6$s + %2$s, %3$s, %1$s + %2$s, %3$s + %2$s, %1$s + %3$s. %2$s bis %8$s. %7$s + %1$s, %3$s. %2$s bis %6$s, %8$s. %7$s + %3$s. %2$s, %5$s bis %8$s. %7$s, %10$s + %3$s. %2$s, %5$s bis %8$s. %7$s, %10$s + %1$s, %3$s. %2$s, %5$s bis %6$s, %8$s. %7$s, %10$s + %1$s, %3$s. %2$s, %5$s bis %6$s, %8$s. %7$s, %10$s + %3$s. %2$s %4$s, %5$s bis %8$s. %7$s %9$s, %10$s + %3$s. %2$s %4$s, %5$s bis %8$s. %7$s %9$s, %10$s + %1$s, %3$s. %2$s %4$s, %5$s bis %6$s, %8$s. %7$s %9$s, %10$s + %1$s, %3$s. %2$s %4$s, %5$s bis %6$s, %8$s. %7$s %9$s, %10$s + %1$s, %3$s. %2$s %4$s bis %6$s, %8$s. %7$s %9$s + %3$s. bis %8$s. %2$s + %1$s, %3$s. %2$s bis %6$s, %8$s. %7$s + %3$s. %2$s bis %8$s. %7$s %9$s + %3$s. bis %8$s. %2$s %9$s + %1$s, %3$s. %2$s bis %6$s, %8$s. %7$s %9$s %b diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 56d9ef829641a..1f9001b7313da 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -111,7 +111,6 @@ "Auf die Datei konnte nicht zugegriffen werden." "Die angeforderte Datei wurde nicht gefunden." "Es werden zurzeit zu viele Anfragen verarbeitet. Versuchen Sie es später erneut." - "Das Zertifikat wird im Schlüsselspeicher des Systems gespeichert." "Synchronisieren" "Synchronisieren" "Zu viele %s gelöscht." diff --git a/core/res/res/values-el-rGR/donottranslate-cldr.xml b/core/res/res/values-el-rGR/donottranslate-cldr.xml deleted file mode 100644 index e8f02fb0d47b6..0000000000000 --- a/core/res/res/values-el-rGR/donottranslate-cldr.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - Ιανουάριος - Φεβρουάριος - Μάρτιος - Απρίλιος - Μάιος - Ιούνιος - Ιούλιος - Αύγουστος - Σεπτέμβριος - Οκτώβριος - Νοέμβριος - Δεκέμβριος - - Ιανουαρίου - Φεβρουαρίου - Μαρτίου - Απριλίου - Μαΐου - Ιουνίου - Ιουλίου - Αυγούστου - Σεπτεμβρίου - Οκτωβρίου - Νοεμβρίου - Δεκεμβρίου - - Ιαν - Φεβ - Μαρ - Απρ - Μαϊ - Ιουν - Ιουλ - Αυγ - Σεπ - Οκτ - Νοε - Δεκ - - Ι - Φ - Μ - Α - Μ - Ι - Ι - Α - Σ - Ο - Ν - Δ - - Κυριακή - Δευτέρα - Τρίτη - Τετάρτη - Πέμπτη - Παρασκευή - Σάββατο - - Κυρ - Δευ - Τρι - Τετ - Πεμ - Παρ - Σαβ - - Κυρ - Δευ - Τρι - Τετ - Πεμ - Παρ - Σαβ - - Κ - Δ - Τ - Τ - Π - Π - Σ - - π.μ. - μ.μ. - Χτες - Σήμερα - Αύριο - - %-k:%M - %-l:%M %p - %-l:%M %p - h:mm a - H:mm - %d/%m/%Y - dd/MM/yyyy - "%s/%s/%s" - %d %B %Y - %-l:%M:%S %p - %-l:%M:%S %p %d %b %Y - %2$s %1$s - %1$s %3$s - %d %b %Y - %-e %B - %-B - %-B %Y - %-e %b - %-b - %b %Y - %1$s - %2$s - %2$s - %5$s - %3$s/%2$s - %8$s/%7$s - %1$s, %3$s/%2$s - %6$s, %8$s/%7$s - %3$s/%2$s/%4$s - %8$s/%7$s/%9$s - %1$s, %3$s/%2$s/%4$s - %6$s, %8$s/%7$s/%9$s - %5$s %1$s, %3$s/%2$s/%4$s - %10$s %6$s, %8$s/%7$s/%9$s - %5$s %3$s/%2$s - %10$s %8$s/%7$s - %5$s %1$s, %3$s/%2$s - %10$s %6$s, %8$s/%7$s - %5$s %3$s/%2$s/%4$s - %10$s %8$s/%7$s/%9$s - %3$s %1$s, %2$s - %6$s %4$s, %5$s - %1$s, %2$s - %4$s, %5$s - %3$s %2$s - %6$s %5$s - %1$s %2$s, %3$s - %2$s, %3$s - %1$s %2$s - %3$s %2$s - %8$s %7$s - %1$s, %3$s %2$s - %6$s, %8$s %7$s - %5$s %3$s %2$s - %10$s %8$s %7$s - %5$s %3$s %2$s - %10$s %8$s %7$s - %5$s %1$s, %3$s %2$s - %10$s %6$s, %8$s %7$s - %5$s %1$s, %3$s %2$s - %10$s %6$s, %8$s %7$s - %5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s - %5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s - %5$s %1$s, %3$s %2$s %4$s - %10$s %6$s, %8$s %7$s %9$s - %5$s %1$s, %3$s %2$s %4$s - %10$s %6$s, %8$s %7$s %9$s - %1$s, %3$s %2$s %4$s - %6$s, %8$s %7$s %9$s - %3$s-%8$s %2$s - %1$s, %3$s %2$s - %6$s, %8$s %7$s - %3$s %2$s - %8$s %7$s %9$s - %3$s-%8$s %2$s %9$s - %1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s - %b - diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 5c6ba5ac79cfc..e340095f70bbc 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -134,8 +134,6 @@ "Η πρόσβαση στο αρχείο δεν ήταν δυνατή." "Το αρχείο που ζητήθηκε δεν βρέθηκε." "Πραγματοποιείται επεξεργασία πάρα πολλών αιτημάτων. Προσπαθήστε ξανά αργότερα." - - "Συγχρονισμός" "Συγχρονισμός" "Πάρα πολλές %s διαγραφές." diff --git a/core/res/res/values-en-rGB/donottranslate-cldr.xml b/core/res/res/values-en-rGB/donottranslate-cldr.xml index 0e3e035b7587d..65545bae90bb8 100644 --- a/core/res/res/values-en-rGB/donottranslate-cldr.xml +++ b/core/res/res/values-en-rGB/donottranslate-cldr.xml @@ -121,25 +121,25 @@ %3$s/%2$s, %5$s - %8$s/%7$s, %10$s %1$s, %3$s/%2$s, %5$s - %6$s, %8$s/%7$s, %10$s %3$s/%2$s/%4$s, %5$s - %8$s/%7$s/%9$s, %10$s - %1$s %2$s, %3$s - %4$s %5$s, %6$s - %1$s %2$s - %4$s %5$s + %1$s, %2$s, %3$s - %4$s, %5$s, %6$s + %1$s, %2$s - %4$s, %5$s %2$s, %3$s - %5$s, %6$s - %1$s, %2$s %3$s - %2$s %3$s + %1$s, %2$s, %3$s + %2$s, %3$s %1$s, %2$s %3$s %2$s - %8$s %7$s - %1$s %3$s %2$s - %6$s %8$s %7$s + %1$s, %3$s %2$s - %6$s, %8$s %7$s %3$s %2$s, %5$s - %8$s %7$s, %10$s %3$s %2$s, %5$s - %8$s %7$s, %10$s - %1$s %3$s %2$s, %5$s - %6$s %8$s %7$s, %10$s - %1$s %3$s %2$s, %5$s - %6$s %8$s %7$s, %10$s + %1$s, %3$s %2$s, %5$s - %6$s, %8$s %7$s, %10$s + %1$s, %3$s %2$s, %5$s - %6$s, %8$s %7$s, %10$s %3$s %2$s %4$s, %5$s - %8$s %7$s %9$s, %10$s %3$s %2$s %4$s, %5$s - %8$s %7$s %9$s, %10$s %1$s, %3$s %2$s %4$s, %5$s - %6$s, %8$s %7$s %9$s, %10$s %1$s, %3$s %2$s %4$s, %5$s - %6$s, %8$s %7$s %9$s, %10$s %1$s, %3$s %2$s %4$s - %6$s, %8$s %7$s %9$s %3$s-%8$s %2$s - %1$s %3$s %2$s - %6$s %8$s %7$s + %1$s, %3$s %2$s - %6$s, %8$s %7$s %3$s %2$s - %8$s %7$s %9$s %3$s-%8$s %2$s %9$s %1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s diff --git a/core/res/res/values-en-rSG/donottranslate-cldr.xml b/core/res/res/values-en-rSG/donottranslate-cldr.xml deleted file mode 100644 index 286cc0e554f29..0000000000000 --- a/core/res/res/values-en-rSG/donottranslate-cldr.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - January - February - March - April - May - June - July - August - September - October - November - December - - January - February - March - April - May - June - July - August - September - October - November - December - - Jan - Feb - Mar - Apr - May - Jun - Jul - Aug - Sep - Oct - Nov - Dec - - J - F - M - A - M - J - J - A - S - O - N - D - - Sunday - Monday - Tuesday - Wednesday - Thursday - Friday - Saturday - - Sun - Mon - Tue - Wed - Thu - Fri - Sat - - Su - Mo - Tu - We - Th - Fr - Sa - - S - M - T - W - T - F - S - - am - pm - Yesterday - Today - Tomorrow - - %H:%M - %-l:%M%p - %-l:%M%^p - h:mm a - HH:mm - %-m/%-e/%Y - M/d/yyyy - "%s/%s/%s" - %B %-e, %Y - %-l:%M:%S %p - %b %-e, %Y, %-l:%M:%S %p - %1$s, %2$s - %1$s, %3$s - %b %-e, %Y - %B %-e - %-B - %B %Y - %b %-e - %-b - %b %Y - %1$s – %2$s - %2$s – %5$s - %2$s/%3$s – %7$s/%8$s - %1$s, %2$s/%3$s – %6$s, %7$s/%8$s - %2$s/%3$s/%4$s – %7$s/%8$s/%9$s - %1$s, %2$s/%3$s/%4$s – %6$s, %7$s/%8$s/%9$s - %1$s, %2$s/%3$s/%4$s, %5$s – %6$s, %7$s/%8$s/%9$s, %10$s - %2$s/%3$s, %5$s – %7$s/%8$s, %10$s - %1$s, %2$s/%3$s, %5$s – %6$s, %7$s/%8$s, %10$s - %2$s/%3$s/%4$s, %5$s – %7$s/%8$s/%9$s, %10$s - %1$s, %2$s, %3$s – %4$s, %5$s, %6$s - %1$s, %2$s – %4$s, %5$s - %2$s, %3$s – %5$s, %6$s - %1$s, %2$s, %3$s - %2$s, %3$s - %1$s, %2$s - %2$s %3$s – %7$s %8$s - %1$s, %2$s %3$s – %6$s, %7$s %8$s - %2$s %3$s, %5$s – %7$s %8$s, %10$s - %2$s %3$s, %5$s – %7$s %8$s, %10$s - %1$s, %2$s %3$s, %5$s – %6$s, %7$s %8$s, %10$s - %1$s, %2$s %3$s, %5$s – %6$s, %7$s %8$s, %10$s - %2$s %3$s, %4$s, %5$s – %7$s %8$s, %9$s, %10$s - %2$s %3$s, %4$s, %5$s – %7$s %8$s, %9$s, %10$s - %1$s, %2$s %3$s, %4$s, %5$s – %6$s, %7$s %8$s, %9$s, %10$s - %1$s, %2$s %3$s, %4$s, %5$s – %6$s, %7$s %8$s, %9$s, %10$s - %1$s, %2$s %3$s, %4$s – %6$s, %7$s %8$s, %9$s - %2$s %3$s – %8$s - %1$s, %2$s %3$s – %6$s, %7$s %8$s - %2$s %3$s – %7$s %8$s, %9$s - %2$s %3$s – %8$s, %9$s - %1$s, %2$s %3$s – %6$s, %7$s %8$s, %9$s - %b - diff --git a/core/res/res/values-es-rES/donottranslate-cldr.xml b/core/res/res/values-es-rES/donottranslate-cldr.xml deleted file mode 100644 index c1dc58b815d02..0000000000000 --- a/core/res/res/values-es-rES/donottranslate-cldr.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - enero - febrero - marzo - abril - mayo - junio - julio - agosto - septiembre - octubre - noviembre - diciembre - - enero - febrero - marzo - abril - mayo - junio - julio - agosto - septiembre - octubre - noviembre - diciembre - - ene - feb - mar - abr - may - jun - jul - ago - sep - oct - nov - dic - - E - F - M - A - M - J - J - A - S - O - N - D - - domingo - lunes - martes - miércoles - jueves - viernes - sábado - - dom - lun - mar - mié - jue - vie - sáb - - dom - lun - mar - mié - jue - vie - sáb - - D - L - M - M - J - V - S - - a.m. - p.m. - ayer - hoy - mañana - - %-k:%M - %-l:%M %p - %-l:%M %^p - h:mm a - H:mm - %d/%m/%Y - dd/MM/yyyy - "%s/%s/%s" - %-e de %B de %Y - %H:%M:%S - %H:%M:%S %d/%m/%Y - %2$s %1$s - %1$s %3$s - %d/%m/%Y - %-e de %B - %-B - %B de %Y - %-e %b - %-b - %b %Y - %1$s – %2$s - %2$s – %5$s - %3$s/%2$s – %8$s/%7$s - %1$s %3$s/%2$s – %6$s %8$s/%7$s - %3$s/%2$s/%4$s – %8$s/%7$s/%9$s - %1$s %3$s/%2$s/%4$s – %6$s %8$s/%7$s/%9$s - %5$s %1$s %3$s/%2$s/%4$s – %10$s %6$s %8$s/%7$s/%9$s - %5$s %3$s/%2$s – %10$s %8$s/%7$s - %5$s %1$s, %3$s-%2$s – %10$s %6$s, %8$s-%7$s - %5$s %3$s/%2$s/%4$s – %10$s %8$s/%7$s/%9$s - %3$s %1$s %2$s – %6$s %4$s %5$s - %1$s %2$s – %4$s %5$s - %3$s %2$s – %6$s %5$s - %1$s %2$s %3$s - %2$s %3$s - %1$s %2$s - %3$s de %2$s – %8$s de %7$s - %1$s %3$s %2$s – %6$s %8$s %7$s - %5$s %3$s de %2$s – %10$s %8$s de %7$s - %5$s %3$s de %2$s – %10$s %8$s de %7$s - %5$s %1$s %3$s %2$s – %10$s %6$s %8$s %7$s - %5$s %1$s %3$s %2$s – %10$s %6$s %8$s %7$s - %5$s %3$s %2$s %4$s – %10$s %8$s %7$s %9$s - %5$s %3$s %2$s %4$s – %10$s %8$s %7$s %9$s - %5$s %1$s, %3$s %2$s %4$s – %10$s %6$s, %8$s %7$s %9$s - %5$s %1$s, %3$s %2$s %4$s – %10$s %6$s, %8$s %7$s %9$s - %1$s, %3$s %2$s %4$s – %6$s, %8$s %7$s %9$s - %3$s–%8$s %2$s - %1$s %3$s %2$s – %6$s %8$s %7$s - %3$s %2$s – %8$s %7$s %9$s - %3$s–%8$s %2$s %9$s - %1$s %3$s %2$s – %6$s %8$s %7$s %9$s - %b - diff --git a/core/res/res/values-es-rUS/donottranslate-cldr.xml b/core/res/res/values-es-rUS/donottranslate-cldr.xml index d6d89540af918..7ade1428b8f1c 100644 --- a/core/res/res/values-es-rUS/donottranslate-cldr.xml +++ b/core/res/res/values-es-rUS/donottranslate-cldr.xml @@ -27,18 +27,18 @@ noviembre diciembre - ene - feb - mar - abr - may - jun - jul - ago - sep - oct - nov - dic + ene. + feb. + mar. + abr. + may. + jun. + jul. + ago. + sep. + oct. + nov. + dic. E F @@ -61,21 +61,21 @@ viernes sábado - dom - lun - mar - mié - jue - vie - sáb + dom. + lun. + mar. + mié. + jue. + vie. + sáb. - dom - lun - mar - mié - jue - vie - sáb + dom. + lun. + mar. + mié. + jue. + vie. + sáb. D L @@ -85,8 +85,8 @@ V S - a.m. - p.m. + a. m. + p. m. ayer hoy mañana @@ -111,7 +111,7 @@ %-e de %b %b %b de %Y - %1$s a el %2$s + %1$s a %2$s %2$s a el %5$s %2$s/%3$s - %7$s/%8$s %1$s %2$s/%3$s - %6$s %7$s/%8$s diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 6eb1c01a8c6f4..6544d4bf15dbd 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -134,8 +134,6 @@ "No se ha podido acceder al archivo." "No se ha encontrado el archivo solicitado." "Se están procesando demasiadas solicitudes. Vuelve a intentarlo más tarde." - - "Sincronización" "Sincronización" "Demasiadas eliminaciones de %s" diff --git a/core/res/res/values-es/donottranslate-cldr.xml b/core/res/res/values-es/donottranslate-cldr.xml index c1dc58b815d02..0de0b641ac0e3 100644 --- a/core/res/res/values-es/donottranslate-cldr.xml +++ b/core/res/res/values-es/donottranslate-cldr.xml @@ -27,18 +27,18 @@ noviembre diciembre - ene - feb - mar - abr - may - jun - jul - ago - sep - oct - nov - dic + ene. + feb. + mar. + abr. + may. + jun. + jul. + ago. + sep. + oct. + nov. + dic. E F @@ -61,21 +61,21 @@ viernes sábado - dom - lun - mar - mié - jue - vie - sáb + dom. + lun. + mar. + mié. + jue. + vie. + sáb. - dom - lun - mar - mié - jue - vie - sáb + dom. + lun. + mar. + mié. + jue. + vie. + sáb. D L @@ -101,47 +101,47 @@ "%s/%s/%s" %-e de %B de %Y %H:%M:%S - %H:%M:%S %d/%m/%Y - %2$s %1$s - %1$s %3$s + %d/%m/%Y, %H:%M:%S + %1$s, %2$s + %3$s, %1$s %d/%m/%Y %-e de %B %-B %B de %Y - %-e %b + %-e de %b %-b - %b %Y + %b de %Y %1$s – %2$s %2$s – %5$s %3$s/%2$s – %8$s/%7$s %1$s %3$s/%2$s – %6$s %8$s/%7$s %3$s/%2$s/%4$s – %8$s/%7$s/%9$s %1$s %3$s/%2$s/%4$s – %6$s %8$s/%7$s/%9$s - %5$s %1$s %3$s/%2$s/%4$s – %10$s %6$s %8$s/%7$s/%9$s - %5$s %3$s/%2$s – %10$s %8$s/%7$s - %5$s %1$s, %3$s-%2$s – %10$s %6$s, %8$s-%7$s - %5$s %3$s/%2$s/%4$s – %10$s %8$s/%7$s/%9$s - %3$s %1$s %2$s – %6$s %4$s %5$s + %1$s %3$s/%2$s/%4$s, %5$s – %6$s %8$s/%7$s/%9$s, %10$s + %3$s/%2$s, %5$s – %8$s/%7$s, %10$s + %1$s %3$s-%2$s, %5$s – %6$s %8$s-%7$s, %10$s + %3$s/%2$s/%4$s, %5$s – %8$s/%7$s/%9$s, %10$s + %1$s %2$s, %3$s – %4$s %5$s, %6$s %1$s %2$s – %4$s %5$s - %3$s %2$s – %6$s %5$s - %1$s %2$s %3$s + %2$s, %3$s – %5$s, %6$s + %2$s %3$s, %1$s %2$s %3$s - %1$s %2$s + %2$s, %1$s %3$s de %2$s – %8$s de %7$s - %1$s %3$s %2$s – %6$s %8$s %7$s - %5$s %3$s de %2$s – %10$s %8$s de %7$s - %5$s %3$s de %2$s – %10$s %8$s de %7$s - %5$s %1$s %3$s %2$s – %10$s %6$s %8$s %7$s - %5$s %1$s %3$s %2$s – %10$s %6$s %8$s %7$s - %5$s %3$s %2$s %4$s – %10$s %8$s %7$s %9$s - %5$s %3$s %2$s %4$s – %10$s %8$s %7$s %9$s - %5$s %1$s, %3$s %2$s %4$s – %10$s %6$s, %8$s %7$s %9$s - %5$s %1$s, %3$s %2$s %4$s – %10$s %6$s, %8$s %7$s %9$s - %1$s, %3$s %2$s %4$s – %6$s, %8$s %7$s %9$s - %3$s–%8$s %2$s - %1$s %3$s %2$s – %6$s %8$s %7$s - %3$s %2$s – %8$s %7$s %9$s - %3$s–%8$s %2$s %9$s - %1$s %3$s %2$s – %6$s %8$s %7$s %9$s + %1$s %3$s de %2$s – %6$s %8$s de %7$s + %3$s de %2$s, %5$s – %8$s de %7$s, %10$s + %3$s de %2$s, %5$s – %8$s de %7$s, %10$s + %1$s %3$s de %2$s, %5$s – %6$s %8$s de %7$s, %10$s + %1$s %3$s de %2$s, %5$s – %6$s %8$s de %7$s, %10$s + %3$s de %2$s de %4$s, %5$s – %8$s de %7$s de %9$s, %10$s + %3$s de %2$s de %4$s, %5$s – %8$s de %7$s de %9$s, %10$s + %1$s %3$s de %2$s de %4$s, %5$s – %6$s %8$s de %7$s de %9$s, %10$s + %1$s %3$s de %2$s de %4$s, %5$s – %6$s %8$s de %7$s de %9$s, %10$s + %1$s %3$s de %2$s de %4$s – %6$s %8$s de %7$s de %9$s + %3$s–%8$s de %2$s + %1$s %3$s de %2$s – %6$s %8$s de %7$s + %3$s de %2$s – %8$s de %7$s de %9$s + %3$s–%8$s de %2$s de %9$s + %1$s %3$s de %2$s – %6$s %8$s de %7$s de %9$s %b diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 464e1a2bfff21..b0b2d512291c3 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -111,7 +111,6 @@ "No se ha podido acceder al archivo." "No se ha encontrado el archivo solicitado." "Se están procesando demasiadas solicitudes. Vuelve a intentarlo más tarde." - "El certificado se guarda en el almacén de claves del sistema." "Sincronización" "Sincronización" "Demasiadas eliminaciones de %s" diff --git a/core/res/res/values-fi-rFI/donottranslate-cldr.xml b/core/res/res/values-fi-rFI/donottranslate-cldr.xml index df3866e72bdaa..151d9355aa3c3 100644 --- a/core/res/res/values-fi-rFI/donottranslate-cldr.xml +++ b/core/res/res/values-fi-rFI/donottranslate-cldr.xml @@ -53,13 +53,13 @@ M J - sunnuntaina - maanantaina - tiistaina - keskiviikkona - torstaina - perjantaina - lauantaina + sunnuntai + maanantai + tiistai + keskiviikko + torstai + perjantai + lauantai su ma @@ -106,42 +106,42 @@ %1$s %3$s %-e.%-m.%Y %-e. %B - %-b + %-B %-B %Y - %-e. %b + %-e.%-m. %-b - %-b %Y + %-B %Y %1$s–%2$s - %2$s–%5$s + %2$s – %5$s %3$s.%2$s.–%8$s.%7$s. %1$s %3$s.%2$s. – %6$s %8$s.%7$s. %3$s.%2$s.%4$s–%8$s.%7$s.%9$s %1$s %3$s.%2$s.%4$s – %6$s %8$s.%7$s.%9$s - %5$s %1$s %3$s.%2$s.%4$s–%10$s %6$s %8$s.%7$s.%9$s - %5$s %3$s.%2$s.–%10$s %8$s.%7$s. - %5$s %1$s %3$s.%2$s.–%10$s %6$s %8$s.%7$s. - %5$s %3$s.%2$s.%4$s–%10$s %8$s.%7$s.%9$s - %3$s %1$s %2$s–%6$s %4$s %5$s - %1$s %2$s–%4$s %5$s - %3$s %2$s–%6$s %5$s + %5$s %1$s %3$s.%2$s.%4$s – %10$s %6$s %8$s.%7$s.%9$s + %5$s %3$s.%2$s. – %10$s %8$s.%7$s. + %5$s %1$s %3$s.%2$s. – %10$s %6$s %8$s.%7$s. + %5$s %3$s.%2$s.%4$s – %10$s %8$s.%7$s.%9$s + %3$s %1$s %2$s – %6$s %4$s %5$s + %1$s %2$s – %4$s %5$s + %3$s %2$s – %6$s %5$s %1$s %2$s %3$s %2$s %3$s %1$s %2$s - %3$s. %2$s–%8$s. %7$s - %1$s %3$s. %2$s–%6$s %8$s. %7$s - %5$s %3$s. %2$s–%10$s %8$s. %7$s - %5$s %3$s. %2$s–%10$s %8$s. %7$s - %5$s %1$s %3$s. %2$s–%10$s %6$s %8$s. %7$s - %5$s %1$s %3$s. %2$s–%10$s %6$s %8$s. %7$s - %5$s %3$s. %2$s %4$s–%10$s %8$s. %7$s %9$s - %5$s %3$s. %2$s %4$s–%10$s %8$s. %7$s %9$s - %5$s %1$s %3$s. %2$s %4$s–%10$s %6$s %8$s. %7$s %9$s - %5$s %1$s %3$s. %2$s %4$s–%10$s %6$s %8$s. %7$s %9$s - %1$s %3$s. %2$s %4$s–%6$s %8$s. %7$s %9$s - %3$s.–%8$s. %2$s - %1$s %3$s. %2$s–%6$s %8$s. %7$s + %3$s. %2$s – %8$s. %7$s + %1$s %3$s. %2$s – %6$s %8$s. %7$s + %5$s %3$s. %2$s – %10$s %8$s. %7$s + %5$s %3$s. %2$s – %10$s %8$s. %7$s + %5$s %1$s %3$s. %2$s – %10$s %6$s %8$s. %7$s + %5$s %1$s %3$s. %2$s – %10$s %6$s %8$s. %7$s + %5$s %3$s. %2$s %4$s – %10$s %8$s. %7$s %9$s + %5$s %3$s. %2$s %4$s – %10$s %8$s. %7$s %9$s + %5$s %1$s %3$s. %2$s %4$s – %10$s %6$s %8$s. %7$s %9$s + %5$s %1$s %3$s. %2$s %4$s – %10$s %6$s %8$s. %7$s %9$s + %1$s %3$s. %2$s %4$s – %6$s %8$s. %7$s %9$s + %3$s. – %8$s. %2$s + %1$s %3$s. %2$s – %6$s %8$s. %7$s %3$s. %2$s – %8$s. %7$s %9$s - %3$s.–%8$s. %2$s %9$s + %3$s. – %8$s. %2$s %9$s %1$s %3$s. %2$s – %6$s %8$s. %7$s %9$s %b diff --git a/core/res/res/values-fr-rBE/donottranslate-cldr.xml b/core/res/res/values-fr-rBE/donottranslate-cldr.xml deleted file mode 100644 index e1908373a3fe7..0000000000000 --- a/core/res/res/values-fr-rBE/donottranslate-cldr.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - janvier - février - mars - avril - mai - juin - juillet - août - septembre - octobre - novembre - décembre - - janvier - février - mars - avril - mai - juin - juillet - août - septembre - octobre - novembre - décembre - - janv. - févr. - mars - avr. - mai - juin - juil. - août - sept. - oct. - nov. - déc. - - J - F - M - A - M - J - J - A - S - O - N - D - - dimanche - lundi - mardi - mercredi - jeudi - vendredi - samedi - - dim. - lun. - mar. - mer. - jeu. - ven. - sam. - - dim. - lun. - mar. - mer. - jeu. - ven. - sam. - - D - L - M - M - J - V - S - - matin - soir - hier - aujourd’hui - demain - - %-k:%M - %-l:%M %p - %-l:%M %^p - h:mm a - H:mm - %-e/%m/%Y - d/MM/yyyy - "%s/%s/%s" - %-e %B %Y - %H:%M:%S - %H:%M:%S %-e %b %Y - %2$s %1$s - %1$s %3$s - %-e %b %Y - %-e %B - %-B - %B %Y - %-e %b - %b - %b %Y - du %1$s au %2$s - du %2$s au %5$s - %3$s/%2$s - %8$s/%7$s - %1$s %3$s/%2$s - %6$s %8$s/%7$s - %3$s/%2$s/%4$s - %8$s/%7$s/%9$s - %1$s %3$s/%2$s/%4$s - %6$s %8$s/%7$s/%9$s - du %5$s %1$s %3$s/%2$s/%4$s au %10$s %6$s %8$s/%7$s/%9$s - du %5$s %3$s/%2$s au %10$s %8$s/%7$s - du %5$s %1$s %3$s/%2$s au %10$s %6$s %8$s/%7$s - du %5$s %3$s/%2$s/%4$s au %10$s %8$s/%7$s/%9$s - du %3$s %1$s %2$s au %6$s %4$s %5$s - du %1$s %2$s au %4$s %5$s - du %3$s %2$s au %6$s %5$s - %1$s %2$s %3$s - %2$s %3$s - %1$s %2$s - du %3$s %2$s au %8$s %7$s - du %1$s %3$s %2$s au %6$s %8$s %7$s - du %5$s %3$s %2$s au %10$s %8$s %7$s - du %5$s %3$s %2$s au %10$s %8$s %7$s - du %5$s %1$s %3$s %2$s au %10$s %6$s %8$s %7$s - du %5$s %1$s %3$s %2$s au %10$s %6$s %8$s %7$s - du %5$s %3$s %2$s %4$s au %10$s %8$s %7$s %9$s - du %5$s %3$s %2$s %4$s au %10$s %8$s %7$s %9$s - du %5$s %1$s %3$s %2$s %4$s au %10$s %6$s %8$s %7$s %9$s - du %5$s %1$s %3$s %2$s %4$s au %10$s %6$s %8$s %7$s %9$s - du %1$s %3$s %2$s %4$s au %6$s %8$s %7$s %9$s - %3$s-%8$s %2$s - du %1$s %3$s %2$s au %6$s %8$s %7$s - %3$s %2$s au %8$s %7$s %9$s - %3$s-%8$s %2$s %9$s - %1$s %3$s %2$s au %6$s %8$s %7$s %9$s - %b - diff --git a/core/res/res/values-fr-rCA/donottranslate-cldr.xml b/core/res/res/values-fr-rCA/donottranslate-cldr.xml deleted file mode 100644 index 346b971073312..0000000000000 --- a/core/res/res/values-fr-rCA/donottranslate-cldr.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - janvier - février - mars - avril - mai - juin - juillet - août - septembre - octobre - novembre - décembre - - janvier - février - mars - avril - mai - juin - juillet - août - septembre - octobre - novembre - décembre - - janv. - févr. - mars - avr. - mai - juin - juil. - août - sept. - oct. - nov. - déc. - - J - F - M - A - M - J - J - A - S - O - N - D - - dimanche - lundi - mardi - mercredi - jeudi - vendredi - samedi - - dim. - lun. - mar. - mer. - jeu. - ven. - sam. - - dim. - lun. - mar. - mer. - jeu. - ven. - sam. - - D - L - M - M - J - V - S - - matin - soir - hier - aujourd’hui - demain - - %-k:%M - %-l:%M %p - %-l:%M %^p - h:mm a - H:mm - %Y-%m-%d - yyyy-MM-dd - "%s-%s-%s" - %-e %B %Y - %H:%M:%S - %H:%M:%S %Y-%m-%d - %2$s %1$s - %1$s %3$s - %Y-%m-%d - %-e %B - %-B - %B %Y - %-e %b - %-b - %b %Y - %1$s – %2$s - %2$s – %5$s - %2$s-%3$s – %7$s-%8$s - %1$s %2$s-%3$s – %6$s %7$s-%8$s - %4$s-%2$s-%3$s – %9$s-%7$s-%8$s - du %1$s %4$s-%2$s-%3$s au %6$s %9$s-%7$s-%8$s - %5$s %1$s %4$s-%2$s-%3$s – %10$s %6$s %9$s-%7$s-%8$s - %5$s %2$s-%3$s – %10$s %7$s-%8$s - %5$s %1$s %2$s-%3$s – %10$s %6$s %7$s-%8$s - %5$s %4$s-%2$s-%3$s – %10$s %9$s-%7$s-%8$s - %3$s %1$s %2$s – %6$s %4$s %5$s - %1$s %2$s – %4$s %5$s - %3$s %2$s – %6$s %5$s - %1$s %2$s %3$s - %2$s %3$s - %1$s %2$s - %3$s %2$s – %8$s %7$s - %1$s %3$s %2$s – %6$s %8$s %7$s - %5$s %3$s %2$s – %10$s %8$s %7$s - %5$s %3$s %2$s – %10$s %8$s %7$s - %5$s %1$s %3$s %2$s – %10$s %6$s %8$s %7$s - %5$s %1$s %3$s %2$s – %10$s %6$s %8$s %7$s - %5$s %3$s %2$s %4$s – %10$s %8$s %7$s %9$s - %5$s %3$s %2$s %4$s – %10$s %8$s %7$s %9$s - %5$s %1$s %3$s %2$s %4$s – %10$s %6$s %8$s %7$s %9$s - %5$s %1$s %3$s %2$s %4$s – %10$s %6$s %8$s %7$s %9$s - %1$s %3$s %2$s %4$s – %6$s %8$s %7$s %9$s - %3$s–%8$s %2$s - %1$s %3$s %2$s – %6$s %8$s %7$s - du %3$s %2$s au %8$s %7$s %9$s - %3$s–%8$s %2$s %9$s - du %1$s %3$s %2$s au %6$s %8$s %7$s %9$s - %b - diff --git a/core/res/res/values-fr-rCH/donottranslate-cldr.xml b/core/res/res/values-fr-rCH/donottranslate-cldr.xml deleted file mode 100644 index 48db6b8d41692..0000000000000 --- a/core/res/res/values-fr-rCH/donottranslate-cldr.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - janvier - février - mars - avril - mai - juin - juillet - août - septembre - octobre - novembre - décembre - - janvier - février - mars - avril - mai - juin - juillet - août - septembre - octobre - novembre - décembre - - janv. - févr. - mars - avr. - mai - juin - juil. - août - sept. - oct. - nov. - déc. - - J - F - M - A - M - J - J - A - S - O - N - D - - dimanche - lundi - mardi - mercredi - jeudi - vendredi - samedi - - dim. - lun. - mar. - mer. - jeu. - ven. - sam. - - dim. - lun. - mar. - mer. - jeu. - ven. - sam. - - D - L - M - M - J - V - S - - matin - soir - hier - aujourd’hui - demain - - %-k:%M - %-l:%M %p - %-l:%M %^p - h:mm a - H:mm - %d.%m.%Y - dd.MM.yyyy - "%s.%s.%s" - %-e %B %Y - %H:%M:%S - %H:%M:%S %-e %b %Y - %2$s %1$s - %1$s %3$s - %-e %b %Y - %-e %B - %-B - %B %Y - %-e %b - %b - %b %Y - du %1$s au %2$s - du %2$s au %5$s - %3$s.%2$s - %8$s.%7$s - %1$s, %3$s.%2$s - %6$s, %8$s.%7$s - %3$s.%2$s.%4$s - %8$s.%7$s.%9$s - %1$s, %3$s.%2$s.%4$s - %6$s, %8$s.%7$s.%9$s - du %5$s %1$s, %3$s.%2$s.%4$s au %10$s %6$s, %8$s.%7$s.%9$s - du %5$s %3$s.%2$s au %10$s %8$s.%7$s - du %5$s %1$s, %3$s.%2$s au %10$s %6$s, %8$s.%7$s - du %5$s %3$s.%2$s.%4$s au %10$s %8$s.%7$s.%9$s - du %3$s %1$s, %2$s au %6$s %4$s, %5$s - du %1$s, %2$s au %4$s, %5$s - du %3$s %2$s au %6$s %5$s - %1$s %2$s, %3$s - %2$s, %3$s - %1$s %2$s - du %3$s %2$s au %8$s %7$s - du %1$s, %3$s %2$s au %6$s, %8$s %7$s - du %5$s %3$s %2$s au %10$s %8$s %7$s - du %5$s %3$s %2$s au %10$s %8$s %7$s - du %5$s %1$s, %3$s %2$s au %10$s %6$s, %8$s %7$s - du %5$s %1$s, %3$s %2$s au %10$s %6$s, %8$s %7$s - du %5$s %3$s %2$s %4$s au %10$s %8$s %7$s %9$s - du %5$s %3$s %2$s %4$s au %10$s %8$s %7$s %9$s - du %5$s %1$s, %3$s %2$s %4$s au %10$s %6$s, %8$s %7$s %9$s - du %5$s %1$s, %3$s %2$s %4$s au %10$s %6$s, %8$s %7$s %9$s - du %1$s, %3$s %2$s %4$s au %6$s, %8$s %7$s %9$s - %3$s-%8$s %2$s - du %1$s, %3$s %2$s au %6$s, %8$s %7$s - %3$s %2$s au %8$s %7$s %9$s - %3$s-%8$s %2$s %9$s - %1$s, %3$s %2$s au %6$s, %8$s %7$s %9$s - %b - diff --git a/core/res/res/values-fr-rFR/donottranslate-cldr.xml b/core/res/res/values-fr-rFR/donottranslate-cldr.xml deleted file mode 100644 index f340e83841168..0000000000000 --- a/core/res/res/values-fr-rFR/donottranslate-cldr.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - janvier - février - mars - avril - mai - juin - juillet - août - septembre - octobre - novembre - décembre - - janvier - février - mars - avril - mai - juin - juillet - août - septembre - octobre - novembre - décembre - - janv. - févr. - mars - avr. - mai - juin - juil. - août - sept. - oct. - nov. - déc. - - J - F - M - A - M - J - J - A - S - O - N - D - - dimanche - lundi - mardi - mercredi - jeudi - vendredi - samedi - - dim. - lun. - mar. - mer. - jeu. - ven. - sam. - - dim. - lun. - mar. - mer. - jeu. - ven. - sam. - - D - L - M - M - J - V - S - - matin - soir - hier - aujourd’hui - demain - - %-k:%M - %-l:%M %p - %-l:%M %^p - h:mm a - H:mm - %d/%m/%Y - dd/MM/yyyy - "%s/%s/%s" - %-e %B %Y - %H:%M:%S - %H:%M:%S %-e %b %Y - %2$s %1$s - %1$s %3$s - %-e %b %Y - %-e %B - %-B - %B %Y - %-e %b - %-b - %b %Y - %1$s – %2$s - %2$s – %5$s - %3$s/%2$s - %8$s/%7$s - %1$s %3$s/%2$s - %6$s %8$s/%7$s - %3$s/%2$s/%4$s – %8$s/%7$s/%9$s - %1$s %3$s/%2$s/%4$s – %6$s %8$s/%7$s/%9$s - %5$s %1$s %3$s/%2$s/%4$s – %10$s %6$s %8$s/%7$s/%9$s - %5$s %3$s/%2$s – %10$s %8$s/%7$s - %5$s %1$s %3$s/%2$s – %10$s %6$s %8$s/%7$s - %5$s %3$s/%2$s/%4$s – %10$s %8$s/%7$s/%9$s - %3$s %1$s %2$s – %6$s %4$s %5$s - %1$s %2$s – %4$s %5$s - %3$s %2$s – %6$s %5$s - %1$s %2$s %3$s - %2$s %3$s - %1$s %2$s - %3$s %2$s – %8$s %7$s - %1$s %3$s %2$s – %6$s %8$s %7$s - %5$s %3$s %2$s – %10$s %8$s %7$s - %5$s %3$s %2$s – %10$s %8$s %7$s - %5$s %1$s %3$s %2$s – %10$s %6$s %8$s %7$s - %5$s %1$s %3$s %2$s – %10$s %6$s %8$s %7$s - %5$s %3$s %2$s %4$s – %10$s %8$s %7$s %9$s - %5$s %3$s %2$s %4$s – %10$s %8$s %7$s %9$s - %5$s %1$s %3$s %2$s %4$s – %10$s %6$s %8$s %7$s %9$s - %5$s %1$s %3$s %2$s %4$s – %10$s %6$s %8$s %7$s %9$s - %1$s %3$s %2$s %4$s – %6$s %8$s %7$s %9$s - %3$s–%8$s %2$s - %1$s %3$s %2$s – %6$s %8$s %7$s - %3$s %2$s – %8$s %7$s %9$s - %3$s–%8$s %2$s %9$s - %1$s %3$s %2$s – %6$s %8$s %7$s %9$s - %b - diff --git a/core/res/res/values-fr/donottranslate-cldr.xml b/core/res/res/values-fr/donottranslate-cldr.xml index f340e83841168..bf9303932cff2 100644 --- a/core/res/res/values-fr/donottranslate-cldr.xml +++ b/core/res/res/values-fr/donottranslate-cldr.xml @@ -101,9 +101,9 @@ "%s/%s/%s" %-e %B %Y %H:%M:%S - %H:%M:%S %-e %b %Y - %2$s %1$s - %1$s %3$s + %-e %b %Y à %H:%M:%S + %1$s à %2$s + %3$s à %1$s %-e %b %Y %-e %B %-B @@ -111,37 +111,37 @@ %-e %b %-b %b %Y - %1$s – %2$s - %2$s – %5$s - %3$s/%2$s - %8$s/%7$s - %1$s %3$s/%2$s - %6$s %8$s/%7$s - %3$s/%2$s/%4$s – %8$s/%7$s/%9$s - %1$s %3$s/%2$s/%4$s – %6$s %8$s/%7$s/%9$s - %5$s %1$s %3$s/%2$s/%4$s – %10$s %6$s %8$s/%7$s/%9$s - %5$s %3$s/%2$s – %10$s %8$s/%7$s - %5$s %1$s %3$s/%2$s – %10$s %6$s %8$s/%7$s - %5$s %3$s/%2$s/%4$s – %10$s %8$s/%7$s/%9$s - %3$s %1$s %2$s – %6$s %4$s %5$s - %1$s %2$s – %4$s %5$s - %3$s %2$s – %6$s %5$s - %1$s %2$s %3$s + de %1$s à %2$s + du %2$s au %5$s + du %3$s/%2$s au %8$s/%7$s + du %1$s %3$s/%2$s au %6$s %8$s/%7$s + du %3$s/%2$s/%4$s au %8$s/%7$s/%9$s + du %1$s %3$s/%2$s/%4$s au %6$s %8$s/%7$s/%9$s + du %1$s %3$s/%2$s/%4$s à %5$s au %6$s %8$s/%7$s/%9$s à %10$s + du %3$s/%2$s à %5$s au %8$s/%7$s à %10$s + du %1$s %3$s/%2$s à %5$s au %6$s %8$s/%7$s à %10$s + du %3$s/%2$s/%4$s à %5$s au %8$s/%7$s/%9$s à %10$s + du %1$s %2$s à %3$s au %4$s %5$s à %6$s + du %1$s %2$s au %4$s %5$s + du %2$s à %3$s au %5$s à %6$s + %2$s %3$s à %1$s %2$s %3$s - %1$s %2$s - %3$s %2$s – %8$s %7$s - %1$s %3$s %2$s – %6$s %8$s %7$s - %5$s %3$s %2$s – %10$s %8$s %7$s - %5$s %3$s %2$s – %10$s %8$s %7$s - %5$s %1$s %3$s %2$s – %10$s %6$s %8$s %7$s - %5$s %1$s %3$s %2$s – %10$s %6$s %8$s %7$s - %5$s %3$s %2$s %4$s – %10$s %8$s %7$s %9$s - %5$s %3$s %2$s %4$s – %10$s %8$s %7$s %9$s - %5$s %1$s %3$s %2$s %4$s – %10$s %6$s %8$s %7$s %9$s - %5$s %1$s %3$s %2$s %4$s – %10$s %6$s %8$s %7$s %9$s - %1$s %3$s %2$s %4$s – %6$s %8$s %7$s %9$s - %3$s–%8$s %2$s - %1$s %3$s %2$s – %6$s %8$s %7$s - %3$s %2$s – %8$s %7$s %9$s - %3$s–%8$s %2$s %9$s - %1$s %3$s %2$s – %6$s %8$s %7$s %9$s + %2$s à %1$s + du %3$s %2$s au %8$s %7$s + du %1$s %3$s %2$s au %6$s %8$s %7$s + du %3$s %2$s à %5$s au %8$s %7$s à %10$s + du %3$s %2$s à %5$s au %8$s %7$s à %10$s + du %1$s %3$s %2$s à %5$s au %6$s %8$s %7$s à %10$s + du %1$s %3$s %2$s à %5$s au %6$s %8$s %7$s à %10$s + du %3$s %2$s %4$s à %5$s au %8$s %7$s %9$s à %10$s + du %3$s %2$s %4$s à %5$s au %8$s %7$s %9$s à %10$s + du %1$s %3$s %2$s %4$s à %5$s au %6$s %8$s %7$s %9$s à %10$s + du %1$s %3$s %2$s %4$s à %5$s au %6$s %8$s %7$s %9$s à %10$s + du %1$s %3$s %2$s %4$s au %6$s %8$s %7$s %9$s + du %3$s au %8$s %2$s + du %1$s %3$s %2$s au %6$s %8$s %7$s + du %3$s %2$s au %8$s %7$s %9$s + du %3$s au %8$s %2$s %9$s + du %1$s %3$s %2$s au %6$s %8$s %7$s %9$s %b diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 6bd9389af5486..b46ea02d0cac1 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -111,7 +111,6 @@ "Impossible d\'accéder au fichier." "Le fichier demandé est introuvable." "Trop de requêtes sont en cours de traitement. Veuillez réessayer ultérieurement." - "Le certificat est enregistré dans le magasin de clés du système." "Synchroniser" "Synchronisation" "Trop de contenus supprimés (%s)." diff --git a/core/res/res/values-he-rIL/donottranslate-cldr.xml b/core/res/res/values-he-rIL/donottranslate-cldr.xml deleted file mode 100644 index 3378ed7227ad0..0000000000000 --- a/core/res/res/values-he-rIL/donottranslate-cldr.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - ינואר - פברואר - מרס - אפריל - מאי - יוני - יולי - אוגוסט - ספטמבר - אוקטובר - נובמבר - דצמבר - - ינואר - פברואר - מרס - אפריל - מאי - יוני - יולי - אוגוסט - ספטמבר - אוקטובר - נובמבר - דצמבר - - ינו - פבר - מרס - אפר - מאי - יונ - יול - אוג - ספט - אוק - נוב - דצמ - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - - יום ראשון - יום שני - יום שלישי - יום רביעי - יום חמישי - יום שישי - יום שבת - - יום א\' - יום ב\' - יום ג\' - יום ד\' - יום ה\' - יום ו\' - שבת - - יום א\' - יום ב\' - יום ג\' - יום ד\' - יום ה\' - יום ו\' - שבת - - א - ב - ג - ד - ה - ו - ש - - לפנה"צ - אחה"צ - אתמול - היום - מחר - - %-k:%M - %-l:%M %p - %-l:%M %p - h:mm a - H:mm - %d/%m/%Y - dd/MM/yyyy - "%s/%s/%s" - %-e ב%B %Y - %H:%M:%S - %H:%M:%S %-e.%-m.%Y - %2$s %1$s - %1$s %3$s - %-e.%-m.%Y - %-e ב%B - %-B - %B %Y - %b %-e - %-b - %Y %b - %1$s – %2$s - %2$s – %5$s - %3$s/%2$s - %8$s/%7$s - %1$s %3$s/%2$s - %6$s %8$s/%7$s - %3$s/%2$s/%4$s - %8$s/%7$s/%9$s - %1$s %3$s/%2$s/%4$s - %6$s %8$s/%7$s/%9$s - %5$s %1$s, %3$s.%2$s.%4$s – %10$s %6$s, %8$s.%7$s.%9$s - %5$s %3$s/%2$s – %10$s %8$s/%7$s - %5$s %1$s, %2$s-%3$s – %10$s %6$s, %7$s-%8$s - %5$s %3$s/%2$s/%4$s – %10$s %8$s/%7$s/%9$s - %3$s %1$s %2$s – %6$s %4$s %5$s - %1$s %2$s – %4$s %5$s - %3$s %2$s – %6$s %5$s - %1$s %2$s %3$s - %2$s %3$s - %1$s %2$s - %3$s ב%2$s – %8$s ב%7$s - %1$s %3$s %2$s – %6$s %8$s %7$s - %5$s %3$s ב%2$s – %10$s %8$s ב%7$s - %5$s %3$s ב%2$s – %10$s %8$s ב%7$s - %5$s %1$s %3$s %2$s – %10$s %6$s %8$s %7$s - %5$s %1$s %3$s %2$s – %10$s %6$s %8$s %7$s - %5$s %3$s %2$s %4$s – %10$s %8$s %7$s %9$s - %5$s %3$s %2$s %4$s – %10$s %8$s %7$s %9$s - %5$s %1$s, %4$s %2$s %3$s – %10$s %6$s, %9$s %7$s %8$s - %5$s %1$s, %4$s %2$s %3$s – %10$s %6$s, %9$s %7$s %8$s - %1$s, %4$s %2$s %3$s – %6$s, %9$s %7$s %8$s - %3$s-%8$s %2$s - %1$s %3$s %2$s – %6$s %8$s %7$s - %3$s %2$s - %8$s %7$s %9$s - %3$s-%8$s %2$s %9$s - %1$s %3$s %2$s - %6$s %8$s %7$s %9$s - %b - diff --git a/core/res/res/values-hu-rHU/donottranslate-cldr.xml b/core/res/res/values-hu-rHU/donottranslate-cldr.xml index 08a70b81f7b4a..194088999d396 100644 --- a/core/res/res/values-hu-rHU/donottranslate-cldr.xml +++ b/core/res/res/values-hu-rHU/donottranslate-cldr.xml @@ -92,18 +92,18 @@ holnap %H:%M - %-l:%M %p - %-l:%M %^p - h:mm a + %p %-l:%M + %^p %-l:%M + a h:mm HH:mm %Y.%m.%d. yyyy.MM.dd. "%s.%s.%s." %Y. %B %-e. %-k:%M:%S - %-k:%M:%S %Y.%m.%d. - %2$s %1$s - %1$s %3$s + %Y.%m.%d., %-k:%M:%S + %1$s, %2$s + %3$s, %1$s %Y.%m.%d. %B %-e. %-B @@ -117,26 +117,26 @@ %2$s.%3$s., %1$s - %7$s.%8$s., %6$s %4$s.%2$s.%3$s. - %9$s.%7$s.%8$s. %4$s.%2$s.%3$s., %1$s - %9$s.%7$s.%8$s., %6$s - %5$s %4$s.%2$s.%3$s., %1$s - %10$s %9$s.%7$s.%8$s., %6$s - %5$s %2$s. %3$s. - %10$s %7$s. %8$s. - %5$s %2$s. %3$s., %1$s - %10$s %7$s. %8$s., %6$s - %5$s %4$s.%2$s.%3$s. - %10$s %9$s.%7$s.%8$s. - %3$s %2$s, %1$s - %6$s %5$s, %4$s + %4$s.%2$s.%3$s., %1$s, %5$s - %9$s.%7$s.%8$s., %6$s, %10$s + %2$s.%3$s., %5$s - %7$s.%8$s., %10$s + %2$s.%3$s., %1$s, %5$s - %7$s.%8$s., %6$s, %10$s + %4$s.%2$s.%3$s., %5$s - %9$s.%7$s.%8$s., %10$s + %2$s, %1$s, %3$s - %5$s, %4$s, %6$s %2$s, %1$s - %5$s, %4$s - %3$s %2$s - %6$s %5$s - %1$s %3$s, %2$s + %2$s, %3$s - %5$s, %6$s + %3$s, %2$s, %1$s %3$s, %2$s - %1$s %2$s + %2$s, %1$s %2$s %3$s. - %7$s %8$s. %2$s %3$s., %1$s - %7$s %8$s., %6$s - %5$s %2$s %3$s. - %10$s %7$s %8$s. - %5$s %2$s %3$s. - %10$s %7$s %8$s. - %5$s %2$s %3$s., %1$s - %10$s %7$s %8$s., %6$s - %5$s %2$s %3$s., %1$s - %10$s %7$s %8$s., %6$s - %5$s %4$s. %2$s %3$s. - %10$s %9$s. %7$s %8$s. - %5$s %4$s. %2$s %3$s. - %10$s %9$s. %7$s %8$s. - %5$s %4$s. %2$s %3$s., %1$s - %10$s %9$s. %7$s %8$s., %6$s - %5$s %4$s. %2$s %3$s., %1$s - %10$s %9$s. %7$s %8$s., %6$s + %2$s %3$s., %5$s - %7$s %8$s., %10$s + %2$s %3$s., %5$s - %7$s %8$s., %10$s + %2$s %3$s., %1$s, %5$s - %7$s %8$s., %6$s, %10$s + %2$s %3$s., %1$s, %5$s - %7$s %8$s., %6$s, %10$s + %4$s. %2$s %3$s., %5$s - %9$s. %7$s %8$s., %10$s + %4$s. %2$s %3$s., %5$s - %9$s. %7$s %8$s., %10$s + %4$s. %2$s %3$s., %1$s, %5$s - %9$s. %7$s %8$s., %6$s, %10$s + %4$s. %2$s %3$s., %1$s, %5$s - %9$s. %7$s %8$s., %6$s, %10$s %4$s. %2$s %3$s., %1$s - %9$s. %7$s %8$s., %6$s %2$s %3$s-%8$s. %2$s %3$s., %1$s - %7$s %8$s., %6$s diff --git a/core/res/res/values-id-rID/donottranslate-cldr.xml b/core/res/res/values-id-rID/donottranslate-cldr.xml index 6adec84b8ab89..ee3324118f150 100644 --- a/core/res/res/values-id-rID/donottranslate-cldr.xml +++ b/core/res/res/values-id-rID/donottranslate-cldr.xml @@ -99,49 +99,49 @@ %d/%m/%Y dd/MM/yyyy "%s/%s/%s" - %-e %B %Y %H:%M:%S %H:%M:%S %-e %b %Y %2$s %1$s %1$s %3$s %-e %b %Y - %B %-e + %-e %B %-B + %-e %B %Y %B %Y - %b %-e + %-e %b %-b - %Y %b + %b %Y %1$s – %2$s %2$s – %5$s - %2$s-%3$s – %7$s-%8$s - %1$s, %2$s-%3$s – %6$s, %7$s-%8$s - %4$s-%2$s-%3$s – %9$s-%7$s-%8$s - %1$s, %4$s-%2$s-%3$s – %6$s, %9$s-%7$s-%8$s - %5$s %1$s, %4$s-%2$s-%3$s – %10$s %6$s, %9$s-%7$s-%8$s - %5$s %2$s-%3$s – %10$s %7$s-%8$s - %5$s %1$s, %2$s-%3$s – %10$s %6$s, %7$s-%8$s + %3$s-%2$s – %8$s-%7$s + %1$s, %3$s-%2$s – %6$s, %8$s-%7$s + %3$s-%2$s-%4$s – %8$s-%7$s-%9$s + %1$s, %3$s-%2$s-%4$s – %6$s, %8$s-%7$s-%9$s + %5$s %1$s, %3$s-%2$s-%4$s – %10$s %6$s, %8$s-%7$s-%9$s + %5$s %3$s-%2$s – %10$s %8$s-%7$s + %5$s %1$s, %3$s-%2$s – %10$s %6$s, %8$s-%7$s %5$s %3$s/%2$s/%4$s – %10$s %8$s/%7$s/%9$s - %3$s %1$s %2$s – %6$s %4$s %5$s - %1$s %2$s – %4$s %5$s + %3$s %1$s, %2$s – %6$s %4$s, %5$s + %1$s, %2$s – %4$s, %5$s %3$s %2$s – %6$s %5$s - %1$s %2$s %3$s - %2$s %3$s + %1$s %2$s, %3$s + %2$s, %3$s %1$s %2$s - %2$s %3$s – %7$s %8$s - %1$s %2$s %3$s – %6$s %7$s %8$s - %5$s %2$s %3$s – %10$s %7$s %8$s - %5$s %2$s %3$s – %10$s %7$s %8$s - %5$s %1$s %2$s %3$s – %10$s %6$s %7$s %8$s - %5$s %1$s %2$s %3$s – %10$s %6$s %7$s %8$s - %5$s %4$s-%2$s-%3$s – %10$s %9$s-%7$s-%8$s - %5$s %4$s-%2$s-%3$s – %10$s %9$s-%7$s-%8$s - %5$s %1$s, %4$s %2$s %3$s – %10$s %6$s, %9$s %7$s %8$s - %5$s %1$s, %4$s %2$s %3$s – %10$s %6$s, %9$s %7$s %8$s - %1$s, %4$s %2$s %3$s – %6$s, %9$s %7$s %8$s - %2$s-%3$s – %8$s - %1$s %2$s %3$s – %6$s %7$s %8$s - %9$s-%2$s-%3$s – %7$s-%8$s - %9$s-%2$s-%3$s – %8$s - %1$s, %9$s-%2$s-%3$s – %6$s, yyyy-%7$s-%8$s + %3$s %2$s – %8$s %7$s + %1$s, %3$s %2$s – %6$s, %8$s %7$s + %5$s %3$s %2$s – %10$s %8$s %7$s + %5$s %3$s %2$s – %10$s %8$s %7$s + %5$s %1$s, %3$s %2$s – %10$s %6$s, %8$s %7$s + %5$s %1$s, %3$s %2$s – %10$s %6$s, %8$s %7$s + %5$s %3$s %2$s %4$s – %10$s %8$s %7$s %9$s + %5$s %3$s %2$s %4$s – %10$s %8$s %7$s %9$s + %5$s %1$s, %3$s %2$s %4$s – %10$s %6$s, %8$s %7$s %9$s + %5$s %1$s, %3$s %2$s %4$s – %10$s %6$s, %8$s %7$s %9$s + %1$s, %3$s %2$s %4$s – %6$s, %8$s %7$s %9$s + %3$s - %8$s %2$s + %1$s, %3$s %2$s – %6$s, %8$s %7$s + %3$s %2$s - %8$s %7$s %9$s + %3$s - %8$s %2$s %9$s + %1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s %b diff --git a/core/res/res/values-it-rCH/donottranslate-cldr.xml b/core/res/res/values-it-rCH/donottranslate-cldr.xml deleted file mode 100644 index 12170d6c41598..0000000000000 --- a/core/res/res/values-it-rCH/donottranslate-cldr.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - Gennaio - Febbraio - Marzo - Aprile - Maggio - Giugno - Luglio - Agosto - Settembre - Ottobre - Novembre - Dicembre - - gennaio - febbraio - marzo - aprile - maggio - giugno - luglio - agosto - settembre - ottobre - novembre - dicembre - - gen - feb - mar - apr - mag - giu - lug - ago - set - ott - nov - dic - - G - F - M - A - M - G - L - A - S - O - N - D - - domenica - lunedì - martedì - mercoledì - giovedì - venerdì - sabato - - dom - lun - mar - mer - gio - ven - sab - - dom - lun - mar - mer - gio - ven - sab - - D - L - M - M - G - V - S - - m. - p. - ieri - oggi - domani - - %H:%M - %-l:%M %p - %-l:%M %^p - h:mm a - HH:mm - %d.%m.%Y - dd.MM.yyyy - "%s.%s.%s" - %-e %B %Y - %H.%M.%S - %H.%M.%S %-e-%b-%Y - %2$s %1$s - %1$s %3$s - %-e-%b-%Y - %-e %B - %-B - %B %Y - %-e %b - %-b - %b %Y - %1$s - %2$s - %2$s - %5$s - %3$s.%2$s - %8$s.%7$s - %1$s, %3$s.%2$s - %6$s, %8$s.%7$s - %3$s.%2$s.%4$s - %8$s.%7$s.%9$s - %1$s, %3$s.%2$s.%4$s - %6$s, %8$s.%7$s.%9$s - %5$s %1$s, %3$s.%2$s.%4$s - %10$s %6$s, %8$s.%7$s.%9$s - %5$s %3$s.%2$s - %10$s %8$s.%7$s - %5$s %1$s, %3$s.%2$s - %10$s %6$s, %8$s.%7$s - %5$s %3$s.%2$s.%4$s - %10$s %8$s.%7$s.%9$s - %3$s %1$s, %2$s - %6$s %4$s, %5$s - %1$s, %2$s - %4$s, %5$s - %3$s %2$s - %6$s %5$s - %1$s %2$s, %3$s - %2$s, %3$s - %1$s %2$s - %3$s %2$s - %8$s %7$s - %1$s, %3$s %2$s - %6$s, %8$s %7$s - %5$s %3$s %2$s - %10$s %8$s %7$s - %5$s %3$s %2$s - %10$s %8$s %7$s - %5$s %1$s, %3$s %2$s - %10$s %6$s, %8$s %7$s - %5$s %1$s, %3$s %2$s - %10$s %6$s, %8$s %7$s - %5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s - %5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s - %5$s %1$s, %3$s %2$s %4$s - %10$s %6$s, %8$s %7$s %9$s - %5$s %1$s, %3$s %2$s %4$s - %10$s %6$s, %8$s %7$s %9$s - %1$s, %3$s %2$s %4$s - %6$s, %8$s %7$s %9$s - %3$s-%8$s %2$s - %1$s, %3$s %2$s - %6$s, %8$s %7$s - %3$s %2$s - %8$s %7$s %9$s - %3$s-%8$s %2$s %9$s - %1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s - %b - diff --git a/core/res/res/values-it-rIT/donottranslate-cldr.xml b/core/res/res/values-it-rIT/donottranslate-cldr.xml deleted file mode 100644 index 2178bbea2481e..0000000000000 --- a/core/res/res/values-it-rIT/donottranslate-cldr.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - Gennaio - Febbraio - Marzo - Aprile - Maggio - Giugno - Luglio - Agosto - Settembre - Ottobre - Novembre - Dicembre - - gennaio - febbraio - marzo - aprile - maggio - giugno - luglio - agosto - settembre - ottobre - novembre - dicembre - - gen - feb - mar - apr - mag - giu - lug - ago - set - ott - nov - dic - - G - F - M - A - M - G - L - A - S - O - N - D - - domenica - lunedì - martedì - mercoledì - giovedì - venerdì - sabato - - dom - lun - mar - mer - gio - ven - sab - - dom - lun - mar - mer - gio - ven - sab - - D - L - M - M - G - V - S - - m. - p. - ieri - oggi - domani - - %H:%M - %-l:%M %p - %-l:%M %^p - h:mm a - HH:mm - %d/%m/%Y - dd/MM/yyyy - "%s/%s/%s" - %d %B %Y - %H.%M.%S - %H.%M.%S %d/%b/%Y - %2$s %1$s - %1$s %3$s - %d/%b/%Y - %-e %B - %-B - %B %Y - %-e %b - %-b - %b %Y - %1$s - %2$s - %2$s - %5$s - %3$s/%2$s - %8$s/%7$s - %1$s %3$s/%2$s - %6$s %8$s/%7$s - %3$s/%2$s/%4$s - %8$s/%7$s/%9$s - %1$s %3$s/%2$s/%4$s - %6$s %8$s/%7$s/%9$s - %5$s %1$s, %3$s/%2$s/%4$s - %10$s %6$s, %8$s/%7$s/%9$s - %5$s %3$s/%2$s - %10$s %8$s/%7$s - %5$s %1$s %3$s/%2$s - %10$s %6$s %8$s/%7$s - %5$s %3$s/%2$s/%4$s - %10$s %8$s/%7$s/%9$s - %3$s %1$s %2$s - %6$s %4$s %5$s - %1$s %2$s - %4$s %5$s - %3$s %2$s - %6$s %5$s - %1$s %2$s %3$s - %2$s %3$s - %1$s %2$s - %3$s %2$s - %8$s %7$s - %1$s %3$s %2$s - %6$s %8$s %7$s - %5$s %3$s %2$s - %10$s %8$s %7$s - %5$s %3$s %2$s - %10$s %8$s %7$s - %5$s %1$s %3$s %2$s - %10$s %6$s %8$s %7$s - %5$s %1$s %3$s %2$s - %10$s %6$s %8$s %7$s - %5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s - %5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s - %5$s %1$s %3$s %2$s %4$s - %10$s %6$s %8$s %7$s %9$s - %5$s %1$s %3$s %2$s %4$s - %10$s %6$s %8$s %7$s %9$s - %1$s %3$s %2$s %4$s - %6$s %8$s %7$s %9$s - %3$s-%8$s %2$s - %1$s %3$s %2$s - %6$s %8$s %7$s - %3$s %2$s - %8$s %7$s %9$s - %3$s-%8$s %2$s %9$s - %1$s %3$s %2$s - %6$s %8$s %7$s %9$s - %b - diff --git a/core/res/res/values-it/donottranslate-cldr.xml b/core/res/res/values-it/donottranslate-cldr.xml index 2178bbea2481e..5cc697c91629d 100644 --- a/core/res/res/values-it/donottranslate-cldr.xml +++ b/core/res/res/values-it/donottranslate-cldr.xml @@ -1,18 +1,18 @@ - Gennaio - Febbraio - Marzo - Aprile - Maggio - Giugno - Luglio - Agosto - Settembre - Ottobre - Novembre - Dicembre + gennaio + febbraio + marzo + aprile + maggio + giugno + luglio + agosto + settembre + ottobre + novembre + dicembre gennaio febbraio @@ -100,8 +100,8 @@ dd/MM/yyyy "%s/%s/%s" %d %B %Y - %H.%M.%S - %H.%M.%S %d/%b/%Y + %H:%M:%S + %H:%M:%S %d/%b/%Y %2$s %1$s %1$s %3$s %d/%b/%Y diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 1a1845082238f..1b8d504e8a7de 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -111,7 +111,6 @@ "Impossibile accedere al file." "Impossibile trovare il file richiesto." "Troppe richieste in fase di elaborazione. Riprova più tardi." - "Il certificato viene salvato nell\'archivio chiavi del sistema." "Sinc" "Sincronizzazione" "Troppe eliminazioni di %s." diff --git a/core/res/res/values-ja-rJP/donottranslate-cldr.xml b/core/res/res/values-ja-rJP/donottranslate-cldr.xml deleted file mode 100644 index d2510f60132ad..0000000000000 --- a/core/res/res/values-ja-rJP/donottranslate-cldr.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - 1月 - 2月 - 3月 - 4月 - 5月 - 6月 - 7月 - 8月 - 9月 - 10月 - 11月 - 12月 - - 1月 - 2月 - 3月 - 4月 - 5月 - 6月 - 7月 - 8月 - 9月 - 10月 - 11月 - 12月 - - 1月 - 2月 - 3月 - 4月 - 5月 - 6月 - 7月 - 8月 - 9月 - 10月 - 11月 - 12月 - - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - - 日曜日 - 月曜日 - 火曜日 - 水曜日 - 木曜日 - 金曜日 - 土曜日 - - - - - - - - - - - - - - - - - - - - - - - - - - 午前 - 午後 - 昨日 - 今日 - 明日 - - %-k:%M - %p%-l:%M - %p%-l:%M - ah:mm - H:mm - %Y/%m/%d - yyyy/MM/dd - "%s/%s/%s" - %Y年%-m月%-e日 - %-k:%M:%S - %-k:%M:%S %Y/%m/%d - %2$s %1$s - %1$s %3$s - %Y/%m/%d - %-m月%-e日 - %-B - %Y年%-m月 - %-m月%-e日 - %-b - %Y年%-m月 - %1$s~%2$s - %2$s~%5$s - %2$s/%3$s~%7$s/%8$s - %2$s/%3$s(%1$s)~%7$s/%8$s(%6$s) - %4$s/%2$s/%3$s~%9$s/%7$s/%8$s - %4$s/%2$s/%3$s(%1$s)~%9$s/%7$s/%8$s(%6$s) - %5$s %4$s/%2$s/%3$s(%1$s)~%10$s %9$s/%7$s/%8$s(%6$s) - %5$s %2$s/%3$s~%10$s %7$s/%8$s - %5$s %2$s/%3$s(%1$s)~%10$s %7$s/%8$s(%6$s) - %5$s %4$s/%2$s/%3$s~%10$s %9$s/%7$s/%8$s - %3$s %2$s(%1$s)~%6$s %5$s(%4$s) - %2$s(%1$s)~%5$s(%4$s) - %3$s %2$s~%6$s %5$s - %1$s %3$s(%2$s) - %3$s(%2$s) - %1$s %2$s - %2$s%3$s日~%7$s%8$s日 - %2$s%3$s日(%1$s)~%7$s%8$s日(%6$s) - %5$s %2$s%3$s日~%10$s %7$s%8$s日 - %5$s %2$s%3$s日~%10$s %7$s%8$s日 - %5$s %2$s%3$s日(%1$s)~%10$s %7$s%8$s日(%6$s) - %5$s %2$s%3$s日(%1$s)~%10$s %7$s%8$s日(%6$s) - %5$s %4$s年%2$s%3$s日~%10$s %9$s年%7$s%8$s日 - %5$s %4$s年%2$s%3$s日~%10$s %9$s年%7$s%8$s日 - %5$s %4$s年%2$s%3$s日(%1$s)~%10$s %9$s年%7$s%8$s日(%6$s) - %5$s %4$s年%2$s%3$s日(%1$s)~%10$s %9$s年%7$s%8$s日(%6$s) - %4$s年%2$s%3$s日(%1$s)~%9$s年%7$s%8$s日(%6$s) - %2$s%3$s日~%8$s日 - %2$s%3$s日(%1$s)~%7$s%8$s日(%6$s) - %9$s年%2$s%3$s日~%7$s%8$s日 - %9$s年%2$s%3$s日~%8$s日 - %9$s年%2$s%3$s日(%1$s)~%7$s%8$s日(%6$s) - %b - diff --git a/core/res/res/values-ja/donottranslate-cldr.xml b/core/res/res/values-ja/donottranslate-cldr.xml index d2510f60132ad..dab8e2adaa9b9 100644 --- a/core/res/res/values-ja/donottranslate-cldr.xml +++ b/core/res/res/values-ja/donottranslate-cldr.xml @@ -53,13 +53,13 @@ 11 12 - 日曜日 - 月曜日 - 火曜日 - 水曜日 - 木曜日 - 金曜日 - 土曜日 + + + + + + + @@ -85,25 +85,25 @@ - 午前 - 午後 + AM + PM 昨日 今日 明日 %-k:%M - %p%-l:%M - %p%-l:%M - ah:mm + %-l:%M%p + %-l:%M%^p + h:mma H:mm %Y/%m/%d yyyy/MM/dd "%s/%s/%s" %Y年%-m月%-e日 %-k:%M:%S - %-k:%M:%S %Y/%m/%d - %2$s %1$s - %1$s %3$s + %Y/%m/%d %-k:%M:%S + %1$s %2$s + %3$s %1$s %Y/%m/%d %-m月%-e日 %-B @@ -114,34 +114,34 @@ %1$s~%2$s %2$s~%5$s %2$s/%3$s~%7$s/%8$s - %2$s/%3$s(%1$s)~%7$s/%8$s(%6$s) + %2$s/%3$s (%1$s)~%7$s/%8$s (%6$s) %4$s/%2$s/%3$s~%9$s/%7$s/%8$s - %4$s/%2$s/%3$s(%1$s)~%9$s/%7$s/%8$s(%6$s) - %5$s %4$s/%2$s/%3$s(%1$s)~%10$s %9$s/%7$s/%8$s(%6$s) - %5$s %2$s/%3$s~%10$s %7$s/%8$s - %5$s %2$s/%3$s(%1$s)~%10$s %7$s/%8$s(%6$s) - %5$s %4$s/%2$s/%3$s~%10$s %9$s/%7$s/%8$s - %3$s %2$s(%1$s)~%6$s %5$s(%4$s) - %2$s(%1$s)~%5$s(%4$s) - %3$s %2$s~%6$s %5$s - %1$s %3$s(%2$s) - %3$s(%2$s) - %1$s %2$s + %4$s/%2$s/%3$s (%1$s)~%9$s/%7$s/%8$s (%6$s) + %4$s/%2$s/%3$s (%1$s) %5$s~%9$s/%7$s/%8$s (%6$s) %10$s + %2$s/%3$s %5$s~%7$s/%8$s %10$s + %2$s/%3$s (%1$s) %5$s~%7$s/%8$s (%6$s) %10$s + %4$s/%2$s/%3$s %5$s~%9$s/%7$s/%8$s %10$s + %2$s (%1$s) %3$s~%5$s (%4$s) %6$s + %2$s (%1$s)~%5$s (%4$s) + %2$s%3$s~%5$s%6$s + %3$s (%2$s) %1$s + %3$s (%2$s) + %2$s %1$s %2$s%3$s日~%7$s%8$s日 - %2$s%3$s日(%1$s)~%7$s%8$s日(%6$s) - %5$s %2$s%3$s日~%10$s %7$s%8$s日 - %5$s %2$s%3$s日~%10$s %7$s%8$s日 - %5$s %2$s%3$s日(%1$s)~%10$s %7$s%8$s日(%6$s) - %5$s %2$s%3$s日(%1$s)~%10$s %7$s%8$s日(%6$s) - %5$s %4$s年%2$s%3$s日~%10$s %9$s年%7$s%8$s日 - %5$s %4$s年%2$s%3$s日~%10$s %9$s年%7$s%8$s日 - %5$s %4$s年%2$s%3$s日(%1$s)~%10$s %9$s年%7$s%8$s日(%6$s) - %5$s %4$s年%2$s%3$s日(%1$s)~%10$s %9$s年%7$s%8$s日(%6$s) - %4$s年%2$s%3$s日(%1$s)~%9$s年%7$s%8$s日(%6$s) + %2$s%3$s日 (%1$s)~%7$s%8$s日 (%6$s) + %2$s%3$s日%5$s~%7$s%8$s日%10$s + %2$s%3$s日%5$s~%7$s%8$s日%10$s + %2$s%3$s日 (%1$s) %5$s~%7$s%8$s日 (%6$s) %10$s + %2$s%3$s日 (%1$s) %5$s~%7$s%8$s日 (%6$s) %10$s + %4$s年%2$s%3$s日%5$s~%9$s年%7$s%8$s日%10$s + %4$s年%2$s%3$s日%5$s~%9$s年%7$s%8$s日%10$s + %4$s年%2$s%3$s日 (%1$s) %5$s~%9$s年%7$s%8$s日 (%6$s) %10$s + %4$s年%2$s%3$s日 (%1$s) %5$s~%9$s年%7$s%8$s日 (%6$s) %10$s + %4$s年%2$s%3$s日 (%1$s)~%9$s年%7$s%8$s日 (%6$s) %2$s%3$s日~%8$s日 - %2$s%3$s日(%1$s)~%7$s%8$s日(%6$s) + %2$s%3$s日 (%1$s)~%7$s%8$s日 (%6$s) %9$s年%2$s%3$s日~%7$s%8$s日 %9$s年%2$s%3$s日~%8$s日 - %9$s年%2$s%3$s日(%1$s)~%7$s%8$s日(%6$s) + %9$s年%2$s%3$s日 (%1$s)~%7$s%8$s日 (%6$s) %b diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 618d16b9db5c5..6a659ee0ccfdd 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -134,8 +134,6 @@ "ファイルにアクセスできませんでした。" "要求されたファイルが見つかりませんでした。" "処理中のリクエストが多すぎます。しばらくしてからもう一度試してください。" - - "同期" "同期" "%sでの削除が多すぎます。" diff --git a/core/res/res/values-ko-rKR/donottranslate-cldr.xml b/core/res/res/values-ko-rKR/donottranslate-cldr.xml deleted file mode 100644 index 57cd35692e36d..0000000000000 --- a/core/res/res/values-ko-rKR/donottranslate-cldr.xml +++ /dev/null @@ -1,135 +0,0 @@ - - - 1월 - 2월 - 3월 - 4월 - 5월 - 6월 - 7월 - 8월 - 9월 - 10월 - 11월 - 12월 - - 1월 - 2월 - 3월 - 4월 - 5월 - 6월 - 7월 - 8월 - 9월 - 10월 - 11월 - 12월 - - - 1월 - 2월 - 3월 - 4월 - 5월 - 6월 - 7월 - 8월 - 9월 - 10월 - 11월 - 12월 - - 일요일 - 월요일 - 화요일 - 수요일 - 목요일 - 금요일 - 토요일 - - - - - - - - - - - - - - - - - - - - - - - - - - 오전 - 오후 - 어제 - 오늘 - 내일 - - %-k:%M - %-l:%M %p - %-l:%M %p - h:mm a - H:mm - %Y. %-m. %-e. - yyyy. M. d. - "%s. %s. %s." - %Y년 %-m월 %-e일 - %p %-l:%M:%S - %p %-l:%M:%S %Y. %-m. %-e. - %2$s %1$s - %1$s %3$s - %Y. %-m. %-e. - %B %-e일 - %-B - %Y년 %B - %b %-e일 - %-b - %Y년 %b - %1$s – %2$s - %2$s – %5$s - %2$s. %3$s ~ %7$s. %8$s - %2$s. %3$s %1$s ~ %7$s. %8$s %6$s - %4$s. %2$s. %3$s. ~ %9$s. %7$s. %8$s. - %4$s. %2$s. %3$s. %1$s ~ %9$s. %7$s. %8$s. %6$s - %5$s %4$s. %2$s. %3$s. %1$s – %10$s %9$s. %7$s. %8$s. %6$s - %5$s %2$s. %3$s. – %10$s %7$s. %8$s. - %5$s %2$s. %3$s. (%1$s) – %10$s %7$s. %8$s. (%6$s) - %5$s %4$s. %2$s. %3$s. – %10$s %9$s. %7$s. %8$s. - %3$s %2$s (%1$s) – %6$s %5$s (%4$s) - %2$s (%1$s) – %5$s (%4$s) - %3$s %2$s – %6$s %5$s - %1$s %3$s (%2$s) - %3$s (%2$s) - %1$s %2$s - %2$s %3$s일 – %7$s %8$s일 - %2$s %3$s일 (%1$s) – %7$s %8$s일 (%6$s) - %5$s %2$s %3$s일 – %10$s %7$s %8$s일 - %5$s %2$s %3$s일 – %10$s %7$s %8$s일 - %5$s %2$s %3$s일 (%1$s) – %10$s %7$s %8$s일 (%6$s) - %5$s %2$s %3$s일 (%1$s) – %10$s %7$s %8$s일 (%6$s) - %5$s %4$s년 %2$s %3$s일 – %10$s %9$s년 %7$s %8$s일 - %5$s %4$s년 %2$s %3$s일 – %10$s %9$s년 %7$s %8$s일 - %5$s %4$s년 %2$s %3$s일 %1$s – %10$s %9$s년 %7$s %8$s일 %6$s - %5$s %4$s년 %2$s %3$s일 %1$s – %10$s %9$s년 %7$s %8$s일 %6$s - %4$s년 %2$s %3$s일 %1$s – %9$s년 %7$s %8$s일 %6$s - %2$s %3$s일 ~ %8$s일 - %2$s %3$s일 (%1$s) – %7$s %8$s일 (%6$s) - %9$s년 %2$s %3$s일 ~ %7$s %8$s일 - %9$s년 %2$s %3$s일~%8$s일 - %9$s년 %2$s %3$s일 %1$s ~ %7$s %8$s일 %6$s - %b - diff --git a/core/res/res/values-ko/donottranslate-cldr.xml b/core/res/res/values-ko/donottranslate-cldr.xml index 57cd35692e36d..47f8c0331b2a1 100644 --- a/core/res/res/values-ko/donottranslate-cldr.xml +++ b/core/res/res/values-ko/donottranslate-cldr.xml @@ -27,6 +27,18 @@ 11월 12월 + 1월 + 2월 + 3월 + 4월 + 5월 + 6월 + 7월 + 8월 + 9월 + 10월 + 11월 + 12월 1월 2월 @@ -80,56 +92,56 @@ 내일 %-k:%M - %-l:%M %p - %-l:%M %p - h:mm a + %p %-l:%M + %p %-l:%M + a h:mm H:mm %Y. %-m. %-e. yyyy. M. d. "%s. %s. %s." %Y년 %-m월 %-e일 %p %-l:%M:%S - %p %-l:%M:%S %Y. %-m. %-e. - %2$s %1$s - %1$s %3$s + %Y. %-m. %-e. %p %-l:%M:%S + %1$s %2$s + %3$s %1$s %Y. %-m. %-e. %B %-e일 %-B %Y년 %B - %b %-e일 - %-b - %Y년 %b - %1$s – %2$s - %2$s – %5$s + %-m. %-e. + %-m월 + %Y. %-m. + %1$s ~ %2$s + %2$s ~ %5$s %2$s. %3$s ~ %7$s. %8$s %2$s. %3$s %1$s ~ %7$s. %8$s %6$s %4$s. %2$s. %3$s. ~ %9$s. %7$s. %8$s. %4$s. %2$s. %3$s. %1$s ~ %9$s. %7$s. %8$s. %6$s - %5$s %4$s. %2$s. %3$s. %1$s – %10$s %9$s. %7$s. %8$s. %6$s - %5$s %2$s. %3$s. – %10$s %7$s. %8$s. - %5$s %2$s. %3$s. (%1$s) – %10$s %7$s. %8$s. (%6$s) - %5$s %4$s. %2$s. %3$s. – %10$s %9$s. %7$s. %8$s. - %3$s %2$s (%1$s) – %6$s %5$s (%4$s) - %2$s (%1$s) – %5$s (%4$s) - %3$s %2$s – %6$s %5$s - %1$s %3$s (%2$s) - %3$s (%2$s) - %1$s %2$s - %2$s %3$s일 – %7$s %8$s일 - %2$s %3$s일 (%1$s) – %7$s %8$s일 (%6$s) - %5$s %2$s %3$s일 – %10$s %7$s %8$s일 - %5$s %2$s %3$s일 – %10$s %7$s %8$s일 - %5$s %2$s %3$s일 (%1$s) – %10$s %7$s %8$s일 (%6$s) - %5$s %2$s %3$s일 (%1$s) – %10$s %7$s %8$s일 (%6$s) - %5$s %4$s년 %2$s %3$s일 – %10$s %9$s년 %7$s %8$s일 - %5$s %4$s년 %2$s %3$s일 – %10$s %9$s년 %7$s %8$s일 - %5$s %4$s년 %2$s %3$s일 %1$s – %10$s %9$s년 %7$s %8$s일 %6$s - %5$s %4$s년 %2$s %3$s일 %1$s – %10$s %9$s년 %7$s %8$s일 %6$s - %4$s년 %2$s %3$s일 %1$s – %9$s년 %7$s %8$s일 %6$s + %4$s. %2$s. %3$s. %1$s %5$s ~ %9$s. %7$s. %8$s. %6$s %10$s + %2$s. %3$s. %5$s ~ %7$s. %8$s. %10$s + %2$s. %3$s. %1$s %5$s ~ %7$s. %8$s. %6$s %10$s + %4$s. %2$s. %3$s. %5$s ~ %9$s. %7$s. %8$s. %10$s + %2$s %1$s %3$s ~ %5$s %4$s %6$s + %2$s %1$s ~ %5$s %4$s + %2$s %3$s ~ %5$s %6$s + %3$s %2$s %1$s + %3$s %2$s + %2$s %1$s + %2$s %3$s일 ~ %7$s %8$s일 + %2$s %3$s일 %1$s ~ %7$s %8$s일 %6$s + %2$s %3$s일 %5$s ~ %7$s %8$s일 %10$s + %2$s %3$s일 %5$s ~ %7$s %8$s일 %10$s + %2$s %3$s일 %1$s %5$s ~ %7$s %8$s일 %6$s %10$s + %2$s %3$s일 %1$s %5$s ~ %7$s %8$s일 %6$s %10$s + %4$s년 %2$s %3$s일 %5$s ~ %9$s년 %7$s %8$s일 %10$s + %4$s년 %2$s %3$s일 %5$s ~ %9$s년 %7$s %8$s일 %10$s + %4$s년 %2$s %3$s일 %1$s %5$s ~ %9$s년 %7$s %8$s일 %6$s %10$s + %4$s년 %2$s %3$s일 %1$s %5$s ~ %9$s년 %7$s %8$s일 %6$s %10$s + %4$s년 %2$s %3$s일 %1$s ~ %9$s년 %7$s %8$s일 %6$s %2$s %3$s일 ~ %8$s일 - %2$s %3$s일 (%1$s) – %7$s %8$s일 (%6$s) + %2$s %3$s일 %1$s ~ %7$s %8$s일 %6$s %9$s년 %2$s %3$s일 ~ %7$s %8$s일 - %9$s년 %2$s %3$s일~%8$s일 + %9$s년 %2$s %3$s일 ~ %8$s일 %9$s년 %2$s %3$s일 %1$s ~ %7$s %8$s일 %6$s %b diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index d60ebaa1cc33f..34b19b69c85cd 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -134,8 +134,6 @@ "파일에 액세스할 수 없습니다." "요청한 파일을 찾을 수 없습니다." "처리 중인 요청이 너무 많습니다. 잠시 후에 다시 시도해 주세요." - - "동기화" "동기화" "%s 삭제가 너무 많습니다." diff --git a/core/res/res/values-lt-rLT/donottranslate-cldr.xml b/core/res/res/values-lt-rLT/donottranslate-cldr.xml index 20d58e05fea59..ad410e7d7568e 100644 --- a/core/res/res/values-lt-rLT/donottranslate-cldr.xml +++ b/core/res/res/values-lt-rLT/donottranslate-cldr.xml @@ -27,18 +27,18 @@ lapkričio gruodžio - Sau - Vas - Kov - Bal - Geg - Bir - Lie - Rgp - Rgs - Spl - Lap - Grd + sau. + vas. + kov. + bal. + geg. + bir. + lie. + rgp. + rgs. + spl. + lap. + grd. S V @@ -101,47 +101,47 @@ "%s-%s-%s" %Y m. %B %-e d. %H:%M:%S - %H:%M:%S %Y.%m.%d - %2$s %1$s - %1$s %3$s - %Y.%m.%d - %B %-e - %-B - %Y %B + %H:%M:%S, %Y-%m-%d + %2$s, %1$s + %1$s, %3$s + %Y-%m-%d + %B %-e d. + %B mėn. + %Y m. %B mėn. %b %-e d. - %b - %Y m. %b - %1$s - %2$s - %2$s - %5$s - %2$s-%3$s - %7$s-%8$s - %2$s-%3$s%1$s - %7$s-%8$s%6$s - %4$s-%2$s-%3$s - %9$s-%7$s-%8$s - %4$s-%2$s-%3$s%1$s - %9$s-%7$s-%8$s%6$s - %5$s %4$s-%2$s-%3$s%1$s - %10$s %9$s-%7$s-%8$s%6$s - %5$s %2$s-%3$s - %10$s %7$s-%8$s - %5$s %2$s-%3$s%1$s - %10$s %7$s-%8$s%6$s - %5$s %4$s-%2$s-%3$s - %10$s %9$s-%7$s-%8$s - %3$s %2$s%1$s - %6$s %5$s%4$s - %2$s%1$s - %5$s%4$s - %3$s %2$s - %6$s %5$s - %1$s %3$s%2$s - %3$s%2$s - %1$s %2$s - %2$s %3$s - %7$s %8$s - %2$s %3$s d.%1$s - %7$s %8$s d.%6$s - %5$s %2$s %3$s - %10$s %7$s %8$s - %5$s %2$s %3$s - %10$s %7$s %8$s - %5$s %2$s %3$s d.%1$s - %10$s %7$s %8$s d.%6$s - %5$s %2$s %3$s d.%1$s - %10$s %7$s %8$s d.%6$s - %5$s %4$s m. %2$s %3$s d. - %10$s %9$s m. %7$s %8$s d. - %5$s %4$s m. %2$s %3$s d. - %10$s %9$s m. %7$s %8$s d. - %5$s %4$s m. %2$s %3$s d.,%1$s - %10$s %9$s m. %7$s %8$s d.,%6$s - %5$s %4$s m. %2$s %3$s d.,%1$s - %10$s %9$s m. %7$s %8$s d.,%6$s - %4$s m. %2$s %3$s d.,%1$s - %9$s m. %7$s %8$s d.,%6$s - %2$s %3$s d.-%8$s d. - %2$s %3$s d.%1$s - %7$s %8$s d.%6$s - %9$s m. %2$s %3$s d. - %7$s %8$s d. - %9$s m. %2$s %3$s d.-%8$s d. - %9$s m. %2$s %3$s d.,%1$s - %7$s %8$s d.,%6$s + %b mėn. + %Y m. %b mėn. + %1$s-%2$s + %2$s-%5$s + %2$s-%3$s-%7$s-%8$s + %2$s-%3$s, %1$s-%7$s-%8$s, %6$s + %4$s-%2$s-%3$s-%9$s-%7$s-%8$s + %4$s-%2$s-%3$s, %1$s-%9$s-%7$s-%8$s, %6$s + %5$s, %4$s-%2$s-%3$s, %1$s-%10$s, %9$s-%7$s-%8$s, %6$s + %5$s, %2$s-%3$s-%10$s, %7$s-%8$s + %5$s, %2$s-%3$s, %1$s-%10$s, %7$s-%8$s, %6$s + %5$s, %4$s-%2$s-%3$s-%10$s, %9$s-%7$s-%8$s + %3$s, %2$s, %1$s-%6$s, %5$s, %4$s + %2$s, %1$s-%5$s, %4$s + %3$s, %2$s-%6$s, %5$s + %1$s, %3$s, %2$s + %3$s, %2$s + %1$s, %2$s + %2$s %3$s d.-%7$s %8$s d. + %2$s %3$s d., %1$s-%7$s %8$s d., %6$s + %5$s, %2$s %3$s d.-%10$s, %7$s %8$s d. + %5$s, %2$s %3$s d.-%10$s, %7$s %8$s d. + %5$s, %2$s %3$s d., %1$s-%10$s, %7$s %8$s d., %6$s + %5$s, %2$s %3$s d., %1$s-%10$s, %7$s %8$s d., %6$s + %5$s, %4$s m. %2$s %3$s d.-%10$s, %9$s m. %7$s %8$s d. + %5$s, %4$s m. %2$s %3$s d.-%10$s, %9$s m. %7$s %8$s d. + %5$s, %4$s m. %2$s %3$s d., %1$s-%10$s, %9$s m. %7$s %8$s d., %6$s + %5$s, %4$s m. %2$s %3$s d., %1$s-%10$s, %9$s m. %7$s %8$s d., %6$s + %4$s m. %2$s %3$s d., %1$s-%9$s m. %7$s %8$s d., %6$s + %2$s %3$s-%8$s d. + %2$s %3$s d., %1$s-%7$s %8$s d., %6$s + %9$s m. %2$s %3$s d.-%7$s %8$s d. + %9$s m. %2$s %3$s-%8$s d. + %9$s m. %2$s %3$s d., %1$s-%7$s %8$s d., %6$s %b diff --git a/core/res/res/values-lv-rLV/donottranslate-cldr.xml b/core/res/res/values-lv-rLV/donottranslate-cldr.xml index 3dec1d2e37264..2c6765ac9a954 100644 --- a/core/res/res/values-lv-rLV/donottranslate-cldr.xml +++ b/core/res/res/values-lv-rLV/donottranslate-cldr.xml @@ -101,9 +101,9 @@ "%s.%s.%s" %Y. gada %-e. %B %H:%M:%S - %H:%M:%S %Y. gada %-e. %b - %2$s %1$s - %1$s %3$s + %Y. gada %-e. %b, %H:%M:%S + %1$s, %2$s + %3$s, %1$s %Y. gada %-e. %b %-e. %B %-B @@ -111,37 +111,37 @@ %-e. %b %-b %Y. g. %b - %1$s - %2$s - %2$s - %5$s - %3$s.%2$s–%8$s.%7$s - %1$s, %3$s.%2$s - %6$s, %8$s.%7$s + %1$s-%2$s + %2$s-%5$s + %3$s.%2$s.–%8$s.%7$s. + %1$s, %3$s.%2$s.-%6$s, %8$s.%7$s. %3$s.%2$s.%4$s.–%8$s.%7$s.%9$s. - %1$s, %3$s.%2$s.%4$s. – %6$s, %8$s.%7$s.%9$s. - %5$s %1$s, %3$s.%2$s.%4$s. - %10$s %6$s, %8$s.%7$s.%9$s. - %5$s %3$s.%2$s. - %10$s %8$s.%7$s. - %5$s %1$s, %3$s.%2$s. - %10$s %6$s, %8$s.%7$s. - %5$s %3$s.%2$s.%4$s - %10$s %8$s.%7$s.%9$s - %3$s %1$s, %2$s - %6$s %4$s, %5$s - %1$s, %2$s - %4$s, %5$s - %3$s %2$s - %6$s %5$s - %1$s %2$s, %3$s + %1$s, %3$s.%2$s.%4$s.–%6$s, %8$s.%7$s.%9$s. + %1$s, %3$s.%2$s.%4$s., %5$s-%6$s, %8$s.%7$s.%9$s., %10$s + %3$s.%2$s., %5$s-%8$s.%7$s., %10$s + %1$s, %3$s.%2$s., %5$s-%6$s, %8$s.%7$s., %10$s + %3$s.%2$s.%4$s, %5$s-%8$s.%7$s.%9$s, %10$s + %1$s, %2$s, %3$s-%4$s, %5$s, %6$s + %1$s, %2$s-%4$s, %5$s + %2$s, %3$s-%5$s, %6$s + %2$s, %3$s, %1$s %2$s, %3$s - %1$s %2$s - %3$s. %2$s - %8$s. %7$s - %1$s, %3$s. %2$s - %6$s, %8$s. %7$s - %5$s %3$s. %2$s - %10$s %8$s. %7$s - %5$s %3$s. %2$s - %10$s %8$s. %7$s - %5$s %1$s, %3$s. %2$s - %10$s %6$s, %8$s. %7$s - %5$s %1$s, %3$s. %2$s - %10$s %6$s, %8$s. %7$s - %5$s %4$s. gada %3$s. %2$s - %10$s %9$s. gada %8$s. %7$s - %5$s %4$s. gada %3$s. %2$s - %10$s %9$s. gada %8$s. %7$s - %5$s %1$s, %4$s. g. %3$s. %2$s - %10$s %6$s, %9$s. g. %8$s. %7$s - %5$s %1$s, %4$s. g. %3$s. %2$s - %10$s %6$s, %9$s. g. %8$s. %7$s - %1$s, %4$s. g. %3$s. %2$s - %6$s, %9$s. g. %8$s. %7$s + %2$s, %1$s + %3$s. %2$s-%8$s. %7$s + %1$s, %3$s. %2$s-%6$s, %8$s. %7$s + %3$s. %2$s, %5$s-%8$s. %7$s, %10$s + %3$s. %2$s, %5$s-%8$s. %7$s, %10$s + %1$s, %3$s. %2$s, %5$s-%6$s, %8$s. %7$s, %10$s + %1$s, %3$s. %2$s, %5$s-%6$s, %8$s. %7$s, %10$s + %4$s. gada %3$s. %2$s, %5$s-%9$s. gada %8$s. %7$s, %10$s + %4$s. gada %3$s. %2$s, %5$s-%9$s. gada %8$s. %7$s, %10$s + %1$s, %4$s. g. %3$s. %2$s, %5$s-%6$s, %9$s. g. %8$s. %7$s, %10$s + %1$s, %4$s. g. %3$s. %2$s, %5$s-%6$s, %9$s. g. %8$s. %7$s, %10$s + %1$s, %4$s. g. %3$s. %2$s-%6$s, %9$s. g. %8$s. %7$s %3$s.-%8$s. %2$s - %1$s, %3$s. %2$s - %6$s, %8$s. %7$s - %9$s. gada %3$s. %2$s - %8$s. %7$s + %1$s, %3$s. %2$s-%6$s, %8$s. %7$s + %9$s. gada %3$s. %2$s-%8$s. %7$s %9$s. gada %3$s.-%8$s. %2$s - %1$s, %9$s. gada %3$s. %2$s - %6$s, y. gada %8$s. %7$s + %1$s, %9$s. gada %3$s. %2$s-%6$s, y. gada %8$s. %7$s %b diff --git a/core/res/res/values-nb-rNO/donottranslate-cldr.xml b/core/res/res/values-nb-rNO/donottranslate-cldr.xml deleted file mode 100644 index ecf01118298f4..0000000000000 --- a/core/res/res/values-nb-rNO/donottranslate-cldr.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - januar - februar - mars - april - mai - juni - juli - august - september - oktober - november - desember - - januar - februar - mars - april - mai - juni - juli - august - september - oktober - november - desember - - jan. - feb. - mars - apr. - mai - juni - juli - aug. - sep. - okt. - nov. - des. - - J - F - M - A - M - J - J - A - S - O - N - D - - søndag - mandag - tirsdag - onsdag - torsdag - fredag - lørdag - - søn. - man. - tir. - ons. - tor. - fre. - lør. - - søn. - man. - tir. - ons. - tor. - fre. - lør. - - S - M - T - O - T - F - L - - AM - PM - i går - i dag - i morgen - - %H.%M - %-l.%M %p - %-l.%M %^p - h.mm a - HH.mm - %d.%m.%Y - dd.MM.yyyy - "%s.%s.%s" - %-e. %B %Y - %H.%M.%S - %H.%M.%S %-e. %b %Y - %2$s %1$s - %1$s %3$s - %-e. %b %Y - %-e. %B - %-B - %B %Y - %-e. %b - %-b - %b %Y - %1$s–%2$s - %2$s–%5$s - %3$s.%2$s.–%8$s.%7$s. - %1$s %3$s.%2$s.–%6$s %8$s.%7$s. - %3$s.%2$s.%4$s–%8$s.%7$s.%9$s - %1$s %3$s.%2$s.%4$s–%6$s %8$s.%7$s.%9$s - %5$s %1$s %3$s.%2$s.%4$s–%10$s %6$s %8$s.%7$s.%9$s - %5$s %3$s.%2$s.–%10$s %8$s.%7$s. - %5$s %1$s %3$s.%2$s–%10$s %6$s %8$s.%7$s - %5$s %3$s.%2$s.%4$s–%10$s %8$s.%7$s.%9$s - %3$s %1$s %2$s–%6$s %4$s %5$s - %1$s %2$s–%4$s %5$s - %3$s %2$s–%6$s %5$s - %1$s %2$s %3$s - %2$s %3$s - %1$s %2$s - %3$s. %2$s–%8$s. %7$s - %1$s %3$s. %2$s–%6$s %8$s. %7$s - %5$s %3$s. %2$s–%10$s %8$s. %7$s - %5$s %3$s. %2$s–%10$s %8$s. %7$s - %5$s %1$s %3$s. %2$s–%10$s %6$s %8$s. %7$s - %5$s %1$s %3$s. %2$s–%10$s %6$s %8$s. %7$s - %5$s %3$s. %2$s %4$s–%10$s %8$s. %7$s %9$s - %5$s %3$s. %2$s %4$s–%10$s %8$s. %7$s %9$s - %5$s %1$s %3$s. %2$s %4$s–%10$s %6$s %8$s. %7$s %9$s - %5$s %1$s %3$s. %2$s %4$s–%10$s %6$s %8$s. %7$s %9$s - %1$s %3$s. %2$s %4$s–%6$s %8$s. %7$s %9$s - %3$s.–%8$s. %2$s - %1$s %3$s. %2$s–%6$s %8$s. %7$s - %3$s. %2$s–%8$s. %7$s %9$s - %3$s.–%8$s. %2$s %9$s - %1$s %3$s. %2$s–%6$s %8$s. %7$s %9$s - %b - diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index 875b4bcd1e625..dff943ccf13b9 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -134,8 +134,6 @@ "Kunne ikke åpne filen." "Fant ikke den forespurte filen." "For mange forespørsler blir behandlet. Prøv igjen senere." - - "Synkronisering" "Synkronisering" "For mange slettinger av %s." diff --git a/core/res/res/values-nl-rBE/donottranslate-cldr.xml b/core/res/res/values-nl-rBE/donottranslate-cldr.xml deleted file mode 100644 index 680a392863573..0000000000000 --- a/core/res/res/values-nl-rBE/donottranslate-cldr.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - januari - februari - maart - april - mei - juni - juli - augustus - september - oktober - november - december - - januari - februari - maart - april - mei - juni - juli - augustus - september - oktober - november - december - - jan. - feb. - mrt. - apr. - mei - jun. - jul. - aug. - sep. - okt. - nov. - dec. - - J - F - M - A - M - J - J - A - S - O - N - D - - zondag - maandag - dinsdag - woensdag - donderdag - vrijdag - zaterdag - - zo - ma - di - wo - do - vr - za - - zo - ma - di - wo - do - vr - za - - Z - M - D - W - D - V - Z - - AM - PM - Gisteren - Vandaag - Morgen - - %H:%M - %-l:%M %p - %-l:%M %^p - h:mm a - HH:mm - %-e/%m/%Y - d/MM/yyyy - "%s/%s/%s" - %-e %B %Y - %H:%M:%S - %H:%M:%S %-e-%b-%Y - %2$s %1$s - %1$s %3$s - %-e-%b-%Y - %-e %B - %-B - %B %Y - %-e-%b - %-b - %b %Y - %1$s - %2$s - %2$s - %5$s - %3$s/%2$s - %8$s/%7$s - %1$s %3$s/%2$s - %6$s %8$s/%7$s - %3$s/%2$s/%4$s - %8$s/%7$s/%9$s - %1$s %3$s/%2$s/%4$s - %6$s %8$s/%7$s/%9$s - %5$s %1$s %3$s/%2$s/%4$s - %10$s %6$s %8$s/%7$s/%9$s - %5$s %3$s/%2$s - %10$s %8$s/%7$s - %5$s %1$s %3$s/%2$s - %10$s %6$s %8$s/%7$s - %5$s %3$s/%2$s/%4$s - %10$s %8$s/%7$s/%9$s - %3$s %1$s %2$s - %6$s %4$s %5$s - %1$s %2$s - %4$s %5$s - %3$s %2$s - %6$s %5$s - %1$s %2$s %3$s - %2$s %3$s - %1$s %2$s - %3$s %2$s - %8$s %7$s - %1$s %3$s %2$s - %6$s %8$s %7$s - %5$s %3$s %2$s - %10$s %8$s %7$s - %5$s %3$s %2$s - %10$s %8$s %7$s - %5$s %1$s %3$s %2$s - %10$s %6$s %8$s %7$s - %5$s %1$s %3$s %2$s - %10$s %6$s %8$s %7$s - %5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s - %5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s - %5$s %1$s %3$s %2$s %4$s - %10$s %6$s %8$s %7$s %9$s - %5$s %1$s %3$s %2$s %4$s - %10$s %6$s %8$s %7$s %9$s - %1$s %3$s %2$s %4$s - %6$s %8$s %7$s %9$s - %3$s-%8$s %2$s - %1$s %3$s %2$s - %6$s %8$s %7$s - %3$s %2$s - %8$s %7$s %9$s - %3$s-%8$s %2$s %9$s - %1$s %3$s %2$s - %6$s %8$s %7$s %9$s - %b - diff --git a/core/res/res/values-nl-rNL/donottranslate-cldr.xml b/core/res/res/values-nl-rNL/donottranslate-cldr.xml deleted file mode 100644 index b6231b6227904..0000000000000 --- a/core/res/res/values-nl-rNL/donottranslate-cldr.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - januari - februari - maart - april - mei - juni - juli - augustus - september - oktober - november - december - - januari - februari - maart - april - mei - juni - juli - augustus - september - oktober - november - december - - jan. - feb. - mrt. - apr. - mei - jun. - jul. - aug. - sep. - okt. - nov. - dec. - - J - F - M - A - M - J - J - A - S - O - N - D - - zondag - maandag - dinsdag - woensdag - donderdag - vrijdag - zaterdag - - zo - ma - di - wo - do - vr - za - - zo - ma - di - wo - do - vr - za - - Z - M - D - W - D - V - Z - - AM - PM - Gisteren - Vandaag - Morgen - - %H:%M - %-l:%M %p - %-l:%M %^p - h:mm a - HH:mm - %d-%m-%Y - dd-MM-yyyy - "%s-%s-%s" - %-e %B %Y - %H:%M:%S - %H:%M:%S %-e %b %Y - %2$s %1$s - %1$s %3$s - %-e %b %Y - %-e %B - %-B - %B %Y - %-e-%b - %-b - %b %Y - %1$s - %2$s - %2$s - %5$s - %3$s-%2$s - %8$s-%7$s - %1$s %3$s-%2$s - %6$s %8$s-%7$s - %3$s-%2$s-%4$s - %8$s-%7$s-%9$s - %1$s %3$s-%2$s-%4$s - %6$s %8$s-%7$s-%9$s - %5$s %1$s %3$s-%2$s-%4$s - %10$s %6$s %8$s-%7$s-%9$s - %5$s %3$s-%2$s - %10$s %8$s-%7$s - %5$s %1$s %3$s-%2$s - %10$s %6$s %8$s-%7$s - %5$s %3$s-%2$s-%4$s - %10$s %8$s-%7$s-%9$s - %3$s %1$s %2$s - %6$s %4$s %5$s - %1$s %2$s - %4$s %5$s - %3$s %2$s - %6$s %5$s - %1$s %2$s %3$s - %2$s %3$s - %1$s %2$s - %3$s %2$s - %8$s %7$s - %1$s %3$s %2$s - %6$s %8$s %7$s - %5$s %3$s %2$s - %10$s %8$s %7$s - %5$s %3$s %2$s - %10$s %8$s %7$s - %5$s %1$s %3$s %2$s - %10$s %6$s %8$s %7$s - %5$s %1$s %3$s %2$s - %10$s %6$s %8$s %7$s - %5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s - %5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s - %5$s %1$s %3$s %2$s %4$s - %10$s %6$s %8$s %7$s %9$s - %5$s %1$s %3$s %2$s %4$s - %10$s %6$s %8$s %7$s %9$s - %1$s %3$s %2$s %4$s - %6$s %8$s %7$s %9$s - %3$s-%8$s %2$s - %1$s %3$s %2$s - %6$s %8$s %7$s - %3$s %2$s - %8$s %7$s %9$s - %3$s-%8$s %2$s %9$s - %1$s %3$s %2$s - %6$s %8$s %7$s %9$s - %b - diff --git a/core/res/res/values-nl/donottranslate-cldr.xml b/core/res/res/values-nl/donottranslate-cldr.xml index b6231b6227904..2360e3f9a23b9 100644 --- a/core/res/res/values-nl/donottranslate-cldr.xml +++ b/core/res/res/values-nl/donottranslate-cldr.xml @@ -108,7 +108,7 @@ %-e %B %-B %B %Y - %-e-%b + %-e %b %-b %b %Y %1$s - %2$s diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index cd1b460e5ac02..533be17eeaabe 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -111,7 +111,6 @@ "Het bestand kan niet worden geopend." "Het opgevraagde bestand is niet gevonden." "Er worden te veel aanvragen verwerkt. Probeer het later opnieuw." - "Het certificaat is opgeslagen in de opslagruimte voor sleutels van het systeem." "Synchroniseren" "Synchroniseren" "Te veel verwijderen voor %s." diff --git a/core/res/res/values-pl-rPL/donottranslate-cldr.xml b/core/res/res/values-pl-rPL/donottranslate-cldr.xml deleted file mode 100644 index 4ad17bf11c469..0000000000000 --- a/core/res/res/values-pl-rPL/donottranslate-cldr.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - styczeń - luty - marzec - kwiecień - maj - czerwiec - lipiec - sierpień - wrzesień - październik - listopad - grudzień - - stycznia - lutego - marca - kwietnia - maja - czerwca - lipca - sierpnia - września - października - listopada - grudnia - - sty - lut - mar - kwi - maj - cze - lip - sie - wrz - paź - lis - gru - - s - l - m - k - m - c - l - s - w - p - l - g - - niedziela - poniedziałek - wtorek - środa - czwartek - piątek - sobota - - niedz. - pon. - wt. - śr. - czw. - pt. - sob. - - niedz. - pon. - wt. - śr. - czw. - pt. - sob. - - N - P - W - Ś - C - P - S - - AM - PM - Wczoraj - Dzisiaj - Jutro - - %-k:%M - %-l:%M %p - %-l:%M %^p - h:mm a - H:mm - %d-%m-%Y - dd-MM-yyyy - "%s-%s-%s" - %-e %B %Y - %H:%M:%S - %H:%M:%S %d-%m-%Y - %2$s %1$s - %1$s %3$s - %d-%m-%Y - %-e %B - %-B - %-B %Y - %b %-e - %-b - %Y %b - %1$s - %2$s - %2$s - %5$s - %3$s.%2$s-%8$s.%7$s - %1$s, %3$s.%2$s - %6$s, %8$s.%7$s - %3$s.%2$s.%4$s-%8$s.%7$s.%9$s - %1$s, %3$s-%2$s-%4$s-%6$s, %8$s-%7$s-%9$s - %5$s %1$s, %3$s.%2$s.%4$s - %10$s %6$s, %8$s.%7$s.%9$s - %5$s %3$s.%2$s - %10$s %8$s.%7$s - %5$s %1$s, %2$s-%3$s - %10$s %6$s, %7$s-%8$s - %5$s %3$s-%2$s-%4$s - %10$s %8$s-%7$s-%9$s - %3$s %1$s, %2$s - %6$s %4$s, %5$s - %1$s, %2$s - %4$s, %5$s - %3$s %2$s - %6$s %5$s - %1$s %2$s, %3$s - %2$s, %3$s - %1$s %2$s - %3$s %2$s - %8$s %7$s - %3$s %2$s %1$s - %8$s %7$s %6$s - %5$s %3$s %2$s - %10$s %8$s %7$s - %5$s %3$s %2$s - %10$s %8$s %7$s - %5$s %3$s %2$s %1$s - %10$s %8$s %7$s %6$s - %5$s %3$s %2$s %1$s - %10$s %8$s %7$s %6$s - %5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s - %5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s - %5$s %1$s, %3$s %2$s %4$s - %10$s %6$s, %8$s %7$s %9$s - %5$s %1$s, %3$s %2$s %4$s - %10$s %6$s, %8$s %7$s %9$s - %1$s, %3$s %2$s %4$s - %6$s, %8$s %7$s %9$s - %3$s-%8$s %2$s - %3$s %2$s %1$s - %8$s %7$s %6$s - %3$s %2$s - %8$s %7$s %9$s - %3$s-%8$s %2$s %9$s - %1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s - %b - diff --git a/core/res/res/values-pl/donottranslate-cldr.xml b/core/res/res/values-pl/donottranslate-cldr.xml index 4ad17bf11c469..f20a5b74ccf7e 100644 --- a/core/res/res/values-pl/donottranslate-cldr.xml +++ b/core/res/res/values-pl/donottranslate-cldr.xml @@ -96,52 +96,52 @@ %-l:%M %^p h:mm a H:mm - %d-%m-%Y - dd-MM-yyyy - "%s-%s-%s" + %d.%m.%Y + dd.MM.yyyy + "%s.%s.%s" %-e %B %Y %H:%M:%S - %H:%M:%S %d-%m-%Y - %2$s %1$s + %d.%m.%Y %H:%M:%S + %1$s %2$s %1$s %3$s - %d-%m-%Y + %d.%m.%Y %-e %B %-B %-B %Y - %b %-e + %-e %b %-b - %Y %b - %1$s - %2$s - %2$s - %5$s + %b %Y + %1$s-%2$s + %2$s-%5$s %3$s.%2$s-%8$s.%7$s - %1$s, %3$s.%2$s - %6$s, %8$s.%7$s + %1$s, %3$s.%2$s-%6$s, %8$s.%7$s %3$s.%2$s.%4$s-%8$s.%7$s.%9$s - %1$s, %3$s-%2$s-%4$s-%6$s, %8$s-%7$s-%9$s - %5$s %1$s, %3$s.%2$s.%4$s - %10$s %6$s, %8$s.%7$s.%9$s - %5$s %3$s.%2$s - %10$s %8$s.%7$s - %5$s %1$s, %2$s-%3$s - %10$s %6$s, %7$s-%8$s - %5$s %3$s-%2$s-%4$s - %10$s %8$s-%7$s-%9$s - %3$s %1$s, %2$s - %6$s %4$s, %5$s - %1$s, %2$s - %4$s, %5$s - %3$s %2$s - %6$s %5$s + %1$s, %3$s.%2$s.%4$s-%6$s, %8$s.%7$s.%9$s + %1$s, %3$s.%2$s.%4$s %5$s-%6$s, %8$s.%7$s.%9$s %10$s + %3$s.%2$s %5$s-%8$s.%7$s %10$s + %1$s, %3$s.%2$s %5$s-%6$s, %8$s.%7$s %10$s + %3$s.%2$s.%4$s %5$s-%8$s.%7$s.%9$s %10$s + %1$s, %2$s %3$s-%4$s, %5$s %6$s + %1$s, %2$s-%4$s, %5$s + %2$s %3$s-%5$s %6$s %1$s %2$s, %3$s %2$s, %3$s %1$s %2$s - %3$s %2$s - %8$s %7$s - %3$s %2$s %1$s - %8$s %7$s %6$s - %5$s %3$s %2$s - %10$s %8$s %7$s - %5$s %3$s %2$s - %10$s %8$s %7$s - %5$s %3$s %2$s %1$s - %10$s %8$s %7$s %6$s - %5$s %3$s %2$s %1$s - %10$s %8$s %7$s %6$s - %5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s - %5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s - %5$s %1$s, %3$s %2$s %4$s - %10$s %6$s, %8$s %7$s %9$s - %5$s %1$s, %3$s %2$s %4$s - %10$s %6$s, %8$s %7$s %9$s - %1$s, %3$s %2$s %4$s - %6$s, %8$s %7$s %9$s + %3$s %2$s-%8$s %7$s + %1$s, %3$s %2$s-%6$s, %8$s %7$s + %3$s %2$s %5$s-%8$s %7$s %10$s + %3$s %2$s %5$s-%8$s %7$s %10$s + %1$s, %3$s %2$s %5$s-%6$s, %8$s %7$s %10$s + %1$s, %3$s %2$s %5$s-%6$s, %8$s %7$s %10$s + %3$s %2$s %4$s %5$s-%8$s %7$s %9$s %10$s + %3$s %2$s %4$s %5$s-%8$s %7$s %9$s %10$s + %1$s, %3$s %2$s %4$s %5$s-%6$s, %8$s %7$s %9$s %10$s + %1$s, %3$s %2$s %4$s %5$s-%6$s, %8$s %7$s %9$s %10$s + %1$s, %3$s %2$s %4$s-%6$s, %8$s %7$s %9$s %3$s-%8$s %2$s - %3$s %2$s %1$s - %8$s %7$s %6$s - %3$s %2$s - %8$s %7$s %9$s + %1$s, %3$s %2$s-%6$s, %8$s %7$s + %3$s %2$s-%8$s %7$s %9$s %3$s-%8$s %2$s %9$s - %1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s + %1$s, %3$s %2$s-%6$s, %8$s %7$s %9$s %b diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index 65f3ad14d3254..3a8c6a6c029e6 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -111,7 +111,6 @@ "Nie można uzyskać dostępu do pliku." "Nie znaleziono żądanego pliku." "Zbyt wiele żądań jest przetwarzanych. Spróbuj ponownie później." - "Certyfikat jest zapisywany w magazynie kluczy systemu." "Synchronizacja" "Synchronizuj" "Zbyt wiele usuwanych %s." diff --git a/core/res/res/values-pt-rBR/donottranslate-cldr.xml b/core/res/res/values-pt-rBR/donottranslate-cldr.xml deleted file mode 100644 index 1111658ffb907..0000000000000 --- a/core/res/res/values-pt-rBR/donottranslate-cldr.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - janeiro - fevereiro - março - abril - maio - junho - julho - agosto - setembro - outubro - novembro - dezembro - - janeiro - fevereiro - março - abril - maio - junho - julho - agosto - setembro - outubro - novembro - dezembro - - jan - fev - mar - abr - mai - jun - jul - ago - set - out - nov - dez - - J - F - M - A - M - J - J - A - S - O - N - D - - domingo - segunda-feira - terça-feira - quarta-feira - quinta-feira - sexta-feira - sábado - - dom - seg - ter - qua - qui - sex - sáb - - dom - seg - ter - qua - qui - sex - sáb - - D - S - T - Q - Q - S - S - - AM - PM - Ontem - Hoje - Amanhã - - %-kh%M - %-l:%M %p - %-l:%M %^p - h:mm a - H\'h\'mm - %d/%m/%Y - dd/MM/yyyy - "%s/%s/%s" - %-e de %B de %Y - %H:%M:%S - %H:%M:%S %d/%m/%Y - %2$s %1$s - %1$s %3$s - %d/%m/%Y - %-e de %B - %-B - %B de %Y - %-e de %b - %-b - %b de %Y - %1$s - %2$s - %2$s - %5$s - %3$s/%2$s - %8$s/%7$s - %1$s, %3$s/%2$s - %6$s, %8$s/%7$s - %3$s/%2$s/%4$s - %8$s/%7$s/%9$s - %1$s, %3$s/%2$s/%4$s - %6$s, %8$s/%7$s/%9$s - %5$s %1$s, %3$s/%2$s/%4$s - %10$s %6$s, %8$s/%7$s/%9$s - %5$s %3$s/%2$s - %10$s %8$s/%7$s - %5$s %1$s, %3$s/%2$s - %10$s %6$s, %8$s/%7$s - %5$s %3$s/%2$s/%4$s - %10$s %8$s/%7$s/%9$s - %3$s %1$s, %2$s - %6$s %4$s, %5$s - %1$s, %2$s - %4$s, %5$s - %3$s %2$s - %6$s %5$s - %1$s %2$s, %3$s - %2$s, %3$s - %1$s %2$s - %3$s de %2$s - %8$s de %7$s - %1$s, %3$s de %2$s - %6$s, %8$s de %7$s - %5$s %3$s de %2$s - %10$s %8$s de %7$s - %5$s %3$s de %2$s - %10$s %8$s de %7$s - %5$s %1$s, %3$s de %2$s - %10$s %6$s, %8$s de %7$s - %5$s %1$s, %3$s de %2$s - %10$s %6$s, %8$s de %7$s - %5$s %3$s de %2$s de %4$s - %10$s %8$s de %7$s de %9$s - %5$s %3$s de %2$s de %4$s - %10$s %8$s de %7$s de %9$s - %5$s %1$s, %3$s de %2$s de %4$s - %10$s %6$s, %8$s de %7$s de %9$s - %5$s %1$s, %3$s de %2$s de %4$s - %10$s %6$s, %8$s de %7$s de %9$s - %1$s, %3$s de %2$s de %4$s - %6$s, %8$s de %7$s de %9$s - %3$s-%8$s de %2$s - %1$s, %3$s de %2$s - %6$s, %8$s de %7$s - %3$s de %2$s - %8$s de %7$s de %9$s - %3$s-%8$s de %2$s de %9$s - %1$s, %3$s de %2$s - %6$s, %8$s de %7$s de %9$s - %b - diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index d4623f96c4d6b..04ca746c16e88 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -134,8 +134,6 @@ "Não foi possível aceder ao ficheiro." "Não foi possível localizar o ficheiro pedido." "Existem demasiados pedidos em processamento. Tente novamente mais tarde." - - "Sincronização" "Sincronização" "Demasiadas eliminações de %s." diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 97d7596b690b9..8c5babb2eb8e9 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -134,8 +134,6 @@ "Não foi possível acessar o arquivo." "O arquivo solicitado não foi encontrado." "Há muitas solicitações sendo processadas. Tente novamente mais tarde." - - "Sincronizar" "Sincronizar" "Muitas exclusões de %s." diff --git a/core/res/res/values-ru-rRU/donottranslate-cldr.xml b/core/res/res/values-ru-rRU/donottranslate-cldr.xml deleted file mode 100644 index 21c06ff3a0abc..0000000000000 --- a/core/res/res/values-ru-rRU/donottranslate-cldr.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - Январь - Февраль - Март - Апрель - Май - Июнь - Июль - Август - Сентябрь - Октябрь - Ноябрь - Декабрь - - января - февраля - марта - апреля - мая - июня - июля - августа - сентября - октября - ноября - декабря - - янв. - февр. - марта - апр. - мая - июня - июля - авг. - сент. - окт. - нояб. - дек. - - Я - Ф - М - А - М - И - И - А - С - О - Н - Д - - воскресенье - понедельник - вторник - среда - четверг - пятница - суббота - - Вс - Пн - Вт - Ср - Чт - Пт - Сб - - Вс - Пн - Вт - Ср - Чт - Пт - Сб - - В - П - В - С - Ч - П - С - - AM - PM - Вчера - Сегодня - Завтра - - %-k:%M - %-l:%M %p - %-l:%M %^p - h:mm a - H:mm - %d.%m.%Y - dd.MM.yyyy - "%s.%s.%s" - %-e %B %Y г. - %-k:%M:%S - %-k:%M:%S %d.%m.%Y - %2$s %1$s - %1$s %3$s - %d.%m.%Y - %-e %B - %-B - %B %Y - %-e %b - %-b - %b %Y - %1$s - %2$s - %2$s - %5$s - %3$s.%2$s - %8$s.%7$s - %1$s, %2$s-%3$s – %6$s, %7$s-%8$s - %3$s.%2$s.%4$s - %8$s.%7$s.%9$s - %3$s.%2$s.%4$s - %8$s.%7$s.%9$s - %5$s %1$s, %4$s-%2$s-%3$s - %10$s %6$s, %9$s-%7$s-%8$s - %5$s %3$s.%2$s - %10$s %8$s.%7$s - %5$s %1$s, %2$s-%3$s - %10$s %6$s, %7$s-%8$s - %5$s %3$s.%2$s.%4$s - %10$s %8$s.%7$s.%9$s - %3$s %2$s - %6$s %5$s - %2$s - %5$s - %3$s %2$s - %6$s %5$s - %1$s %3$s - %3$s - %1$s %2$s - %3$s %2$s - %8$s %7$s - %1$s %2$s %3$s - %6$s %7$s %8$s - %5$s %3$s %2$s - %10$s %8$s %7$s - %5$s %3$s %2$s - %10$s %8$s %7$s - %5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s - %5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s - %5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s - %5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s - %5$s %1$s, %3$s %2$s %4$s - %10$s %6$s, %8$s %7$s %9$s - %5$s %1$s, %3$s %2$s %4$s - %10$s %6$s, %8$s %7$s %9$s - %1$s, %3$s %2$s %4$s - %6$s, %8$s %7$s %9$s - %3$s-%8$s %2$s - %1$s %2$s %3$s - %6$s %7$s %8$s - %3$s %2$s - %8$s %7$s %9$s г. - %3$s-%8$s %2$s %9$s г. - %3$s %2$s - %8$s %7$s %9$s г. - %b - diff --git a/core/res/res/values-ru/donottranslate-cldr.xml b/core/res/res/values-ru/donottranslate-cldr.xml index 21c06ff3a0abc..7745944f078b6 100644 --- a/core/res/res/values-ru/donottranslate-cldr.xml +++ b/core/res/res/values-ru/donottranslate-cldr.xml @@ -1,18 +1,18 @@ - Январь - Февраль - Март - Апрель - Май - Июнь - Июль - Август - Сентябрь - Октябрь - Ноябрь - Декабрь + январь + февраль + март + апрель + май + июнь + июль + август + сентябрь + октябрь + ноябрь + декабрь января февраля @@ -61,21 +61,21 @@ пятница суббота - Вс - Пн - Вт - Ср - Чт - Пт - Сб + вс + пн + вт + ср + чт + пт + сб - Вс - Пн - Вт - Ср - Чт - Пт - Сб + вс + пн + вт + ср + чт + пт + сб В П @@ -101,45 +101,45 @@ "%s.%s.%s" %-e %B %Y г. %-k:%M:%S - %-k:%M:%S %d.%m.%Y - %2$s %1$s - %1$s %3$s + %-k:%M:%S, %d.%m.%Y + %2$s, %1$s + %1$s, %3$s %d.%m.%Y %-e %B %-B - %B %Y + %-B %Y %-e %b %-b - %b %Y + %-b %Y %1$s - %2$s %2$s - %5$s %3$s.%2$s - %8$s.%7$s - %1$s, %2$s-%3$s – %6$s, %7$s-%8$s + %1$s, %3$s.%2$s – %6$s, %8$s.%7$s %3$s.%2$s.%4$s - %8$s.%7$s.%9$s %3$s.%2$s.%4$s - %8$s.%7$s.%9$s - %5$s %1$s, %4$s-%2$s-%3$s - %10$s %6$s, %9$s-%7$s-%8$s - %5$s %3$s.%2$s - %10$s %8$s.%7$s - %5$s %1$s, %2$s-%3$s - %10$s %6$s, %7$s-%8$s - %5$s %3$s.%2$s.%4$s - %10$s %8$s.%7$s.%9$s - %3$s %2$s - %6$s %5$s - %2$s - %5$s - %3$s %2$s - %6$s %5$s - %1$s %3$s - %3$s - %1$s %2$s + %5$s, %1$s, %3$s.%2$s.%4$s - %10$s, %6$s, %8$s.%7$s.%9$s + %5$s, %3$s.%2$s - %10$s, %8$s.%7$s + %5$s, %1$s, %3$s.%2$s - %10$s, %6$s, %8$s.%7$s + %5$s, %3$s.%2$s.%4$s - %10$s, %8$s.%7$s.%9$s + %3$s, %1$s, %2$s - %6$s, %4$s, %5$s + %1$s, %2$s - %4$s, %5$s + %3$s, %2$s - %6$s, %5$s + %1$s, %2$s, %3$s + %2$s, %3$s + %1$s, %2$s %3$s %2$s - %8$s %7$s - %1$s %2$s %3$s - %6$s %7$s %8$s - %5$s %3$s %2$s - %10$s %8$s %7$s - %5$s %3$s %2$s - %10$s %8$s %7$s - %5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s - %5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s - %5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s - %5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s - %5$s %1$s, %3$s %2$s %4$s - %10$s %6$s, %8$s %7$s %9$s - %5$s %1$s, %3$s %2$s %4$s - %10$s %6$s, %8$s %7$s %9$s + %1$s, %3$s %2$s - %6$s, %8$s %7$s + %5$s, %3$s %2$s - %10$s, %8$s %7$s + %5$s, %3$s %2$s - %10$s, %8$s %7$s + %5$s, %1$s, %3$s %2$s - %10$s, %6$s, %8$s %7$s + %5$s, %1$s, %3$s %2$s - %10$s, %6$s, %8$s %7$s + %5$s, %3$s %2$s %4$s - %10$s, %8$s %7$s %9$s + %5$s, %3$s %2$s %4$s - %10$s, %8$s %7$s %9$s + %5$s, %1$s, %3$s %2$s %4$s - %10$s, %6$s, %8$s %7$s %9$s + %5$s, %1$s, %3$s %2$s %4$s - %10$s, %6$s, %8$s %7$s %9$s %1$s, %3$s %2$s %4$s - %6$s, %8$s %7$s %9$s %3$s-%8$s %2$s - %1$s %2$s %3$s - %6$s %7$s %8$s + %1$s, %3$s %2$s - %6$s, %8$s %7$s %3$s %2$s - %8$s %7$s %9$s г. %3$s-%8$s %2$s %9$s г. %3$s %2$s - %8$s %7$s %9$s г. diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 03284c15d33e2..bb218c515e070 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -134,8 +134,6 @@ "Не удается получить доступ к файлу." "Не удалось найти указанные файлы." "Обрабатывается слишком много запросов. Повторите попытку позднее." - - "Синхр." "Синхр." "Слишком много удалений %s." diff --git a/core/res/res/values-sk-rSK/donottranslate-cldr.xml b/core/res/res/values-sk-rSK/donottranslate-cldr.xml index 16239df8c04e6..64780742a5cfd 100644 --- a/core/res/res/values-sk-rSK/donottranslate-cldr.xml +++ b/core/res/res/values-sk-rSK/donottranslate-cldr.xml @@ -96,52 +96,52 @@ %-l:%M %p h:mm a HH:mm - %-e.%-m.%Y - d.M.yyyy - "%s.%s.%s" + %-e. %-m. %Y + d. M. yyyy + "%s. %s. %s" %-e. %B %Y %-k:%M:%S - %-k:%M:%S %-e.%-m.%Y + %-k:%M:%S %-e. %-m. %Y %2$s %1$s %1$s %3$s - %-e.%-m.%Y + %-e. %-m. %Y %-e. %B %-B - %B %Y + %-B %Y %-e. %b %b - %b %Y + %-b %Y %1$s - %2$s %2$s - %5$s - %3$s.%2$s. - %8$s.%7$s. - %1$s, %3$s.%2$s. - %6$s, %8$s.%7$s. - %3$s.%2$s.%4$s - %8$s.%7$s.%9$s - %1$s, %3$s.%2$s.%4$s - %6$s, %8$s.%7$s.%9$s - %5$s %1$s, %3$s.%2$s.%4$s - %10$s %6$s, %8$s.%7$s.%9$s - %5$s %3$s.%2$s. - %10$s %8$s.%7$s. - %5$s %1$s, %3$s.%2$s. - %10$s %6$s, %8$s.%7$s. - %5$s %3$s.%2$s.%4$s - %10$s %8$s.%7$s.%9$s - %3$s %1$s, %2$s - %6$s %4$s, %5$s - %1$s, %2$s - %4$s, %5$s + %3$s. %2$s. - %8$s. %7$s. + %1$s %3$s. %2$s. - %6$s %8$s. %7$s. + %3$s. %2$s. %4$s - %8$s. %7$s. %9$s + %1$s %3$s. %2$s. %4$s - %6$s %8$s. %7$s. %9$s + %5$s %1$s %3$s. %2$s. %4$s - %10$s %6$s %8$s. %7$s. %9$s + %5$s %3$s. %2$s. - %10$s %8$s. %7$s. + %5$s %1$s %3$s. %2$s. - %10$s %6$s %8$s. %7$s. + %5$s %3$s. %2$s. %4$s - %10$s %8$s. %7$s. %9$s + %3$s %1$s %2$s - %6$s %4$s %5$s + %1$s %2$s - %4$s %5$s %3$s %2$s - %6$s %5$s - %1$s %2$s, %3$s - %2$s, %3$s + %1$s %2$s %3$s + %2$s %3$s %1$s %2$s %3$s. %2$s - %8$s. %7$s - %1$s, %3$s. %2$s - %6$s, %8$s. %7$s + %1$s %3$s. %2$s - %6$s %8$s. %7$s %5$s %3$s. %2$s - %10$s %8$s. %7$s %5$s %3$s. %2$s - %10$s %8$s. %7$s - %5$s %1$s, %3$s. %2$s - %10$s %6$s, %8$s. %7$s - %5$s %1$s, %3$s. %2$s - %10$s %6$s, %8$s. %7$s + %5$s %1$s %3$s. %2$s - %10$s %6$s %8$s. %7$s + %5$s %1$s %3$s. %2$s - %10$s %6$s %8$s. %7$s %5$s %3$s. %2$s %4$s - %10$s %8$s. %7$s %9$s %5$s %3$s. %2$s %4$s - %10$s %8$s. %7$s %9$s - %5$s %1$s, %3$s. %2$s %4$s - %10$s %6$s, %8$s. %7$s %9$s - %5$s %1$s, %3$s. %2$s %4$s - %10$s %6$s, %8$s. %7$s %9$s - %1$s, %3$s. %2$s %4$s - %6$s, %8$s. %7$s %9$s + %5$s %1$s %3$s. %2$s %4$s - %10$s %6$s %8$s. %7$s %9$s + %5$s %1$s %3$s. %2$s %4$s - %10$s %6$s %8$s. %7$s %9$s + %1$s %3$s. %2$s %4$s - %6$s %8$s. %7$s %9$s %3$s. - %8$s. %2$s - %1$s, %3$s. %2$s - %6$s, %8$s. %7$s + %1$s %3$s. %2$s - %6$s %8$s. %7$s %3$s. %2$s - %8$s. %7$s %9$s %3$s. - %8$s. %2$s %9$s - %1$s, %3$s. %2$s - %6$s, %8$s. %7$s %9$s + %1$s %3$s. %2$s - %6$s %8$s. %7$s %9$s %b diff --git a/core/res/res/values-sl-rSI/donottranslate-cldr.xml b/core/res/res/values-sl-rSI/donottranslate-cldr.xml index b4ea32f37abdc..ae1678291d0e9 100644 --- a/core/res/res/values-sl-rSI/donottranslate-cldr.xml +++ b/core/res/res/values-sl-rSI/donottranslate-cldr.xml @@ -27,18 +27,18 @@ november december - jan - feb - mar - apr - maj - jun - jul - avg - sep - okt - nov - dec + jan. + feb. + mar. + apr. + maj. + jun. + jul. + avg. + sep. + okt. + nov. + dec. j f @@ -61,21 +61,21 @@ petek sobota - ned - pon - tor - sre - čet - pet - sob + ned. + pon. + tor. + sre. + čet. + pet. + sob. - ned - pon - tor - sre - čet - pet - sob + ned. + pon. + tor. + sre. + čet. + pet. + sob. n p @@ -101,47 +101,47 @@ "%s. %s. %s" %d. %B %Y %H:%M:%S - %H:%M:%S %-e. %b. %Y - %2$s %1$s - %1$s %3$s - %-e. %b. %Y + %H:%M:%S, %-e. %b %Y + %2$s, %1$s + %1$s, %3$s + %-e. %b %Y %-e. %B %-B %B %Y - %-e. %b. + %-e. %b %b - %b. %Y - %1$s – %2$s - %2$s – %5$s - %3$s. %2$s. – %8$s. %7$s. - %1$s., %3$s. %2$s. – %6$s., %8$s. %7$s. - %3$s. %2$s. %4$s – %8$s. %7$s. %9$s - %1$s., %3$s. %2$s. %4$s – %6$s., %8$s. %7$s. %9$s - %5$s %1$s., %3$s. %2$s. %4$s – %10$s %6$s., %8$s. %7$s. %9$s - %5$s %3$s. %2$s. – %10$s %8$s. %7$s. - %5$s %1$s., %3$s. %2$s. – %10$s %6$s., %8$s. %7$s. - %5$s %3$s. %2$s. %4$s – %10$s %8$s. %7$s. %9$s - %3$s %1$s., %2$s – %6$s %4$s., %5$s - %1$s., %2$s – %4$s., %5$s - %3$s %2$s – %6$s %5$s - %1$s %2$s., %3$s - %2$s., %3$s - %1$s %2$s - %3$s. %2$s – %8$s. %7$s - %1$s., %3$s. %2$s. – %6$s., %8$s. %7$s. - %5$s %3$s. %2$s – %10$s %8$s. %7$s - %5$s %3$s. %2$s – %10$s %8$s. %7$s - %5$s %1$s., %3$s. %2$s. – %10$s %6$s., %8$s. %7$s. - %5$s %1$s., %3$s. %2$s. – %10$s %6$s., %8$s. %7$s. - %5$s %3$s. %2$s. %4$s – %10$s %8$s. %7$s. %9$s - %5$s %3$s. %2$s. %4$s – %10$s %8$s. %7$s. %9$s - %5$s %1$s., %3$s. %2$s. %4$s – %10$s %6$s., %8$s. %7$s. %9$s - %5$s %1$s., %3$s. %2$s. %4$s – %10$s %6$s., %8$s. %7$s. %9$s - %1$s., %3$s. %2$s. %4$s – %6$s., %8$s. %7$s. %9$s - %3$s.–%8$s. %2$s. - %1$s., %3$s. %2$s. – %6$s., %8$s. %7$s. - %3$s. %2$s. – %8$s. %7$s. %9$s - %3$s.–%8$s. %2$s. %9$s - %1$s., %3$s. %2$s. – %6$s., %8$s. %7$s. %9$s + %b %Y + %1$s–%2$s + %2$s–%5$s + %3$s. %2$s.–%8$s. %7$s. + %1$s, %3$s. %2$s.–%6$s, %8$s. %7$s. + %3$s. %2$s. %4$s–%8$s. %7$s. %9$s + %1$s, %3$s. %2$s. %4$s–%6$s, %8$s. %7$s. %9$s + %5$s, %1$s, %3$s. %2$s. %4$s–%10$s, %6$s, %8$s. %7$s. %9$s + %5$s, %3$s. %2$s.–%10$s, %8$s. %7$s. + %5$s, %1$s, %3$s. %2$s.–%10$s, %6$s, %8$s. %7$s. + %5$s, %3$s. %2$s. %4$s–%10$s, %8$s. %7$s. %9$s + %3$s, %1$s, %2$s–%6$s, %4$s, %5$s + %1$s, %2$s–%4$s, %5$s + %3$s, %2$s–%6$s, %5$s + %1$s, %2$s, %3$s + %2$s, %3$s + %1$s, %2$s + %3$s. %2$s–%8$s. %7$s + %1$s, %3$s. %2$s–%6$s, %8$s. %7$s + %5$s, %3$s. %2$s–%10$s, %8$s. %7$s + %5$s, %3$s. %2$s–%10$s, %8$s. %7$s + %5$s, %1$s, %3$s. %2$s–%10$s, %6$s, %8$s. %7$s + %5$s, %1$s, %3$s. %2$s–%10$s, %6$s, %8$s. %7$s + %5$s, %3$s. %2$s %4$s–%10$s, %8$s. %7$s %9$s + %5$s, %3$s. %2$s %4$s–%10$s, %8$s. %7$s %9$s + %5$s, %1$s, %3$s. %2$s %4$s–%10$s, %6$s, %8$s. %7$s %9$s + %5$s, %1$s, %3$s. %2$s %4$s–%10$s, %6$s, %8$s. %7$s %9$s + %1$s, %3$s. %2$s %4$s–%6$s, %8$s. %7$s %9$s + %3$s.–%8$s. %2$s + %1$s, %3$s. %2$s–%6$s, %8$s. %7$s + %3$s. %2$s–%8$s. %7$s %9$s + %3$s.–%8$s. %2$s %9$s + %1$s, %3$s. %2$s–%6$s, %8$s. %7$s %9$s %b diff --git a/core/res/res/values-sv-rSE/donottranslate-cldr.xml b/core/res/res/values-sv-rSE/donottranslate-cldr.xml deleted file mode 100644 index a6ffc9aa77af6..0000000000000 --- a/core/res/res/values-sv-rSE/donottranslate-cldr.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - januari - februari - mars - april - maj - juni - juli - augusti - september - oktober - november - december - - januari - februari - mars - april - maj - juni - juli - augusti - september - oktober - november - december - - jan - feb - mar - apr - maj - jun - jul - aug - sep - okt - nov - dec - - J - F - M - A - M - J - J - A - S - O - N - D - - söndag - måndag - tisdag - onsdag - torsdag - fredag - lördag - - sön - mån - tis - ons - tors - fre - lör - - sön - mån - tis - ons - tors - fre - lör - - S - M - T - O - T - F - L - - f.m. - e.m. - igår - idag - imorgon - - %-k.%M - %-l:%M %p - %-l:%M %^p - h:mm a - H.mm - %Y-%m-%d - yyyy-MM-dd - "%s-%s-%s" - %-e %B %Y - %H:%M:%S - %H:%M:%S %-e %b %Y - %2$s %1$s - %1$s %3$s - %-e %b %Y - %-e %B - %-B - %Y %B - %-e %b - %-b - %Y %b - %1$s – %2$s - %2$s – %5$s - %3$s/%2$s – %8$s/%7$s - %1$s %3$s/%2$s – %6$s %8$s/%7$s - %4$s-%2$s-%3$s – %9$s-%7$s-%8$s - %1$s, %4$s-%2$s-%3$s – %6$s, %9$s-%7$s-%8$s - %5$s %1$s, %4$s-%2$s-%3$s – %10$s %6$s, %9$s-%7$s-%8$s - %5$s %3$s/%2$s – %10$s %8$s/%7$s - %5$s %1$s %3$s/%2$s – %10$s %6$s %8$s/%7$s - %5$s %4$s-%2$s-%3$s – %10$s %9$s-%7$s-%8$s - %3$s %1$s %2$s – %6$s %4$s %5$s - %1$s %2$s – %4$s %5$s - %3$s %2$s – %6$s %5$s - %1$s %2$s %3$s - %2$s %3$s - %1$s %2$s - %3$s %2$s – %8$s %7$s - %1$s %3$s %2$s – %6$s %8$s %7$s - %5$s %3$s %2$s – %10$s %8$s %7$s - %5$s %3$s %2$s – %10$s %8$s %7$s - %5$s %1$s %3$s %2$s – %10$s %6$s %8$s %7$s - %5$s %1$s %3$s %2$s – %10$s %6$s %8$s %7$s - %5$s %3$s %2$s %4$s – %10$s %8$s %7$s %9$s - %5$s %3$s %2$s %4$s – %10$s %8$s %7$s %9$s - %5$s %1$s %3$s %2$s %4$s – %10$s %6$s %8$s %7$s %9$s - %5$s %1$s %3$s %2$s %4$s – %10$s %6$s %8$s %7$s %9$s - %1$s %3$s %2$s %4$s – %6$s %8$s %7$s %9$s - %3$s–%8$s %2$s - %1$s %3$s %2$s – %6$s %8$s %7$s - %3$s %2$s–%8$s %7$s %9$s - %3$s–%8$s %2$s %9$s - %1$s %3$s %2$s–%6$s %8$s %7$s %9$s - %b - diff --git a/core/res/res/values-sv/donottranslate-cldr.xml b/core/res/res/values-sv/donottranslate-cldr.xml index a6ffc9aa77af6..0172755f2cc13 100644 --- a/core/res/res/values-sv/donottranslate-cldr.xml +++ b/core/res/res/values-sv/donottranslate-cldr.xml @@ -91,13 +91,13 @@ idag imorgon - %-k.%M + %-k:%M %-l:%M %p %-l:%M %^p h:mm a - H.mm - %Y-%m-%d - yyyy-MM-dd + H:mm + %d-%m-%Y + dd-MM-yyyy "%s-%s-%s" %-e %B %Y %H:%M:%S @@ -110,17 +110,17 @@ %Y %B %-e %b %-b - %Y %b - %1$s – %2$s + %b %Y + %1$s–%2$s %2$s – %5$s %3$s/%2$s – %8$s/%7$s %1$s %3$s/%2$s – %6$s %8$s/%7$s - %4$s-%2$s-%3$s – %9$s-%7$s-%8$s - %1$s, %4$s-%2$s-%3$s – %6$s, %9$s-%7$s-%8$s - %5$s %1$s, %4$s-%2$s-%3$s – %10$s %6$s, %9$s-%7$s-%8$s + %3$s-%2$s-%4$s – %8$s-%7$s-%9$s + %1$s %3$s-%2$s-%4$s – %6$s %8$s-%7$s-%9$s + %5$s %1$s %3$s-%2$s-%4$s – %10$s %6$s %8$s-%7$s-%9$s %5$s %3$s/%2$s – %10$s %8$s/%7$s %5$s %1$s %3$s/%2$s – %10$s %6$s %8$s/%7$s - %5$s %4$s-%2$s-%3$s – %10$s %9$s-%7$s-%8$s + %5$s %3$s-%2$s-%4$s – %10$s %8$s-%7$s-%9$s %3$s %1$s %2$s – %6$s %4$s %5$s %1$s %2$s – %4$s %5$s %3$s %2$s – %6$s %5$s @@ -140,8 +140,8 @@ %1$s %3$s %2$s %4$s – %6$s %8$s %7$s %9$s %3$s–%8$s %2$s %1$s %3$s %2$s – %6$s %8$s %7$s - %3$s %2$s–%8$s %7$s %9$s + %3$s %2$s – %8$s %7$s %9$s %3$s–%8$s %2$s %9$s - %1$s %3$s %2$s–%6$s %8$s %7$s %9$s + %1$s %3$s %2$s – %6$s %8$s %7$s %9$s %b diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 383126a68fdf4..a9e79898a0ec9 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -134,8 +134,6 @@ "Det gick inte att komma åt filen." "Den begärda filen hittades inte." "För många begäranden bearbetas. Försök igen senare." - - "Synkronisera" "Synkronisera" "För många %s-borttagningar." diff --git a/core/res/res/values-tr-rTR/donottranslate-cldr.xml b/core/res/res/values-tr-rTR/donottranslate-cldr.xml deleted file mode 100644 index d61230593437d..0000000000000 --- a/core/res/res/values-tr-rTR/donottranslate-cldr.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - Ocak - Şubat - Mart - Nisan - Mayıs - Haziran - Temmuz - Ağustos - Eylül - Ekim - Kasım - Aralık - - Ocak - Şubat - Mart - Nisan - Mayıs - Haziran - Temmuz - Ağustos - Eylül - Ekim - Kasım - Aralık - - Oca - Şub - Mar - Nis - May - Haz - Tem - Ağu - Eyl - Eki - Kas - Ara - - O - Ş - M - N - M - H - T - A - E - E - K - A - - Pazar - Pazartesi - Salı - Çarşamba - Perşembe - Cuma - Cumartesi - - Paz - Pzt - Sal - Çar - Per - Cum - Cmt - - Paz - Pzt - Sal - Çar - Per - Cum - Cmt - - P - P - S - Ç - P - C - C - - AM - PM - Dün - Bugün - Yarın - - %H:%M - %-l:%M %p - %-l:%M %^p - h:mm a - HH:mm - %d %m %Y - dd MM yyyy - "%s %s %s" - %d %B %Y - %H:%M:%S - %H:%M:%S %d %b %Y - %2$s %1$s - %1$s %3$s - %d %b %Y - %d %B - %-B - %B %Y - %d %b - %-b - %b %Y - %1$s - %2$s - %2$s - %5$s - %3$s.%2$s - %8$s.%7$s - %3$s.%2$s %1$s - %8$s.%7$s %6$s - %3$s.%2$s.%4$s - %8$s.%7$s.%9$s - %3$s.%2$s.%4$s %1$s - %8$s.%7$s.%9$s %6$s - %5$s %3$s.%2$s.%4$s %1$s - %10$s %8$s.%7$s.%9$s %6$s - %5$s %3$s/%2$s - %10$s %8$s/%7$s - %5$s %3$s/%2$s %1$s - %10$s %8$s/%7$s %6$s - %5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s - %3$s %2$s %1$s - %6$s %5$s %4$s - %2$s %1$s - %5$s %4$s - %3$s %2$s - %6$s %5$s - %1$s %3$s %2$s - %3$s %2$s - %1$s %2$s - %3$s %2$s - %8$s %7$s - %3$s %2$s %1$s - %8$s %7$s %6$s - %5$s %3$s %2$s - %10$s %8$s %7$s - %5$s %3$s %2$s - %10$s %8$s %7$s - %5$s %3$s %2$s %1$s - %10$s %8$s %7$s %6$s - %5$s %3$s %2$s %1$s - %10$s %8$s %7$s %6$s - %5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s - %5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s - %5$s %3$s %2$s %4$s %1$s - %10$s %8$s %7$s %9$s %6$s - %5$s %3$s %2$s %4$s %1$s - %10$s %8$s %7$s %9$s %6$s - %3$s %2$s %4$s %1$s - %8$s %7$s %9$s %6$s - %3$s-%8$s %2$s - %3$s %2$s %1$s - %8$s %7$s %6$s - %3$s %2$s - %8$s %7$s %9$s - %3$s-%8$s %2$s %9$s - %3$s %2$s %9$s %1$s - %8$s %7$s y %6$s - %b - diff --git a/core/res/res/values-tr/donottranslate-cldr.xml b/core/res/res/values-tr/donottranslate-cldr.xml index d61230593437d..fd8e7624230f9 100644 --- a/core/res/res/values-tr/donottranslate-cldr.xml +++ b/core/res/res/values-tr/donottranslate-cldr.xml @@ -101,9 +101,9 @@ "%s %s %s" %d %B %Y %H:%M:%S - %H:%M:%S %d %b %Y - %2$s %1$s - %1$s %3$s + %d %b %Y %H:%M:%S + %1$s %2$s + %3$s %1$s %d %b %Y %d %B %-B @@ -117,31 +117,31 @@ %3$s.%2$s %1$s - %8$s.%7$s %6$s %3$s.%2$s.%4$s - %8$s.%7$s.%9$s %3$s.%2$s.%4$s %1$s - %8$s.%7$s.%9$s %6$s - %5$s %3$s.%2$s.%4$s %1$s - %10$s %8$s.%7$s.%9$s %6$s - %5$s %3$s/%2$s - %10$s %8$s/%7$s - %5$s %3$s/%2$s %1$s - %10$s %8$s/%7$s %6$s - %5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s - %3$s %2$s %1$s - %6$s %5$s %4$s + %3$s.%2$s.%4$s %1$s %5$s - %8$s.%7$s.%9$s %6$s %10$s + %3$s/%2$s %5$s - %8$s/%7$s %10$s + %3$s/%2$s %1$s %5$s - %8$s/%7$s %6$s %10$s + %3$s %2$s %4$s %5$s - %8$s %7$s %9$s %10$s + %2$s %1$s %3$s - %5$s %4$s %6$s %2$s %1$s - %5$s %4$s - %3$s %2$s - %6$s %5$s - %1$s %3$s %2$s + %2$s %3$s - %5$s %6$s + %3$s %2$s %1$s %3$s %2$s - %1$s %2$s + %2$s %1$s %3$s %2$s - %8$s %7$s %3$s %2$s %1$s - %8$s %7$s %6$s - %5$s %3$s %2$s - %10$s %8$s %7$s - %5$s %3$s %2$s - %10$s %8$s %7$s - %5$s %3$s %2$s %1$s - %10$s %8$s %7$s %6$s - %5$s %3$s %2$s %1$s - %10$s %8$s %7$s %6$s - %5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s - %5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s - %5$s %3$s %2$s %4$s %1$s - %10$s %8$s %7$s %9$s %6$s - %5$s %3$s %2$s %4$s %1$s - %10$s %8$s %7$s %9$s %6$s + %3$s %2$s %5$s - %8$s %7$s %10$s + %3$s %2$s %5$s - %8$s %7$s %10$s + %3$s %2$s %1$s %5$s - %8$s %7$s %6$s %10$s + %3$s %2$s %1$s %5$s - %8$s %7$s %6$s %10$s + %3$s %2$s %4$s %5$s - %8$s %7$s %9$s %10$s + %3$s %2$s %4$s %5$s - %8$s %7$s %9$s %10$s + %3$s %2$s %4$s %1$s %5$s - %8$s %7$s %9$s %6$s %10$s + %3$s %2$s %4$s %1$s %5$s - %8$s %7$s %9$s %6$s %10$s %3$s %2$s %4$s %1$s - %8$s %7$s %9$s %6$s %3$s-%8$s %2$s %3$s %2$s %1$s - %8$s %7$s %6$s %3$s %2$s - %8$s %7$s %9$s %3$s-%8$s %2$s %9$s - %3$s %2$s %9$s %1$s - %8$s %7$s y %6$s + %3$s %2$s %1$s - %8$s %7$s %6$s %9$s %b diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index ccaa08bf0db71..e4bbca7203c1a 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -134,8 +134,6 @@ "Dosyaya erişilemedi." "İstenen dosya bulunamadı." "Çok fazla sayıda istek işleniyor. Daha sonra yeniden deneyin." - - "Senk." "Senk." "Çok fazla %s silme var." diff --git a/core/res/res/values-uk-rUA/donottranslate-cldr.xml b/core/res/res/values-uk-rUA/donottranslate-cldr.xml index c51f8d1eae067..ed310c8c461be 100644 --- a/core/res/res/values-uk-rUA/donottranslate-cldr.xml +++ b/core/res/res/values-uk-rUA/donottranslate-cldr.xml @@ -1,18 +1,18 @@ - Січень - Лютий - Березень - Квітень - Травень - Червень - Липень - Серпень - Вересень - Жовтень - Листопад - Грудень + січень + лютий + березень + квітень + травень + червень + липень + серпень + вересень + жовтень + листопад + грудень січня лютого @@ -53,29 +53,29 @@ Л Г - Неділя - Понеділок - Вівторок - Середа - Четвер - Пʼятниця - Субота + неділя + понеділок + вівторок + середа + четвер + пʼятниця + субота - Нд - Пн - Вт - Ср - Чт - Пт - Сб + нд. + пн. + вт. + ср. + чт. + пт. + сб. - Нд - Пн - Вт - Ср - Чт - Пт - Сб + нд. + пн. + вт. + ср. + чт. + пт. + сб. Н П @@ -101,47 +101,47 @@ "%s.%s.%s" %-e %B %Y р. %H:%M:%S - %H:%M:%S %-e %b %Y - %2$s %1$s - %1$s %3$s - %-e %b %Y + %-e %b %Y р., %H:%M:%S + %1$s, %2$s + %3$s, %1$s + %-e %b %Y р. %-e %B %-B - %-B %Y + %-B %Y р. %-e %b %-b - %-b %Y + %-b %Y р. %1$s – %2$s %2$s – %5$s %3$s.%2$s – %8$s.%7$s %1$s, %3$s.%2$s – %6$s, %8$s.%7$s %3$s.%2$s.%4$s – %8$s.%7$s.%9$s %1$s, %3$s.%2$s.%4$s – %6$s, %8$s.%7$s.%9$s - %5$s %1$s, %3$s.%2$s.%4$s – %10$s %6$s, %8$s.%7$s.%9$s - %5$s %3$s.%2$s – %10$s %8$s.%7$s - %5$s %1$s, %3$s.%2$s – %10$s %6$s, %8$s.%7$s - %5$s %3$s.%2$s.%4$s – %10$s %8$s.%7$s.%9$s - %3$s %1$s, %2$s – %6$s %4$s, %5$s + %1$s, %3$s.%2$s.%4$s, %5$s – %6$s, %8$s.%7$s.%9$s, %10$s + %3$s.%2$s, %5$s – %8$s.%7$s, %10$s + %1$s, %3$s.%2$s, %5$s – %6$s, %8$s.%7$s, %10$s + %3$s.%2$s.%4$s, %5$s – %8$s.%7$s.%9$s, %10$s + %1$s, %2$s, %3$s – %4$s, %5$s, %6$s %1$s, %2$s – %4$s, %5$s - %3$s %2$s – %6$s %5$s - %1$s %2$s, %3$s + %2$s, %3$s – %5$s, %6$s + %2$s, %3$s, %1$s %2$s, %3$s - %1$s %2$s + %2$s, %1$s %3$s %2$s – %8$s %7$s %1$s, %3$s %2$s – %6$s, %8$s %7$s - %5$s %3$s %2$s – %10$s %8$s %7$s - %5$s %3$s %2$s – %10$s %8$s %7$s - %5$s %1$s, %3$s %2$s – %10$s %6$s, %8$s %7$s - %5$s %1$s, %3$s %2$s – %10$s %6$s, %8$s %7$s - %5$s %3$s %2$s %4$s – %10$s %8$s %7$s %9$s - %5$s %3$s %2$s %4$s – %10$s %8$s %7$s %9$s - %5$s %1$s, %3$s %2$s %4$s – %10$s %6$s, %8$s %7$s %9$s - %5$s %1$s, %3$s %2$s %4$s – %10$s %6$s, %8$s %7$s %9$s - %1$s, %3$s %2$s %4$s – %6$s, %8$s %7$s %9$s - %3$s–%8$s %2$s + %3$s %2$s, %5$s – %8$s %7$s, %10$s + %3$s %2$s, %5$s – %8$s %7$s, %10$s + %1$s, %3$s %2$s, %5$s – %6$s, %8$s %7$s, %10$s + %1$s, %3$s %2$s, %5$s – %6$s, %8$s %7$s, %10$s + %3$s %2$s %4$s р., %5$s – %8$s %7$s %9$s р., %10$s + %3$s %2$s %4$s р., %5$s – %8$s %7$s %9$s р., %10$s + %1$s, %3$s %2$s %4$s р., %5$s – %6$s, %8$s %7$s %9$s р., %10$s + %1$s, %3$s %2$s %4$s р., %5$s – %6$s, %8$s %7$s %9$s р., %10$s + %1$s, %3$s %2$s %4$s р. – %6$s, %8$s %7$s %9$s р. + %3$s – %8$s %2$s %1$s, %3$s %2$s – %6$s, %8$s %7$s - %3$s %2$s – %8$s %7$s %9$s - %3$s–%8$s %2$s %9$s - %1$s, %3$s %2$s – %6$s, %8$s %7$s %9$s + %3$s %2$s – %8$s %7$s %9$s р. + %3$s – %8$s %2$s %9$s р. + %1$s, %3$s %2$s – %6$s, %8$s %7$s %9$s р. %b diff --git a/core/res/res/values-zh-rCN/donottranslate-cldr.xml b/core/res/res/values-zh-rCN/donottranslate-cldr.xml index 6d52d7046f998..5077e945f5ca4 100644 --- a/core/res/res/values-zh-rCN/donottranslate-cldr.xml +++ b/core/res/res/values-zh-rCN/donottranslate-cldr.xml @@ -1,57 +1,57 @@ - 一月 - 二月 - 三月 - 四月 - 五月 - 六月 - 七月 - 八月 - 九月 - 十月 - 十一月 - 十二月 + 1 月 + 2 月 + 3 月 + 4 月 + 5 月 + 6 月 + 7 月 + 8 月 + 9 月 + 10 月 + 11 月 + 12 月 - 1月 - 2月 - 3月 - 4月 - 5月 - 6月 - 7月 - 8月 - 9月 - 10月 - 11月 - 12月 + 1 月 + 2 月 + 3 月 + 4 月 + 5 月 + 6 月 + 7 月 + 8 月 + 9 月 + 10 月 + 11 月 + 12 月 - 1月 - 2月 - 3月 - 4月 - 5月 - 6月 - 7月 - 8月 - 9月 - 10月 - 11月 - 12月 + 1 月 + 2 月 + 3 月 + 4 月 + 5 月 + 6 月 + 7 月 + 8 月 + 9 月 + 10 月 + 11 月 + 12 月 - 1月 - 2月 - 3月 - 4月 - 5月 - 6月 - 7月 - 8月 - 9月 - 10月 - 11月 - 12月 + 1 月 + 2 月 + 3 月 + 4 月 + 5 月 + 6 月 + 7 月 + 8 月 + 9 月 + 10 月 + 11 月 + 12 月 星期日 星期一 @@ -92,56 +92,56 @@ 明天 %-k:%M - %p%-l:%M - %p%-l:%M - ah:mm + %p %-l:%M + %p %-l:%M + a h:mm H:mm %Y-%-m-%-e yyyy-M-d "%s-%s-%s" - %Y年%-m月%-e日 - %p%I:%M:%S - %p%I:%M:%S %Y-%-m-%-e - %2$s %1$s - %1$s %3$s + %Y 年 %-m 月 %-e 日 + %p %I:%M:%S + %Y 年 %-m 月 %-e 日%p %I:%M:%S + %1$s %2$s + %3$s %1$s %Y-%-m-%-e - %B%-e日 + %B %-e 日 %-B - %Y年%B - %b%-e日 + %Y 年 %B + %b %-e 日 %-b - %Y年%b - %1$s–%2$s - %2$s–%5$s - %2$s-%3$s至%7$s-%8$s - %2$s-%3$s%1$s至%7$s-%8$s%6$s - %4$s-%2$s-%3$s至%9$s-%7$s-%8$s - %4$s-%2$s-%3$s%1$s至%9$s-%7$s-%8$s%6$s - %5$s %4$s年%2$s月%3$s日,%1$s–%10$s %9$s年%7$s月%8$s日,%6$s - %5$s %2$s-%3$s–%10$s %7$s-%8$s - %5$s %2$s-%3$s%1$s–%10$s %7$s-%8$s%6$s - %5$s %4$s-%2$s-%3$s–%10$s %9$s-%7$s-%8$s - %3$s %2$s%1$s–%6$s %5$s%4$s - %2$s%1$s–%5$s%4$s - %3$s %2$s–%6$s %5$s - %1$s %3$s%2$s + %Y 年 %b + %1$s – %2$s + %2$s – %5$s + %2$s 月 %3$s 日 - %7$s 月 %8$s 日 + %2$s 月 %3$s 日%1$s - %7$s 月 %8$s 日%6$s + %4$s-%2$s-%3$s - %9$s-%7$s-%8$s + %4$s-%2$s-%3$s %1$s - %9$s-%7$s-%8$s %6$s + %4$s-%2$s-%3$s %5$s %1$s – %9$s-%7$s-%8$s %10$s %6$s + %2$s 月 %3$s 日 %5$s – %7$s 月 %8$s 日 %10$s + %2$s 月 %3$s 日 %5$s %1$s – %7$s 月 %8$s 日 %10$s %6$s + %4$s-%2$s-%3$s %5$s – %9$s-%7$s-%8$s %10$s + %2$s %3$s %1$s – %5$s %6$s %4$s + %2$s%1$s – %5$s%4$s + %2$s %3$s – %5$s %6$s + %3$s %1$s %2$s %3$s%2$s %1$s %2$s - %2$s%3$s日–%7$s%8$s日 - %2$s%3$s日%1$s–%7$s%8$s日%6$s - %5$s %2$s%3$s日–%10$s %7$s%8$s日 - %5$s %2$s%3$s日–%10$s %7$s%8$s日 - %5$s %2$s%3$s日%1$s–%10$s %7$s%8$s日%6$s - %5$s %2$s%3$s日%1$s–%10$s %7$s%8$s日%6$s - %5$s %4$s年%2$s%3$s日–%10$s %9$s年%7$s%8$s日 - %5$s %4$s年%2$s%3$s日–%10$s %9$s年%7$s%8$s日 - %5$s %4$s年%2$s%3$s日%1$s–%10$s %9$s年%7$s%8$s日%6$s - %5$s %4$s年%2$s%3$s日%1$s–%10$s %9$s年%7$s%8$s日%6$s - %4$s年%2$s%3$s日%1$s–%9$s年%7$s%8$s日%6$s - %2$s%3$s日至%8$s日 - %2$s%3$s日%1$s–%7$s%8$s日%6$s - %9$s年%2$s%3$s日至%7$s%8$s日 - %9$s年%2$s%3$s日至%8$s日 - %9$s年%2$s%3$s日%1$s至%7$s%8$s日%6$s + %2$s %3$s 日 – %7$s %8$s 日 + %2$s %3$s 日%1$s – %7$s %8$s 日%6$s + %2$s %3$s 日 %5$s – %7$s %8$s 日 %10$s + %2$s %3$s 日 %5$s – %7$s %8$s 日 %10$s + %2$s %3$s 日 %5$s %1$s – %7$s %8$s 日 %10$s %6$s + %2$s %3$s 日 %1$s %5$s – %7$s %8$s 日 %6$s %10$s + %4$s 年 %2$s %3$s 日 %5$s – %9$s 年 %7$s %8$s 日 %10$s + %4$s 年 %2$s %3$s 日 %5$s – %9$s 年 %7$s %8$s 日 %10$s + %4$s 年 %2$s %3$s 日 %5$s %1$s – %9$s 年 %7$s %8$s 日 %10$s %6$s + %4$s 年 %2$s %3$s 日 %5$s %1$s – %9$s 年 %7$s %8$s 日 %10$s %6$s + %4$s 年 %2$s %3$s 日%1$s – %9$s 年 %7$s %8$s 日%6$s + %2$s %3$s - %8$s 日 + %2$s %3$s 日%1$s – %7$s %8$s 日%6$s + %9$s 年 %2$s %3$s 日 - %7$s %8$s 日 + %9$s 年 %2$s %3$s - %8$s 日 + %9$s 年 %2$s %3$s 日%1$s - %7$s %8$s 日%6$s %b diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 48c4d38744566..bc95c5954f27f 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -134,8 +134,6 @@ "无法访问该文件。" "找不到请求的文件。" "正在处理的请求太多,请稍后重试。" - - "同步" "同步" "太多%s删除项。" diff --git a/core/res/res/values-zh-rTW/donottranslate-cldr.xml b/core/res/res/values-zh-rTW/donottranslate-cldr.xml index 6d52d7046f998..3e1acf1202aba 100644 --- a/core/res/res/values-zh-rTW/donottranslate-cldr.xml +++ b/core/res/res/values-zh-rTW/donottranslate-cldr.xml @@ -1,57 +1,57 @@ - 一月 - 二月 - 三月 - 四月 - 五月 - 六月 - 七月 - 八月 - 九月 - 十月 - 十一月 - 十二月 + 1 月 + 2 月 + 3 月 + 4 月 + 5 月 + 6 月 + 7 月 + 8 月 + 9 月 + 10 月 + 11 月 + 12 月 - 1月 - 2月 - 3月 - 4月 - 5月 - 6月 - 7月 - 8月 - 9月 - 10月 - 11月 - 12月 + 1 月 + 2 月 + 3 月 + 4 月 + 5 月 + 6 月 + 7 月 + 8 月 + 9 月 + 10 月 + 11 月 + 12 月 - 1月 - 2月 - 3月 - 4月 - 5月 - 6月 - 7月 - 8月 - 9月 - 10月 - 11月 - 12月 + 1 月 + 2 月 + 3 月 + 4 月 + 5 月 + 6 月 + 7 月 + 8 月 + 9 月 + 10 月 + 11 月 + 12 月 - 1月 - 2月 - 3月 - 4月 - 5月 - 6月 - 7月 - 8月 - 9月 - 10月 - 11月 - 12月 + 1 月 + 2 月 + 3 月 + 4 月 + 5 月 + 6 月 + 7 月 + 8 月 + 9 月 + 10 月 + 11 月 + 12 月 星期日 星期一 @@ -92,56 +92,56 @@ 明天 %-k:%M - %p%-l:%M - %p%-l:%M - ah:mm + %p %-l:%M + %p %-l:%M + a h:mm H:mm - %Y-%-m-%-e - yyyy-M-d - "%s-%s-%s" - %Y年%-m月%-e日 - %p%I:%M:%S - %p%I:%M:%S %Y-%-m-%-e - %2$s %1$s - %1$s %3$s - %Y-%-m-%-e - %B%-e日 + %Y/%-m/%-e + yyyy/M/d + "%s/%s/%s" + %Y 年 %-m 月 %-e 日 + %p %I:%M:%S + %Y/%-m/%-e %p %I:%M:%S + %1$s %2$s + %3$s %1$s + %Y/%-m/%-e + %B %-e 日 %-B - %Y年%B - %b%-e日 + %Y 年 %B + %b %-e 日 %-b - %Y年%b - %1$s–%2$s - %2$s–%5$s - %2$s-%3$s至%7$s-%8$s - %2$s-%3$s%1$s至%7$s-%8$s%6$s - %4$s-%2$s-%3$s至%9$s-%7$s-%8$s - %4$s-%2$s-%3$s%1$s至%9$s-%7$s-%8$s%6$s - %5$s %4$s年%2$s月%3$s日,%1$s–%10$s %9$s年%7$s月%8$s日,%6$s - %5$s %2$s-%3$s–%10$s %7$s-%8$s - %5$s %2$s-%3$s%1$s–%10$s %7$s-%8$s%6$s - %5$s %4$s-%2$s-%3$s–%10$s %9$s-%7$s-%8$s - %3$s %2$s%1$s–%6$s %5$s%4$s - %2$s%1$s–%5$s%4$s - %3$s %2$s–%6$s %5$s - %1$s %3$s%2$s + %Y 年 %b + %1$s - %2$s + %2$s至 %5$s + %2$s/%3$s 至 %7$s/%8$s + %2$s/%3$s %1$s至 %7$s/%8$s %6$s + %4$s/%2$s/%3$s 至 %9$s/%7$s/%8$s + %4$s/%2$s/%3$s %1$s至 %9$s/%7$s/%8$s %6$s + %4$s 年 %2$s 月 %3$s 日%1$s %5$s 至 %9$s 年 %7$s 月 %8$s 日%6$s %10$s + %2$s/%3$s %5$s 至 %7$s/%8$s %10$s + %2$s/%3$s %1$s %5$s 至 %7$s/%8$s %6$s %10$s + %4$s/%2$s/%3$s %5$s 至 %9$s/%7$s/%8$s %10$s + %2$s%1$s %3$s 至 %5$s%4$s %6$s + %2$s%1$s至 %5$s%4$s + %2$s %3$s 至 %5$s %6$s + %3$s%2$s %1$s %3$s%2$s - %1$s %2$s - %2$s%3$s日–%7$s%8$s日 - %2$s%3$s日%1$s–%7$s%8$s日%6$s - %5$s %2$s%3$s日–%10$s %7$s%8$s日 - %5$s %2$s%3$s日–%10$s %7$s%8$s日 - %5$s %2$s%3$s日%1$s–%10$s %7$s%8$s日%6$s - %5$s %2$s%3$s日%1$s–%10$s %7$s%8$s日%6$s - %5$s %4$s年%2$s%3$s日–%10$s %9$s年%7$s%8$s日 - %5$s %4$s年%2$s%3$s日–%10$s %9$s年%7$s%8$s日 - %5$s %4$s年%2$s%3$s日%1$s–%10$s %9$s年%7$s%8$s日%6$s - %5$s %4$s年%2$s%3$s日%1$s–%10$s %9$s年%7$s%8$s日%6$s - %4$s年%2$s%3$s日%1$s–%9$s年%7$s%8$s日%6$s - %2$s%3$s日至%8$s日 - %2$s%3$s日%1$s–%7$s%8$s日%6$s - %9$s年%2$s%3$s日至%7$s%8$s日 - %9$s年%2$s%3$s日至%8$s日 - %9$s年%2$s%3$s日%1$s至%7$s%8$s日%6$s + %2$s %1$s + %2$s %3$s 日至 %7$s %8$s 日 + %2$s %3$s 日%1$s至 %7$s %8$s 日%6$s + %2$s %3$s 日 %5$s 至 %7$s %8$s 日 %10$s + %2$s %3$s 日 %5$s 至 %7$s %8$s 日 %10$s + %2$s %3$s 日%1$s %5$s 至 %7$s %8$s 日%6$s %10$s + %2$s %3$s 日%1$s %5$s 至 %7$s %8$s 日%6$s %10$s + %4$s 年 %2$s %3$s 日 %5$s 至 %9$s 年 %7$s %8$s 日 %10$s + %4$s 年 %2$s %3$s 日 %5$s 至 %9$s 年 %7$s %8$s 日 %10$s + %4$s 年 %2$s %3$s 日%1$s %5$s 至 %9$s 年 %7$s %8$s 日%6$s %10$s + %4$s 年 %2$s %3$s 日%1$s %5$s 至 %9$s 年 %7$s %8$s 日%6$s %10$s + %4$s 年 %2$s %3$s 日%1$s至 %9$s 年 %7$s %8$s 日%6$s + %2$s %3$s 日至 %8$s 日 + %2$s %3$s 日%1$s至 %7$s %8$s 日%6$s + %9$s 年 %2$s %3$s 日至 %7$s %8$s 日 + %9$s 年 %2$s %3$s 日至 %8$s 日 + %9$s 年 %2$s %3$s 日%1$s至 %7$s %8$s 日%6$s %b diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 0f9c42314d1a9..87b3ee24de389 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -111,7 +111,6 @@ "無法存取此檔案。" "找不到要求的檔案。" "太多執行要求。請稍後再試一次。" - "憑證已儲存在系統的金鑰存放區。" "同步處理" "同步處理" "同時刪除太多 %s。" diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 75568e14507f1..48b565f598781 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -827,28 +827,6 @@ - - - - - - - - - - - - - + + Too many requests are being processed. Try again later. - - The certificate is saved in the system\'s key store. @@ -911,12 +909,12 @@ you. - read phone state + read phone state and identity Allows the application to access the phone features of the device. An application with this permission can determine the phone - number of this phone, whether a call is active, the number that call is connected to - and the like. + number and serial number of this phone, whether a call is active, the number that call + is connected to and the like. prevent phone from sleeping diff --git a/data/sounds/AudioPackage2.mk b/data/sounds/AudioPackage2.mk index 649787efc5115..5dacc70bc9034 100644 --- a/data/sounds/AudioPackage2.mk +++ b/data/sounds/AudioPackage2.mk @@ -23,7 +23,6 @@ PRODUCT_COPY_FILES += \ $(LOCAL_PATH)/Ring_Digital_02.ogg:system/media/audio/ringtones/Ring_Digital_02.ogg \ $(LOCAL_PATH)/Ring_Synth_04.ogg:system/media/audio/ringtones/Ring_Synth_04.ogg \ $(LOCAL_PATH)/Ring_Synth_02.ogg:system/media/audio/ringtones/Ring_Synth_02.ogg \ - $(LOCAL_PATH)/Silence.ogg:system/media/audio/ringtones/notifications/Silence.ogg \ $(LOCAL_PATH)/newwavelabs/BeatPlucker.ogg:system/media/audio/ringtones/BeatPlucker.ogg \ $(LOCAL_PATH)/newwavelabs/BentleyDubs.ogg:system/media/audio/ringtones/BentleyDubs.ogg \ $(LOCAL_PATH)/newwavelabs/BirdLoop.ogg:system/media/audio/ringtones/BirdLoop.ogg \ diff --git a/data/sounds/OriginalAudio.mk b/data/sounds/OriginalAudio.mk index fc1e92109cac0..291f0b6b997e1 100644 --- a/data/sounds/OriginalAudio.mk +++ b/data/sounds/OriginalAudio.mk @@ -22,7 +22,6 @@ PRODUCT_COPY_FILES += \ $(LOCAL_PATH)/Ring_Digital_02.ogg:system/media/audio/ringtones/Ring_Digital_02.ogg \ $(LOCAL_PATH)/Ring_Synth_04.ogg:system/media/audio/ringtones/Ring_Synth_04.ogg \ $(LOCAL_PATH)/Ring_Synth_02.ogg:system/media/audio/ringtones/Ring_Synth_02.ogg \ - $(LOCAL_PATH)/Silence.ogg:system/media/audio/ringtones/notifications/Silence.ogg \ $(LOCAL_PATH)/newwavelabs/BeatPlucker.ogg:system/media/audio/ringtones/BeatPlucker.ogg \ $(LOCAL_PATH)/newwavelabs/BentleyDubs.ogg:system/media/audio/ringtones/BentleyDubs.ogg \ $(LOCAL_PATH)/newwavelabs/BirdLoop.ogg:system/media/audio/ringtones/BirdLoop.ogg \ diff --git a/data/sounds/Silence.ogg b/data/sounds/Silence.ogg deleted file mode 100644 index 6d789071a525fd1a43d947e8cf87ecd3945d35d2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3973 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 JH{|OF?LW!~Bxe8s diff --git a/docs/html/community/index.jd b/docs/html/community/index.jd index 91c54aab0dda7..eb5887a23e58f 100644 --- a/docs/html/community/index.jd +++ b/docs/html/community/index.jd @@ -9,7 +9,7 @@ page.title=Community

Note: If you are seeking discussion about Android source code (not application development), then please refer to the Open Source Project Mailing lists.

-

Contents

+

Contents

  1. Before you post
  2. Application developer mailing lists
  3. diff --git a/docs/html/guide/developing/device.jd b/docs/html/guide/developing/device.jd index 35c0a1ae0c522..805167826a7d5 100644 --- a/docs/html/guide/developing/device.jd +++ b/docs/html/guide/developing/device.jd @@ -137,7 +137,7 @@ would on the emulator. There are just a few things to do before you can start.If you're developing on Mac OS X, it just works. Skip this step.
  4. If you're developing on Ubuntu Linux, you need to add a rules file:
      -
    1. Login as root and create this file: /etc/udev/rules.d/50-android.rules. +
    2. Login as root and create this file: /etc/udev/rules.d/51-android.rules.

      For Gusty/Hardy, edit the file to read:
      SUBSYSTEM=="usb", SYSFS{idVendor}=="0bb4", MODE="0666"

      diff --git a/docs/html/guide/guide_toc.cs b/docs/html/guide/guide_toc.cs index da4a2c33c5cfe..21271872739dd 100644 --- a/docs/html/guide/guide_toc.cs +++ b/docs/html/guide/guide_toc.cs @@ -1,84 +1,175 @@ + diff --git a/docs/html/guide/practices/ui_guidelines/icon_design.jd b/docs/html/guide/practices/ui_guidelines/icon_design.jd index 155684a25b935..5f0a278bed92d 100644 --- a/docs/html/guide/practices/ui_guidelines/icon_design.jd +++ b/docs/html/guide/practices/ui_guidelines/icon_design.jd @@ -25,7 +25,7 @@ application can use the standard icons by referencing them as resources.
    3. General guidelines
    4. Using the Icon Templates Pack
    5. -
    6. Icon appendix +
    7. Icon appendix
      1. Launcher icons
      2. Menu icons
      3. @@ -989,25 +989,9 @@ simply look at image filenames, which use the format - - - - - - - - - - - - - - + - + + + - - - - - - - - - - - - - - - - - - @@ -1094,14 +1049,6 @@ simply look at image filenames, which use the format - - - - - - - - - + + - - - @@ -1138,9 +1077,6 @@ simply look at image filenames, which use the format Android asset
        Save
        - - - - - - - + + + - - - - - - + + + + + + diff --git a/docs/html/sdk/preview/features.html b/docs/html/sdk/preview/features.html deleted file mode 100644 index a2f085cdce342..0000000000000 --- a/docs/html/sdk/preview/features.html +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Redirecting... - - - - - - - -
        Android asset
        Add
        - Android asset -
        Archive
        - Android asset -
        Attach
        - Android asset -
        Back
        @@ -1024,9 +1008,6 @@ simply look at image filenames, which use the format Android asset
        Clear / Close / Cancel / Discard
        Android asset @@ -1036,56 +1017,30 @@ simply look at image filenames, which use the format Android asset
        Delete
        Android asset
        Directions
        Android asset
        Edit
        - Android asset -
        Favorite
        - Android asset -
        Forward
        Android asset
        Gallery
        - Android asset -
        Go to
        Android asset
        Help
        - Android asset -
        History
        - Android asset -
        Home
        Android asset
        Info / details
        Android asset
        Map mode
        - Android asset -
        Mark
        @@ -1113,22 +1060,14 @@ simply look at image filenames, which use the format Android asset
        More
        - Android asset -
        Play
        Android asset
        Preferences
        - Android asset -
        Refresh
        Android asset
        Rotate
        Android asset @@ -1157,27 +1093,16 @@ simply look at image filenames, which use the format
        Share
        - Android asset -
        Shuffle
        Android asset
        Upload
        Android asset
        View
        - Android asset -
        Video
        @@ -1213,131 +1138,21 @@ or simply look at the image filename, which use the format - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1348,32 +1163,6 @@ or simply look at the image filename, which use the format
        Warning
        - - - - - - - - - - - - - - - - @@ -1383,19 +1172,14 @@ or simply look at the image filename, which use the format Android asset
        Call forward
        + + - - - - - diff --git a/docs/html/guide/practices/ui_guidelines/index.jd b/docs/html/guide/practices/ui_guidelines/index.jd index 0b9d2754d21a3..2d14fa6bc9869 100644 --- a/docs/html/guide/practices/ui_guidelines/index.jd +++ b/docs/html/guide/practices/ui_guidelines/index.jd @@ -38,6 +38,14 @@ graphics files and templates that will make your designer's life easier. describes important underlying principles and mechanisms, such as multitasking, activity reuse, intents, the activity stack, and tasks. It covers this all from a high-level design perspective. + +
        Menu Design Guidelines
        +
        Android applications make use of Option menus and Context menus + that enable users to perform operations and navigate to other parts + of your application or to other applications. These guidelines describe + the difference between Options and Context menus, how to arrange + menu items, when to put commands on-screen, and other details about + menu design.
        diff --git a/docs/html/guide/practices/ui_guidelines/menu_design.jd b/docs/html/guide/practices/ui_guidelines/menu_design.jd new file mode 100644 index 0000000000000..518cea139cd52 --- /dev/null +++ b/docs/html/guide/practices/ui_guidelines/menu_design.jd @@ -0,0 +1,507 @@ +page.title=Menu Design Guidelines +@jd:body + +
        +
        + +

        Menu design quickview

        + +
          +
        • An Options menu is for any commands that are global to the current activity.
        • +
        • A Context menu is for any commands that apply to the current selection.
        • +
        • Place the most frequently used operations first.
        • +
        • Put only the most important commands fixed on the screen.
        • +
        • The commands on the Context menu that appears when you touch & hold on an item should be duplicated on the activity you get to by a normal press on that item. +
        + + +

        In this document

        + +
          +
        1. Tour of the Menus +
            +
          1. Options Menu
          2. +
          3. Context Menu
          4. +
          5. Comparison of Options & Context Menus
          6. +
          7. Commands Fixed in an Activity Screen
          8. +
          +
        2. +
        3. Guidelines +
            +
          1. Separate specific from global commands
          2. +
          3. Place most frequently used first
          4. +
          5. Don't put commands only in a Context menu
          6. +
          7. First command in Context menu should be most intuitive
          8. +
          9. Selecting an item should perform most intuitive operation
          10. +
          11. A Context menu should identify the selected item
          12. +
          13. Put only most important commands fixed on the screen
          14. +
          15. Use short names in Options icon menu
          16. +
          17. A dialog should not have Options menu
          18. +
          19. If no Options menu, don't display message
          20. +
          21. Dim or hide menu items not available
          22. +
          +
        4. +
        + +

        See also

        + +
          +
        1. Touch mode
        2. +
        3. Activity and Task Design
        4. +
        + +
        +
        + +

        + A menu holds a set of commands (user actions) that are normally hidden, and + are accessible by a button, key, or gesture. Menu commands provide a means + for performing operations and for navigating to other parts of your + application or other applications. Menus are useful for freeing screen space, + as an alternative to placing functionality and navigation, in buttons or other + user controls in the content area of your application. +

        + +

        + The Android system provides two types of menus you can use to provide + functionality or navigation. Between them, you should be able to organize + the functionality and navigation for your application. Briefly: +

          +
        • The Options menu contains primary functionality that applies + globally to the current activity or starts a related activity. + It is typically invoked by a user pressing a hard button, often labeled MENU.
        • +
        • The Context menu contains secondary functionality for the currently + selected item. It is typically invoked by a user's touch & hold + on an item. Like on the Options menu, the operation can run either + in the current or another activity.
        • +
        +

        + +

        + All but the simplest applications have menus. The system automatically + lays the menus out and provides standard ways for users to access them. + In this sense, they are familiar and dependable ways for users to access + functionality across all applications. All menus are panels that "float" + on top of the activity screen and are smaller than full screen, so that the + application is still visible around its edges. This is a visual reminder + that a menu is an intermediary operation that disappears once it's used. +

        + +

        + Let's start out with a quick tour of the menus. +

        + +

        Tour of the Menus

        + +
        + NOTE - Your menus and screens might not look like those shown in this document; + they may vary from one version of Android or device to another. +
        + +

        Options Menu

        + +

        + The Options menu contains commands that apply globally across the current + activity, or can start another activity. They do not apply to a selected + item in the content (a Context menu does that). +

        + +

        + On most devices, a user presses the MENU button to access the Options menu, + as shown in the screenshot below. To close the menu, the user presses + MENU again, or presses the BACK button. + In fact, to cancel out of any menu, press the BACK button. (Pressing the MENU + button or touching outside the menu also works.) Note that how to invoke this + menu may be different on different devices. +

        + +

        + Each + activity + activity has its own set of operations and therefore its own Options menu. + An application with multiple activities would have a different Options menu + for each activity. +

        + +

        + For example, in the message list view of an email program, the Options menu + might let you search the messages, compose a new message, refresh the list, + or change the email settings. The compose view of an email program would + have a different Options menu, such as adding a CC field, attaching a file, + or discarding the message. +

        + +

        + In order to handle a large number of menu items, the Options menu + progressively discloses them in two steps: +

        + +
          +
        • + Options icon menu - The first press of the MENU button displays a + non-scrollable grid of icons at the bottom of the screen. (On the G1 + phone, up to 6 buttons typically appear.) +
        • +
        • + Options expanded menu - If the activity has more menu items than will + fit on the icon menu, then the last icon is labeled "More" — selecting it + displays a list that can contain any number of menu items and will scroll + as necessary. +
        • +
        + + + +

        + On some versions of Android, the user can display keyboard shortcuts in the + icon menu by long pressing the MENU button — the text in the icon menu + alternates between the command names and their keyboard shortcuts (if any). +

        + +

        Context Menu

        + +

        + A Context menu is similar to a right-click context menu in a desktop + operating system. It is normally a shortcut that duplicates commands + found elsewhere. +

        + +

        + A user can touch & hold on content on the screen to + access a Context menu (if one exists), as shown in the screenshot below. + A Context menu is a list of menu items (commands) that can operate + on the selected content. The command can either be part of the current + activity, or the system can pass the selected content along to + an operation in another activity (by way of an + intent). +

        + +

        + For example, in an email message list, a user can touch & hold on + an email message to open a Context menu containing commands to read, + archive, or delete the message. +

        + +

        + A user can also touch & hold a location on the screen to + access a Context menu. An example is when the user does touch & hold + on a blank spot on the Home screen, a Context menu appears; selecting + an item from that menu inserts an icon at that location. +

        + + + +

        Context Menu is a Shortcut

        + +

        + In the above example, if the user performs touch & hold on the contact + "Obi Wan Kenobi", a Context menu opens. The commands provided in + this Context menu are the complete set of actions that can be performed + on this contact. +

        + +

        + A normal touch on an item in the content activates the most intuitive + command for that selection — in this case, "View contact". + We recommend that the most intuitive command also be listed as the + first item in the Context menu. In this example, selecting the contact + "Obi Wan Kenobi" runs the same command "View contact" that is listed + at the top of the Context menu. +

        + +

        + Also note, as shown in the following screenshot, the Context menu and the + next screen both hold the same complete set of commands that can be performed + on this contact. The Context menu displays the commands in a list, + while the "View contact" activity splits them into various items in the + Options menu, icon buttons and list items. +

        + +

        + Because of this duplication, using the Context menu is considered a shortcut + for going to the next screen and performing the operation there. Context menus + are less discoverable than either buttons fixed on-screen or the Options menu. + Many users never discover or use Context menus. It is for this reason that, for + the most part, any command on a Context menu should also appear on the most + intuitive operation's screen. As the next section explains, text operations, + such as "Select text" might appear only on a Context menu. Also, rich + applications, such as browsers, which themselves can contain web applications, + may have commands on Context menus that are not available elsewhere. +

        + + + +

        Text Commands in Context Menu

        + +

        + Text links and text fields in the content both have system-provided operations + that are common across all applications: operations such as "Select all", "Select text", + "Copy all", and "Add to dictionary". If the text field is editable, it also + has other operations, such as "Cut all" and "Input Method", and if text + is also on the clipboard, it has "Paste". The system automatically inserts + the appropriate menu items into the Context menu of text links and text + fields, as shown in the following screenshot. +

        + + + + +

        Comparison of Options and Context Menus

        + +

        + An Options menu holds commands that are global to the activity while a + Context menu holds commands that apply only to an item in the content. + As shown in these diagrams, the user navigates to the menu, then + touches a menu item to perform an action or open a dialog. +

        + + + +

        + For more technical information on menus, see + Creating Menus. +

        + +

        Commands Fixed in an Activity Screen

        + +

        + Commands can also be fixed directly on screen, typically in + text buttons, graphic buttons, or list items. This placement is by far the most + discoverable location for commands — a user can immediately see the command + without having to first press a button. This increased visibility needs to be + weighed against the space such user controls take up, or the sense that they + might clutter the visual design. +

        + +

        Guidelines

        + +

        + Selecting the right kind of menu to present, and using menus + consistently, are critical factors in good application design. The following + guidelines should assist user experience designers and application developers + toward this end. +

        + +

        Separate selection-specific commands from global commands

        + +

        + Put any commands that are global to the current activity in the Options menu + or place them fixed in an activity screen; put commands that apply to the + current selection in the Context menu. (In any case, the command + could either run as part of this activity or start another activity.) +

        + +

        + You can determine in which menu to place a command by what it operates on: + If the command acts on selected content (or a particular + location) on the screen, put the command in the + Context menu for that content. If the command acts on no specific content + or location, put it in the Options menu. This separation of commands + is enforced by the system in the following way. When you press the MENU + button to display the Options menu, the selected content becomes unselected, + and so cannot be operated on. For an explanation + of why the content becomes unselected, see the article on + Touch mode. +

        + +

        + An example of a selection-specific Context menu is when a user performs a + touch & hold on a person's name in a list view of a contacts application. + The Context menu would typically contain commands "View contact", "Call contact", + and "Edit contact". +

        + +

        Place the most frequently used operations first

        + +

        + Because of limited screen height, some menus may be scrollable, so it's + important to place the most important commands so they can be viewed without + scrolling. In the case of the Options menu, place the most frequently used + operation on its icon menu; + the user will have to select "More" to see the rest. + It's also useful to place similar commands in the same location — + for example, the Search icon might always be the first icon in the Options + menu across several activities that offer search. +

        + +

        + In a Context menu, the most intuitive command should be first, followed + by commands in order of decreasing use, with the least used command at the bottom. +

        + +

        Don't put commands only in a Context menu

        +

        + If a user can fully access your application without using Context menus, + then it's designed properly! In general, if part of your application is inaccessible + without using Context menus, then you need to duplicate those commands elsewhere. +

        + +

        + Before opening a Context menu, it has no visual representation that identifies + its presence (whereas the Options menu has the MENU button), and so is not + particularly discoverable. + Therefore, in general, a Context menu should duplicate commands + found in the corresponding activity screen. For example, while it's useful to + let the user call a phone number from a Context menu invoked by touch + & hold on a name in a list of contacts, that operation should also + be available by the user touching the phone number itself when viewing contact details. + See shortcut for an illustration of this example. +

        + +

        The first command in a Context menu should be the selection's most intuitive command

        + +

        + As described under shortcut, + touching on an item in the content should activate the same command as touching + the first item in the Context menu. Both cases should be the most intuitive + operation for that item. +

        + +

        Selecting an item in the content should perform the most intuitive operation

        + +

        + In your application, when the user touches any actionable text (such as a link + or list item) or image (such as a photo icon), execute the operation most + likely to be desired by the user. +

        + +

        + Some examples of primary operations: +

        + +
          +
        • Selecting an image executes "View image"
        • +
        • Selecting a media icon or filename executes "Play"
        • +
        • Selecting a URL link executes "Open link"
        • +
        • Selecting an address executes "Go to address" (in a maps application)
        • +
        + +

        + Note that selecting the same item in different contexts might invoke + different operations: +

        + +
          +
        • In a contact application, selecting a contact executes "View details"
        • +
        • In an IM application, selecting a contact executes "Start chat"
        • +
        • In an Email application, when adding a recipient to the "To" field + through the contact book, selecting a contact executes "Add to recipient + list"
        • +
        + + +

        A Context menu should identify the selected item

        + +

        + When a user does touch & hold on an item, the Context menu should + contain the name of the selected item. Therefore, + when creating a Context menu, be sure to include a title and the name of the + selected item so that it's clear to the user what the context is. + For example, if a user selects a contact "Joan of Arc", put that name in the + title of the Context menu (using + {@link android.view.ContextMenu#setHeaderTitle(java.lang.CharSequence) setHeaderTitle}). + Likewise, a command to edit the contact should be called "Edit contact", + not just "Edit". +

        + + +

        Put only the most important commands fixed on the screen

        + +

        + By putting commands in menus, you free up the screen to hold more content. + On the other hand, fixing commands in the content area of an activity + makes them more prominent and easy to use. +

        + +

        + Here are a number of important reasons to place commands fixed on the activity screen: +

        + +
          +
        • + To give a command the highest prominence, ensuring the command is obvious and won't be overlooked.
          + Example: A "Buy" button in a store application. +
        • +
        • + When quick access to the command is important and going to the menu would be + tedious or slow.
          + Example: Next/Previous buttons or Zoom In/Out buttons in an image viewing application. +
        • +
        • + When in the middle of an operation that needs to be completed.
          + Example: Save/Discard buttons in an image crop activity. +
        • +
        • + Dialogs and wizards.
          + Example: OK/Cancel buttons +
        • +
        • + For direct manipulation.
          + Example: Dragging an icon in the Home screen to the trash +
        • +
        + +

        Use short names in the Options icon menu

        + +

        + If a text label in the Options icon menu + is too long, the system truncates it in the middle. Thus, "Create Notification" + is truncated to something like "Create…ication". You have no control over + this truncation, so the best bet is to keep the text short. In some versions of Android, + when the icon is highlighted by a navigation key (such as a trackball), the + entire descriptive text may be shown as a marquee, where the words are + readable as they scroll by. +

        + +

        A dialog should not have an Options menu

        + +

        + When a dialog is displayed, pressing the MENU button should do nothing. This also holds true + for activities that look like dialogs. A dialog box is recognizable by being + smaller than full-screen, having zero to three buttons, is non-scrollable, and + possibly a list of selectable items that can include checkboxes or radio buttons. + +

        + +

        + The rationale behind not having a menu is that when a dialog is displayed, the user is in + the middle of a procedure and should not be allowed to start a new global task + (which is what the Option menu provides). +

        + +

        If an activity has no Options menu, do not display a message

        + +

        + When the user presses the MENU button, if there is no Options menu, the system + currently does nothing. We recommend you do not perform any action (such as + displaying a message). It's a better user experience for this behavior to be + consistent across applications. +

        + + + +

        Dim or hide menu items that are not available in the current context

        + +

        + Sometimes a menu item's action cannot be performed — for example, + the "Forward" button in a browser cannot work until after the "Back" + button has been pressed. We recommend: +

        + +
          +
        • + In Options menu - disable the menu item, which dims the text and icon, + turning it gray. This applies to menu items in both the icon menu and the + "More" menu. It would be disorienting for the icon menu to change from 6 + items to 5 items, and we treat the "More" menu the same way. +
        • +
        • + In Context menu - hide the menu item. This makes the menu shorter so the + user sees only available choices (which also reduces any scrolling). +
        • +
        + + + + diff --git a/docs/html/guide/topics/appwidgets/index.jd b/docs/html/guide/topics/appwidgets/index.jd index 01a96484e4183..fc0061d5ae92a 100644 --- a/docs/html/guide/topics/appwidgets/index.jd +++ b/docs/html/guide/topics/appwidgets/index.jd @@ -150,14 +150,26 @@ folder.

        (number of cells * 74) - 2
        Following this formula, you should use 72 dp for a height of one cell, 294 dp and for a width of four cells.

        -
      4. The updatePerdiodMillis attribute defines how often the App Widget framework should +
      5. The updatePeriodMillis attribute defines how often the App Widget framework should request an update from the {@link android.appwidget.AppWidgetProvider} by calling the {@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[]) onUpdate()} method. The actual update is not guaranteed to occur exactly on time with this value and we suggest updating as infrequently as possible—perhaps no more than once an hour to conserve the battery. You might also allow the user to adjust the frequency in a configuration—some people might want a stock ticker to update every 15 minutes, or maybe - only four times a day.
      6. + only four times a day. +

        Note: If the device is asleep when it is time for an update + (as defined by updatePeriodMillis), then the device will wake up in order + to perform the update. If you don't update more than once per hour, this probably won't + cause significant problems for the battery life. If, however, you need to update more + frequently and/or you do not need to update while the device is asleep, then you can instead + perform updates based on an alarm that will not wake the device. To do so, set an alarm with + an Intent that your AppWidgetProvider receives, using the {@link android.app.AlarmManager}. + Set the alarm type to either {@link android.app.AlarmManager#ELAPSED_REALTIME} or + {@link android.app.AlarmManager#RTC}, which will only + deliver the alarm when the device is awake. Then set updatePeriodMillis to + zero ("0").

        +
      7. The initialLayout attribute points to the layout resource that defines the App Widget layout.
      8. The configure attribute defines the {@link android.app.Activity} to launch when diff --git a/docs/html/guide/topics/resources/resources-i18n.jd b/docs/html/guide/topics/resources/resources-i18n.jd index c26cb63df82d4..85b89d1c409c5 100755 --- a/docs/html/guide/topics/resources/resources-i18n.jd +++ b/docs/html/guide/topics/resources/resources-i18n.jd @@ -465,37 +465,37 @@ MyApp/
      9. - + resources can only be used if both the MCC and the MNC match.

        - + for example en, fr, es.

        - - - - @@ -565,9 +566,9 @@ MyApp/ - + diff --git a/docs/html/images/menu_design/ContextMenuDiagram.png b/docs/html/images/menu_design/ContextMenuDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..06678c75984225435cbdd01573191fbf0a45a709 GIT binary patch literal 79806 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 @@ -120,10 +120,19 @@ home=true 'sdk': { 'layout':"imgLeft", 'icon':"sdk-small.png", - 'name':"SDK 1.5 r2", + 'name':"SDK 1.5 r3", 'img':"sdk-large.png", 'title':"Android 1.5 SDK", - 'desc': "

        Android 1.5 SDK is now available. It includes new APIs for Android 1.5, updated developer tools, multiple platform versions, and a Google APIs add-on.

        Download Android 1.5 SDK

        " + 'desc': "

        Android 1.5 SDK is now available. It includes new APIs for Android 1.5, updated developer tools, multiple platform versions, and a Google APIs add-on.

        Download Android 1.5 SDK »

        " + }, + + 'io': { + 'layout':"imgLeft", + 'icon':"io-small.png", + 'name':"Google I/O", + 'img':"io-large.png", + 'title':"Google I/O Developer Conference", + 'desc': "

        The Google I/O developer conference took place May 27-28 in San Francisco. If you missed the conference, you can experience the Android sessions by viewing YouTube videos.

        See the sessions from Google I/O »

        " }, 'mapskey': { @@ -135,15 +144,6 @@ home=true 'desc':"

        If you're writing an Android application that uses Google Maps (with MapView), you must register your application to obtain a Maps API Key. Without the key, your maps application will not work on Android devices. Obtaining a key requires just a couple of steps.

        Learn more »

        " }, - 'market': { - 'layout':"imgTop", - 'icon':"market-small.png", - 'name':"Android Market", - 'img':"market-large.png", - 'title':"", - 'desc': "

        Android Market helps you get your applications into the hands of users. The beta version of Market is now open and you can begin sharing your applications with users of the first Android-powered phone, the T-Mobile G1.

        Publish your Android app on Market »

        " - }, - 'devphone': { 'layout':"imgLeft", 'icon':"devphone-small.png", diff --git a/docs/html/intl/ja/community/index.jd b/docs/html/intl/ja/community/index.jd new file mode 100644 index 0000000000000..e0a645b2280cd --- /dev/null +++ b/docs/html/intl/ja/community/index.jd @@ -0,0 +1,108 @@ +community=true +page.title=コミュニティ +@jd:body + +
        +

        コミュニティ

        +

        Android デベロッパー コミュニティへようこそ。コミュニティでのディスカッションにぜひ参加してください。投稿する前に、コミュニティ ガイドラインが記載されているグループの趣意をお読みください。

        + +

        注: Android ソース コード(アプリケーション開発ではなく)に関するディスカッションは、オープンソース プロジェクトのメーリング リスト(英語)を参照してください。

        + +

        目次

        +
          +
        1. 質問を投稿する前に
        2. +
        3. アプリケーション デベロッパー メーリング リスト
        4. +
        5. メーリング リストにメールを使用
        6. +
        7. IRC の使用
        8. +
        + +

        質問を投稿する前に

        +

        投稿を作成する前に、下記をお試しください:

        + +
          +
        1. よくある質問を参照します。Android アプリケーションの開発について非常に一般的な質問が、この一覧に記載されており、頻繁に更新されています。
        2. +
        3. Android のメイン サイトの検索バー(このページの上部にあるのと同じもの)に、調べたいキーワードを入力してください。この検索は、サイト、ドキュメント、ブログに含まれるすべてのコンテンツの他に、すべてのグループで以前行われたすべてのディスカッションを網羅しています。誰か他の人が、以前にも同じ問題に遭遇した可能性は大いにあります。
        4. +
        5. メーリング リストのアーカイブを検索して、同じ質問に関するディスカッションが既に存在しないか調べてください。 +
        6. +
        + +

        質問への答えが見つからない場合、コミュニティで質問することをおすすめします。投稿する際は、次の手順に従ってください。 +

          +
        1. コミュニティ ガイドラインが記載されているAndroid メーリングリストの趣意をお読みください。 +
        2. +
        3. 質問に最適なメーリング リストを選択してください。後述するように、デベロッパー向けのメーリング リストは何種類かに分かれています。
        4. +
        5. + 質問の内容を明確に。明確な質問は、回答者と、将来情報を探そうとする人の双方にとって有益です。
        6. +
        7. 投稿は詳しく書いてください。回答者の人たちが問題を理解するのに役立ちます。コードやログのスニペット、スクリーンショットへのリンクを含めることも有用です。質問をわかりやすく表現するための詳しいガイドラインは、賢い質問のしかた(英語)をご覧ください。 +
        8. +
        + + +

        アプリケーション デベロッパー メーリング リスト

        +
          +
        • Android 初心者向け - Android アプリケーションの開発初心者向けです。Android SDK と基本的な Android API の利用方法について学習したい場合は、このメーリング リストから始めてください。このメーリング リストには、SDK を利用するデベロッパーの初歩的なディスカッションの場所です。Android プラットフォームで初めてアプリケーションを作成して実行する際は、非常に有益な情報を得ることができるでしょう。開発環境のインストール方法についての質問を投稿したり、Android 開発の初歩(初めて作成するユーザー インターフェース、権限、Android ファイルシステムでのファイル、Android マーケットでのアプリケーションなど)について教えてもらうことができます。新たに質問する前に、必ず最初にアーカイブを確認してください。高度な内容の質問の場合はここでは質問せず、android-developers メーリング リストで質問してください。また使用に関する質問は、android-discuss メーリング リストの方が適しています。 + +
        • + +
        • Android デベロッパー向け - Android アプリケーション デベロッパーとして経験を積むにつれ、Android アプリケーション開発の基本を把握して、SDK を使いこなせるようになります。今度は、より高度な内容について質問する必要があります。アプリケーションのトラブルシューティング、実装へのアドバイス、アプリケーションのパフォーマンスやユーザー エクスペリエンスを改良するテクニックに関する質問には、次のメーリング リストが役立ちます。使用に関する問題(android-discuss をご利用ください)や、Android SDK を使用する際の初歩的質問(android-beginners をご利用ください)についてのディスカッションの場所ではありません。 + +
        • + +
        • Android ディスカッション - Android に関する「井戸端会議」です。ここでは、Android プラットフォームへのアイデア、自分のアプリケーションの公表、Android 携帯端末に関するディスカッション、コミュニティ リソースなど、Android に関することなら何でも投稿可能です。ただし他のメーリング リストに該当する内容の場合は、そのメーリング リストに投稿することをおすすめします。質問のテーマが限定されている場所の方が、より多くの回答を得ることができるでしょう。 + +
        • + +
        • Android セキュリティ ディスカッション - 安全な開発、新たに発生したセキュリティの問題、Android デベロッパー向けの Android デベロッパーによるベスト プラクティスについて自由にディスカッションを行える場所です。メーリング リストで脆弱性を直接公開することは、すべての Android ユーザーを危険にさらすことになるので、避けてください。 + +
        • + +
        • Android セキュリティに関する発表 - Android セキュリティ チームがセキュリティ関連の発表を行う、小規模なグループです。 + +
        • + +
        • Android マーケット ヘルプフォーラム - Android マーケットに関する質問や問題の報告をするための、ウェブベースのディスカッション フォーラムです。 + +
        • + +
        + + + +

        メーリング リストにメールを使用

        +

        Google グループ のサイトを使用する代わりに、メール クライアントを使用して、メーリング リストに投稿することも可能です。

        +

        Google グループのサイトを使用せずに、グループに登録するには、上記の「メールで登録」のリンクを使用します。

        +

        メーリング リストへの投稿をメールで受信するように設定する方法は、次のとおりです:

        + +
        1. Google グループ サイトから、グループにログインします。たとえば android-framework グループには http://groups.google.com/group/android-framework?hl=ja にアクセスします。
        2. +
        3. 右側の [メンバーステータスを編集] をクリックします。
        4. +
        5. [このグループの閲覧方法] で、メール オプションのいずれかを選択します。
        6. +
        + +

        IRC の使用

        +

        Android コミュニティは irc.freenode.net サーバーの #android チャンネルを使用しています。 +

        + + + + + + + +
        diff --git a/docs/html/intl/ja/guide/basics/what-is-android.jd b/docs/html/intl/ja/guide/basics/what-is-android.jd new file mode 100644 index 0000000000000..89558a0046ff2 --- /dev/null +++ b/docs/html/intl/ja/guide/basics/what-is-android.jd @@ -0,0 +1,81 @@ +page.title=Android とは +@jd:body + +

        Android は、オペレーティング システム、ミドルウェア、主要なアプリケーションを含む、携帯電話向けのソフトウェア スタックです。Android SDK は、Java プログラミング言語を使用した Android プラットフォーム向けのアプリケーションの開発を始めるのに必要なツールと API を提供します。

        + +

        特長

        + +
          +
        • コンポーネントの再利用と置換が可能なアプリケーション フレームワーク
        • +
        • 携帯電話用に最適化された Dalvik 仮想マシン
        • +
        • オープンソース WebKit エンジンをベースにした統合ブラウザ
        • +
        • カスタム 2D グラフィックス ライブラリと OpenGL ES 1.0 仕様に基づいた 3D グラフィックスにより提供される最適化されたグラフィックス(オプションのハードウェア アクセラレーション)
        • +
        • SQLite による構造化データ ストレージ
        • +
        • 音声、映像、静止画の一般的なフォーマット(MPEG4、H.264、MP3、AAC、AMR、JPG、PNG、GIF)に対するメディア サポート
        • +
        • GSM テレフォニー機能(ハードウェアに依存)
        • +
        • Bluetooth、EDGE、3G、WiFi(ハードウェアに依存)
        • +
        • カメラ、GPS、コンパス、加速度計(ハードウェアに依存)
        • +
        • デバイス エミュレータ、デバッグ用ツール、メモリとパフォーマンスの分析、Eclipse IDE 用プラグインを含む機能の豊富な開発環境
        • +
        + + +

        Android アーキテクチャ

        + +

        Android オペレーティング システムの主なコンポーネントを次の図に示します。それぞれのセクションには、各コンポーネントの詳細が記述されています。

        + +

        Android システム アーキテクチャ

        + + +

        アプリケーション

        + +

        Android には、メール クライアント、SMS プログラム、カレンダー、地図、ブラウザ、連絡先などのコア アプリケーションのセットが付属しています。アプリケーションはすべて Java プログラミング言語で作成されています。

        + + +

        アプリケーション フレームワーク

        + +

        デベロッパーは、コア アプリケーションによって使用されるフレームワーク API のすべてにアクセスできます。アプリケーション アーキテクチャは、コンポーネントの再利用を容易にするように設計されています。このため、どのアプリケーションも機能を公開し、別のアプリケーションがその機能を使用することが可能です(ただし、フレームワークによって実施されるセキュリティ制限の対象となります)。このメカニズムによって、ユーザーによるコンポーネントの入れ替えも可能です。

        + +

        アプリケーションの基盤となるのは、次のサービスとシステムのセットです: +

          +
        • アプリケーションの構築を可能にする、拡張可能で豊富なビューのセット。ビューには、リスト、グリッド、テキスト ボックス、ボタンだけでなく、埋め込み可能なウェブブラウザも含まれます。
        • +
        • コンテンツ プロバイダを使用すると、アプリケーションのデータ(たとえば、連絡先アプリケーション)に、別のアプリケーションからアクセスしたり、データを共有させることができます。
        • リソース マネージャは、ローカライズされた文字列、グラフィックス、レイアウト ファイルなどのコード以外のリソースへのアクセスを提供します。
        • +
        • {@link android.app.NotificationManager 通知マネージャ}を使用すると、すべてのアプリケーションからステータス バーにカスタマイズした警告を表示することができます。
        • +
        • {@link android.app.Activity アクティビティ マネージャ}は、アプリケーションのライフサイクルを管理し、共通のナビゲーション バックスタックを提供します。
        • +
        + +

        アプリケーションの簡単な説明と詳細については、Notepad チュートリアルをご覧ください。

        + + +

        ライブラリ

        + +

        Android には C/C++ ライブラリのセットが含まれており、Android システムのさまざまなコンポーネントにおいて使用されています。これらの機能は、Android アプリケーション フレームワークを介して、デベロッパーに公開されています。コア ライブラリの一部を次に示します:

        +
          +
        • システム C ライブラリ - BSD による実装をベースにした標準の C システム ライブラリ(libc)です。埋め込み Linux ベースのデバイス用に最適化されています。
        • +
        • メディア ライブラリ - PacketVideo の OpenCORE をベースにしたライブラリです。MPEG4、H.264、MP3、AAC、AMR、JPG、PNG などの多くの一般的な映像と音声のフォーマットと、静止画ファイルの再生と記録をサポートしています。
        • +
        • サーフェス マネージャ - 表示サブシステムへのアクセスを管理し、複数のアプリケーションからの 2D と 3D のグラフィック レイヤーをシームレスに合成します。
        • +
        • LibWebCore - 最新式のウェブブラウザ エンジンで、Android ブラウザと埋め込み可能な Web 表示の両方を提供します。
        • +
        • SGL - ベースとなる 2D グラフィックス エンジンです。
        • +
        • 3D ライブラリ - OpenGL ES 1.0 API をベースとして実装されたライブラリです。ハードウェア 3D アクセラレーション(可能な場合)か、高度に最適化された埋め込みの 3D ソフトウェア ラスタライザのいずれかを使用します。
        • +
        • FreeType - ビットマップ フォントやベクタ フォントのレンダリングを行います。
        • +
        • SQLite - すべてのアプリケーションで利用可能な強力で軽量のリレーショナル データベース エンジンです。
        • +
        + + + +

        Android ランタイム

        + +

        Android には、Java プログラミング言語のコア ライブラリで利用できる機能のほとんどを提供するコア ライブラリのセットが含まれています。

        + +

        Android の各アプリケーションは、独自のプロセスとして実行され、Dalvik 仮想マシン(VM)の独自のインスタンスにより実行されます。Dalvik は、携帯電話で複数の VM を効率よく実行できるように設計されています。Dalvik VM は、メモリの使用量を最小にするように最適化された Dalvik 実行可能(.dex)フォーマットのファイルを実行します。この VM はレジスタベースであり、Java 言語コンパイラによりコンパイルされた組み込みの「dx」ツールにより .dex フォーマットに変換されたクラスを実行します。

        + +

        Dalvik VM は、Linux カーネルを使用して、スレッディングや低レベルのメモリ管理などの基本機能を実行しています。

        + + + +

        Linux カーネル

        + +

        Android は、Linux バージョン 2.6 を使用して、セキュリティ、メモリ管理、プロセス管理、ネットワーク スタック、ドライバ モデルなどのコア システム サービスを提供します。このカーネルは、ハードウェアと他のソフトウェア スタックの間の抽象化レイヤーとしても機能します。

        diff --git a/docs/html/intl/ja/guide/developing/eclipse-adt.jd b/docs/html/intl/ja/guide/developing/eclipse-adt.jd new file mode 100644 index 0000000000000..26cae54264f4f --- /dev/null +++ b/docs/html/intl/ja/guide/developing/eclipse-adt.jd @@ -0,0 +1,243 @@ +page.title=Eclipse 内で ADT を使用 +@jd:body + + + + +

        「Android Development Tools (ADT) plugin for Eclipse」は、Eclipse 統合開発環境に強力な拡張機能を追加します。拡張機能により、Android アプリケーションの作成とデバッグが容易になります。Eclipse を使用している場合、ADT プラグインを組み込むことで、Android アプリケーションを驚くほど効率よく開発できるようになります:

        + +
          +
        • Eclipse 総合開発環境内から、他の Android 開発ツールにもアクセスできます。たとえば ADT では、DDMS ツールの多くの機能が利用できます。Eclipse からスクリーンショットの撮影、ポート転送の管理、ブレークポイントの設定、スレッドやプロセスの情報の表示を直接行うことが可能です。
        • +
        • Android 開発用の新たなプロジェクト ウィザードが追加されます。それを使用して、新しい Android アプリケーションに必要な基本ファイルをすべて簡単に作成してセットアップできます。
        • +
        • Android アプリケーションのビルド プロセスを自動化と単純化できます。
        • +
        • 同梱の Android コード エディタを使用して、Android のマニフェスト ファイルとリソース ファイルの適切な XML をスムーズに作成できます。
        • +
        • プロジェクトを、ユーザーに配布可能な署名済みの APK 形式でエクスポートすることもできます。
        • +
        + +

        ADT を組み込んだ Eclipse 総合開発環境で Android アプリケーションの開発を始めるには、最初に Eclipse 総合開発環境をダウンロードしてから、ADT プラグインをダウンロードしてインストールする必要があります。そのためには、Eclipse 用 ADT プラグインのインストールに記載されている手順どおりに操作します。

        +

        バージョン 0.9 より前の ADT を使用してアプリケーションを既に開発中の場合は、必ず最新バージョンにアップグレードしてから続行してください。Eclipse ADT プラグインをアップデートするためのガイドをご覧ください。

        +

        注: このガイドでは、ADT プラグインの最新バージョンを使用していることを前提としています。説明の大半は、以前のバージョンにも当てはまりますが、以前のバージョンを使用している場合は、このドキュメントのオンライン版ではなく、SDK パッケージに付属された資料内の同ドキュメントをご覧ください。

        + + +

        Android プロジェクトの作成

        + +

        ADT プラグインが提供する新規プロジェクト ウィザードを使用すると、簡単に Android プロジェクトを新規作成(または既存のコードから作成)できるようになります。新しいプロジェクトを作成するには:

        + +
          +
        1. [ファイル(File)] > [新規(New)] > [プロジェクト(Project)] を選択します。
        2. +
        3. [Android] > [Android プロジェクト(Android Project)] を選択し、[次へ(Next)] をクリックします。
        4. +
        5. プロジェクトの内容を選択します: +
            +
          • プロジェクト名を入力します。これはそのプロジェクトが作成されるフォルダの名前になります。
          • [内容(Contents)] セクションで、[ワークスペース内に新規プロジェクトを作成(Create new project in workspace] を選択します。プロジェクト ワークスペースのロケーションを選択します。
          • +
          • [ターゲット(Target)] タブで、プロジェクトの [ビルド ターゲット(Build Target)] として使用する Android ターゲットを選択します。このビルド ターゲットは、アプリケーションをビルドする Android プラットフォームを指定します。 +

            最新の SDK に導入されている新しい API を使用することがわかっている場合を除き、Android 1.1 などの最も古いバージョンのターゲット (Target Name) を選択してください。

            +

            注: プロジェクトのビルド ターゲットはいつでも変更できます。変更するには、[パッケージ エクスプローラー(Package Explorer)] でプロジェクトを右クリックし、[プロパティ(Properties)] を選択し、[Android] を選択して、指定するプロジェクト ターゲットのチェックボックスをオンにします。

            +
          • +
          • [プロパティ(Properties)] セクションで、必要なすべてのフィールドに入力します。 +
              +
            • アプリケーション名 (Application name) を入力します。アプリケーション名はユーザーにわかりやすいアプリケーションのタイトルにします。この名前が Android 携帯端末に表示されます。
            • +
            • パッケージ名 (Package name) を入力します。これは(Java プログラミング言語でのパッケージのルールに従った)パッケージの名前空間であり、作成するソース コードはすべてこの中に含まれます。
            • +
            • [Activity を作成(Create Activity)] を選択し(オプションですが、一般的な手順です)、メインの Activity クラスの名前を入力します。
            • +
            • [SDK の最小バージョン(Min SDK Version)] を入力します。これは、そのアプリケーションを正常に実行するために必要となる API の最小レベルを示す番号です。ここで入力すると、minSdkVersion 属性が Android マニフェスト ファイルの <uses-sdk> に自動的に設定されます。使用する適切な API レベルがわからない場合は、ビルド ターゲット(Build Target)にリストされている API レベル(API Level)をコピーします。
            • +
            +
          • +
          +
        6. +
        7. [完了(Finish)] をクリックします。
        8. +
        + +

        ヒント: 新規プロジェクト ウィザードは、ツールバーの [新規(New)] アイコンからも開始できます。

        + +

        新規プロジェクト ウィザードを完了すると、ADT は新しいプロジェクトに次のフォルダとファイルを作成します:

        +
        +
        src/
        +
        スタブ Activity Java ファイルが含まれます。アプリケーションの他のすべての Java ファイルも含まれます。
        +
        <Android Version>/(例: Android 1.1/
        +
        アプリケーションのビルド対象となる android.jar ファイルが含まれます。これは、新規プロジェクト ウィザードで選択したビルド ターゲットによって決まります。
        +
        gen/
        +
        ADT により生成された Java ファイル(R.java ファイル、AIDL ファイルから作成されたインターフェースなど)がこのフォルダに含まれます。
        +
        assets/
        +
        このフォルダは空です。未加工のアセット ファイルの保存に使用できます。Resources and Assetsをご覧ください。
        +
        res/
        +
        アプリケーションのリソース用(描画ファイル、レイアウト ファイル、文字列値など)のフォルダです。Resources and Assetsをご覧ください。
        +
        AndroidManifest.xml
        +
        このプロジェクトの Android マニフェストです。The AndroidManifest.xml Fileをご覧ください。
        +
        default.properties
        +
        このファイルには、ビルド ターゲットのようなプロジェクトの設定が含まれます。このファイルはプロジェクトに不可欠なので、ソース リビジョン管理システムで管理する必要があります。このファイルを手動で編集しないでください。プロジェクトのプロパティを編集するには、プロジェクト フォルダを右クリックして、[プロパティ(Properties)] を選択します。
        +
        + + +

        アプリケーションの実行

        + +

        注意してください。アプリケーションを Android エミュレータで実行する前に、Android 仮想デバイス(AVD)を作成する必要があります。AVD では、エミュレータで使用する Android プラットフォームを指定します。詳しくは Android 仮想デバイス のドキュメントをご覧ください。ただし、すぐにアプリケーションを実行したい場合は、次の簡単な手順に従って AVD を作成してください。

        + +

        携帯端末の実機でのみアプリケーションを実行する場合は、AVD は必要ありません。この場合のアプリケーションの実行について詳しくは、Developing On a Device をご覧ください。

        + +

        AVD の作成

        + +

        詳しい説明はこのドキュメントの範囲外なので、AVD を作成する基本的な手順のみをここに示します:

        + +
          +
        1. コマンドライン(たとえば Windows では「コマンド プロンプト」アプリケーション、Mac/Linux では「ターミナル」)を開き、SDK パッケージの tools/ ディレクトリに移動します。
        2. +
        3. 最初に、配備ターゲットを選択する必要があります。選択可能なターゲットを表示するには、次のコマンドを実行します: +
          android list targets
          +

          次のように選択可能な Android ターゲットのリストが表示されます:

          +
          +id:1
          +    Name: Android 1.1
          +    Type: platform
          +    API level: 2
          +    Skins: HVGA (default), HVGA-L, HVGA-P, QVGA-L, QVGA-P
          +id:2
          +    Name: Android 1.5
          +    Type: platform
          +    API level: 3
          +    Skins: HVGA (default), HVGA-L, HVGA-P, QVGA-L, QVGA-P
          +
          +

          アプリケーションを実行する Android プラットフォームに一致するターゲットを探します。id の整数を書き留めておき、次のステップで使用します。

          +
        4. +
        5. 選択した配備ターゲットを使用して、新しい AVD を作成します。次のコマンドを実行します: +
          android create avd --name <your_avd_name> --target <targetID>
          +
        6. カスタム ハードウェア プロファイルを作成するかどうかの問い合わせがあります。「yes」と答えると、携帯端末ハードウェアのさまざまな要素を定義するための一連のプロンプトが開始されます(空白のまま入力すると、かっこ内に表示されたデフォルト値が使用されます)。または、Enter キーを押すと、すべてデフォルト値が使用されます(「no」がデフォルトです)。
        7. + +
        + +

        これで AVD が作成できました。次のセクションでは、エミュレータでアプリケーションを起動する際に、AVD がどのように使用されるかについて説明します。

        + +

        AVD の作成と管理について詳しくは、Android 仮想デバイス のドキュメントをご覧ください。

        + + +

        アプリケーションの実行

        + +

        注: アプリケーションを実行する前に、アプリケーションのビルド ターゲットを満たすターゲットを指定した AVD を必ず作成してください。ビルド ターゲットの要件を満たす AVD が見つからない場合、それを示すコンソール エラーが表示され、起動は中止されます。

        + +

        アプリケーションを実行(またはデバッグ)するには、Eclipse のメイン メニューで [実行(Run)] > [実行(Run)](または [実行(Run)] > [デバッグ(Debug)])を選択します。ADT プラグインはそのプロジェクトのデフォルトの起動構成を自動的に作成します。

        + +

        アプリケーションの実行またはデバッグを選択すると、Eclipse では以下が行われます:

        + +
          +
        1. プロジェクトがコンパイルされます(最後のビルド以降、変更があった場合)。
        2. +
        3. デフォルトの起動構成が作成されます(そのプロジェクトでまだ作成されていない場合)。
        4. +
        5. エミュレータまたは端末(起動構成で定義された配備ターゲットに基づきます)にアプリケーションがインストールされ、起動されます。 +

          デフォルトでは、Android アプリケーションの起動構成ではデバイス ターゲットの選択に「自動ターゲット」モードを使用します。自動ターゲット モードでの配備ターゲットの選択について詳しくは、下記の自動または手動のターゲット モードをご覧ください。

          +
        6. +
        + +

        デバッグの場合は、アプリケーションは「デバッガ待ち」モードで開始されます。デバッガの接続後、Eclipse はデバッグ パースペクティブを開きます。

        + +

        プロジェクトで使用する起動構成を設定または変更するには、構成マネージャを使用します。詳しくは起動構成の作成をご覧ください。

        + + +

        起動構成の作成

        + +

        起動構成では、実行するプロジェクト、開始する Activity、使用するエミュレータ オプションなどを指定します。プロジェクトを初めて Android アプリケーションとして実行すると、ADT は自動的に起動構成を作成します。デフォルトの起動構成は、デフォルトのプロジェクト アクティビティを起動し、自動ターゲット モードで端末を選択します(優先 AVD が指定されていない場合)。デフォルト設定がプロジェクトに適さない場合は、起動構成をカスタマイズするか、新規作成することができます。

        + +

        起動構成を作成または変更するには、使用している Eclipse のバージョンに合わせて、次の手順どおりに操作します:

        + +
          +
        1. 構成マネージャを開きます。 +
            +
          • Eclipse 3.3(Europa)では、[実行(Run)] > [実行ダイアログを開く(Open Run Dialog)](または [デバッグ ダイアログを開く(Open Debug Dialog)])を選択します。 +
          • +
          • Eclipse 3.4(Ganymede)では、[Run(実行)] > [実行の構成(Run Configurations)](または [デバッグの構成(Debug Configurations)])を選択します。 +
          • +
          +
        2. +
        3. [Android アプリケーション(Android Application)] 項目を展開し、新しい構成を作成するか、既存の構成を開きます。 +
            +
          • 新しい構成を作成するには: +
              +
            1. [Android アプリケーション(Android Application)] を選択し、リストの上にある 新規起動の構成(New launch configuration) アイコンをクリックします(または [Android アプリケーション(Android Application)] を右クリックして、[新規(New)] をクリックします)。
            2. +
            3. この構成の名前を入力します。
            4. +
            5. [Android] タブで、この構成を使用して実行するプロジェクトを参照し、選択します。
            6. +
            +
          • 既存の構成を開くには、[Android アプリケーション(Android Application)] の下にネストされているリストからその構成名を選択します。
          • +
          +
        4. +
        5. 必要に応じて起動構成の設定を変更します。 +

          [ターゲット(Target)] タブでは、アプリケーションを実行する AVD の選択を手動(Manual)モードで行うか、自動(Automatic)モードで行うかを考えます(次の自動または手動のターゲット モードのセクションをご覧ください)。

          +
        6. +
        + + +

        自動または手動のターゲット モード

        + +

        デフォルトでは、起動構成には、自動ターゲット モードで選択された AVD が使用されます。このモードでは、ADT は次の方法により、アプリケーションの AVD を選択します:

        + +
          +
        1. 既に実行中の端末またはエミュレータがあり、その AVD 構成がアプリケーションのビルド ターゲットの要件を満たす場合は、その端末またはエミュレータにアプリケーションがインストールされ、実行されます。
        2. +
        3. 端末またはエミュレータが複数実行中の場合は、そのうちのビルド ターゲットの要件を満たすものが「デバイス選択(Device Chooser)」に表示されるので、その中から選択できます。
        4. +
        5. ビルド ターゲットの要件を満たす実行中の端末やエミュレータがない場合は、ADT は使用可能な AVD を調べます。ビルド ターゲットの要件を満たす AVD があれば、その AVD を使用して新しいエミュレータが起動され、そこにアプリケーションがインストールされ、実行されます。
        6. +
        7. 上記を満たすものがない場合は、アプリケーションは実行されず、ビルド ターゲット要件を満たす既存の AVD がないというエラーがコンソールに表示されます。
        8. +
        + +

        ただし起動構成で「優先 AVD」が選択されている場合は、アプリケーションは常にその AVD に配備されます。その AVD がまだ実行されていない場合は、新しいエミュレータが起動されます。

        +

        起動構成が手動モードの場合は、アプリケーションを実行するたびに、「Device Chooser」が表示されるので、使用する AVD を選択できます。

        + +

        アプリケーションへの署名

        + +

        Android アプリケーションの開発を始めると、Android アプリケーションをシステムがエミュレータや実機にインストールする前に、どの Android アプリケーションにもデジタル署名が必要であることがわかります。署名には、デバッグ キーを使用する方法(エミュレータや開発用端末ですぐにテストする場合)と、非公開キーを使用する方法(アプリケーションを配布する場合)の 2 つがあります。

        +

        ADT プラグインでは、アプリケーションをエミュレータや開発用端末にインストールする前に、.apk ファイルがデバッグ キーを使用して署名されるので、開発を早めることができます。つまり、独自の非公開キーを生成する必要がなく、Eclipse からアプリケーションをすぐに実行できます。Keytool に ADT がアクセスできれば、デベロッパーが特に操作する必要はありません。ただし、アプリケーションを公開する場合は、SDK ツールが生成するデバッグ キーではなく、独自の非公開キーを使用してアプリケーションに署名する必要があります

        +

        アプリケーションへの署名をご覧ください。Android でのアプリケーションへの署名と、Android アプリケーション デベロッパーにとっての署名の意味について説明しています。このドキュメントには、ADT のエクスポート ウィザードを使用してアプリケーションをエクスポートし、署名するためのガイドも含まれています。

        + +

        Eclipse のヒント

        + +

        Eclipse での任意の Java コードの実行

        + +

        Eclipse のブレークポイントで中断したとき、任意のコードを実行できます。たとえば「zip」という文字列引数を使用する関数では、パッケージと呼び出しクラスのメソッドに関する情報を取得できます。任意の静的メソッドを呼び出すこともできます。たとえば android.os.Debug.startMethodTracing() と入力すると、dmTrace が起動されます。

        コードの実行ウィンドウを開き、メイン メニューから [ウィンドウ(Window)] > [ビューの表示(Show View)] > [表示(Display)] を選択すると、簡単なテキスト エディタである [表示(Display)] ウィンドウが開きます。式を入力し、そのテキストをハイライト表示し、'J' アイコンをクリックして(または Ctrl+Shift+D キーを押して)そのコードを実行します。コードは、選択したスレッド(ブレークポイントまたはシングルステップ ポイントで停止している必要があります)のコンテキストで実行されます(手動でスレッドを強制停止した場合は、シングルステップを 1 回実行する必要があります。スレッドが Object.wait() 状態の場合は、上記を実行できません)。

        現在、ブレークポイントで中断している場合は、ソース コードの一部をハイライト表示し、Ctrl+Shift+D キーを押して実行することができます。

        同じスコープ内のテキストの一部をハイライト表示するには、Alt+Shift+上矢印キーを押して、より広い範囲の閉じたブロック(複数可)を選択するか、下矢印キーを押して選択範囲を小さくすることができます。

        Eclipse で [表示(Display)] ウィンドウを使用した入力とその応答のサンプルを次に示します。

        + +
        - Android asset -
        3G
        - Android asset -
        Airplane mode
        - Android asset -
        Alarm
        Android asset
        Bluetooth
        - Android asset -
        Bluetooth connected
        - Android asset -
        Calendar
        - Android asset -
        Disk full
        - Android asset -
        EDGE
        Android asset
        Email
        - Android asset -
        Gmail
        - Android asset -
        GPRS
        Android asset
        IM
        - Android asset -
        Installation complete
        - Android asset -
        Music
        - Android asset -
        Roaming
        - Android asset -
        Signal
        - Android asset -
        Signal unavailable
        - Android asset -
        Silent mode
        - Android asset -
        SMS/MMS
        - Android asset -
        Speaker phone
        - Android asset -
        Sync
        - Android asset -
        Sync error
        - Android asset -
        USB connected
        - Android asset -
        Vibrate
        Android asset
        Voicemail
        - Android asset -
        WiFi
        - Android asset -
        WiFi network available
        - Android asset -
        WiFi unavailable
        - Android asset -
        Battery 100%
        - Android asset -
        Battery empty
        Android asset
        Call
        Android asset
        Call on hold
        - Android asset -
        GPS on
        Android asset
        Missed call
        MCC and MNCThe mobile country code optionally followed by mobile network code +

        The mobile country code optionally followed by mobile network code from the SIM in the device. For example mcc310 (U.S. on any carrier); mcc310-mnc004 (U.S., Verizon brand); mcc208-mnc00 (France, Orange brand); mcc234-mnc00 (U.K., BT brand). -

        +

        If the device uses a radio connection (GSM phone), the MCC will come from the SIM, and the MNC will come from the network to which the device is attached. You might sometimes use the MCC alone, for example to include country-specific legal resources in your application. If your application specifies resources for a MCC/MNC combination, those - resources can only be used if both the MCC and the MNC match.

        Language and regionThe two letter ISO +

        The two letter ISO 639-1 language code optionally followed by a two letter ISO 3166-1-alpha-2 region code (preceded by lowercase "r"). For example fr, en-rUS, fr-rFR, es-rES. -

        +

        The codes are not case-sensitive; the r prefix is used to distinguish the region portion. You cannot specify a region alone, but you can specify a language alone, - for example en, fr, es.

        Screen dimensionssmall, normal, large -

        +

        small, normal, large +

        Specify that the resource is for a particular class of screen. The meanings of these are:

          @@ -517,27 +517,27 @@ MyApp/
        Wider/taller screenslong, notlong -

        +

        long, notlong +

        Specify that the resource is for a taller/wider than traditional screen. This is based purely on the aspect ration of the screen: QVGA, HVGA, and VGA are notlong; WQVGA, WVGA, FWVGA are long. Note that long may mean either wide or tall, depending on the current - orientation. + orientation.

        Screen orientationport, land, square -

        +

        port, land, square +

        Specifies that the resource is for a screen that is tall (port) - or wide (land); square is not currently used. + or wide (land); square is not currently used.

        Screen pixel densityldpi, mdpi, hdpi, nodpi -

        +

        ldpi, mdpi, hdpi, nodpi +

        Specifies the screen density the resource is defined for. The medium density of traditional HVGA screens (mdpi) is defined to be approximately 160dpi; low density (ldpi) is 120, and high density (hdpi) is 240. There @@ -545,7 +545,7 @@ MyApp/ in ldpi would be 12x12 is mdpi and 16x16 in hdpi. The special nodpi density can be used with bitmap resources to prevent them from being scaled at load time to match the device density. -

        +

        When Android selects which resource files to use, it handles screen density differently than the other qualifiers. In step 1 of How Android finds the best @@ -553,10 +553,11 @@ MyApp/ be a match. In step 4, if the qualifier being considered is screen density, Android will select the best final match at that point, without any need to move on to step 5. -

        +

        You can also specify explicit densities like 92dpi or 108dpi, but these are not fully supported by the system so should not be used. +

        Whether the keyboard is available to the userkeysexposed, keyshidden, keyssoft -

        - If your application has specific resources that should only be used with a soft keyboard, use the keyssoft value. If no keyssoft resources are available (only keysexposed and keyshidden) and the device shows a soft keyboard, the system will use keysexposed resources.

        keysexposed, keyshidden, keyssoft +

        + If your application has specific resources that should only be used with a soft keyboard, use the keyssoft value. If no keyssoft resources are available (only keysexposed and keyshidden) and the device shows a soft keyboard, the system will use keysexposed resources.

        Primary text input method!RDT@34AQOJ(Ge>6HXvwkENS@5?Osj zmqyli_Mj=`NBii?oapni!}Bn@LjA2=uhY)AScZgAuQE3(nOzqD#(q9P!VKUa`mhfC z%dx)1FJa0Axr?fc)}erKe{$|!mw7M9nWr!$a#O3Af-xNva(=k( zx1!fZ^Y&-{fL-h3bL*2#K$GRlgN`0Ey54eq_2*R;KAO>rLin%lEty$mWe-2p9yhnX zcPdHeBa<+mEKWS<%O-{gxf!;tl*lFl@sH18rNXH|W=#1Bq08)_jl=1){l*51onf}m z=FYYJ0AF$3ag+CRU-``vd?f+|QyNZdC5QhxwP^dM?#rv0;Ca(~NMyXrjRqsdsn{+a zl%R=nt(%XLw(4KNKqzYaFK1 z$GgjAAJ?i+?Q+vZ>cFNC!kRBVHf{&g^Q|5ZrB}e$aeXvhCwI*VaQA)yr1wPu%+W)A zDW_mvL62**0#uo4Ms;F7`-)71W@nlX<+e`;03q$(8s*0+vi!0S5)OJD&htl~{kKyz zeNWxCFK`Pc_+9rtZrAI^+dDZq4KNIJcx9iw)Psrd(#%(S+^t1@du6RiF%Z;bEoS0cB*G<>qJ$@yxBGcSB0pcUCido*kg|9xDI<-P5HAuF zHhgrX4tGmyFb(Aa#dZf%PI+L)N}w)>%*-%EOn`|+tZS^RdN^Q)bIfMjvnubETfEX{ zd=Hi60~YzynYX6H;JSm@64$+p0p=x_v!vvKCJGA)QUi=iik0J~$%I32CVDiyYkT@c z7y}HYxe1dQa(970jZ%cmtxFH6Q{mVyU;toT5KY4VN^qOh4NtkHv_Wck01p9)Ws}=T z1T-RrY+(T*E+HWyU4;3~b5GB)4!8%UO#X>_Syh_dzly|3s!3EIz_zrF9eh1VT(x&@ zJRMaWRSYv%joj80^o?eVEEXwdP`!`umolic9|8LTkmgS*X9_T|YFq>flw{TN5pRHk z2BTib{YAOlU~e>je2(ymt6)lX(rMfEXlw=_-b?*A=-KN=Z2wMB%^~w#4*!7HwIJmXIub}%YmFQUBFo={$A zWAEl8LMUVS<9@Xyaz-oAWopa5e!F*_ImSi>7wIucD!pMMA)&)~z1P#B*X$hzxdY)j z>)D^nHL86QAqZCdv62NS_^iH{m3+|S#o{ej0sWy=R{4$$;m;?TjVoS=(xS#8tYfE>P15j~Dh1}FKGy2pcZI-IfCUrv4+A+k*z(!15X?UZWiw^FN+MSywNK!Oa+mWtsK~DUKwJuv08d#j z`D7_FoORiwj}Pg3#+AQW`E|e@pZS$Zt%L%p8!F~|n$dsx$kmfQUt<~(J`qF8=MK_( z5Q;A#n3p6IL-gAzQ^f&zkYCoRB4D~ss-ZEb&8Ca!F=rWXRunoihS_PPj-0m#u_QZm zZ}ny8Ap%*WGs+DsO>PBmAA#Pc-|pVvA9Al${03rTYRd6MYBqmbXCYeB@q$? z;vUa!H=nl;fZXr-HNG5kH)ZOW*9RoWSoNA6H+Rrz%mLE^AOl>R_2eACfXcbiCySq) zs3o3PF)?!GA$6)Q9rqT8!TV#4`_scDmQgF<7-`dpES z1(S;X<@PvH-($)}{9TImK)^1>lLr1nKoLbPJj7%`B%e$hA;HeQba@;f;a}{XiD%!9 zzV|PO3Ck-@Azk$J$vQ98COveB!C7GGq~>YdpzxzzbUKfZtIfZs*mxL7Kh>8eg*WE3bQ~o zN7ll^;#jZ&WFONF6RJ2*H_gpb1-+g%Jii%+v}||nz)Qg5D_b>ZXB}29J7bGmXy5-S z)!k*I>0qyDr&*ma?J6c~MbX;1Ej@g%tjA_BNCnSr+c(4GzwD2U>9@6YeMNE@J?1tz zQWNDhGaMs~po+^R9Wv!|A}JXnxSdTp=l%5e&8c4-suq!@^+UGH=E{AZPD+2H!9nwV znrV`#{_Fe67TDPE#g4n%*;QMuyPnXsafl;I?o@?N!*1n(Ji?9bWRZ4?#F(;}(-yL0 zdc{%j>!j4|7EhlIc@fjM!9J+j8VNS9lI%yy{CfKQrhZ9}bS$U)3D|7bSIq>5!^I#4 zk*A%YUGWJEt(D%bo_d~cZs+b&%Pv%3OL<#}vj0n39D2r(;Y}^QpV*QOS)9I7toT>5 z`2$MJ_tONn>_~ahUBSnuB#4serT_J%zd@&E8(E;Exxt;$MfD92Oz!ET%P+Rt3 z-AuvdAV3t1wG-js;L6p0*7`lTL*_b6eL&d6?5)o<3gEa1xZDq~{SI06fwn&@Lp8s7 z5ACpkvdb$3fg~x0BHNgGTT!r%o4f#Q6Gnmd=vW+S(4=JodQ2eIUWYqGJT?R|2oB-j zYB>;Z$Zs7lB7habVI|+o+PX}xBi_@zN~)5dYRH<`YQ+1er#{MNE~N9%9}+OX{~5=; z3~t^`Fj#Fe@Da~ zoc2o!Y{cqCa(C>ItBKDAFm;d^seVLNP2ZNq{BosJ;-Rmmosn4=Ay z@CnhXD^+mq_lWi|H`}^@^}Pe+u?so$`#MA+kg(8i@8dEaHqPSyRzosIu7{^s=oGy1 zAeLxPy_z;FLq{VYaTHa#6-Bh;FrEdcu=S0aWyyWj7&&U!Rmpjn&D2?&HZpQjvqPxt z)*@xeJ-5Tq$J*xCzw?p5*qmKLeV(pof$F*hTFL=kT#$5BiBw22OK^JK(J1EH+fPa= zv}eaid#3zrg1NSK10K9YIfFq`ZpniOWzziBAXAm=@nnN}c`BW9RtyU<3M8Kbos{<~ zY=SLQ(5);tH`lK97tnJVI7Yw6u(e-(0`9B->ihto1y~h;r_%?tAa&S$fv^M3mFI9K zG&~#u9v)=Xo0n-)@$^|W!AOpnB*yQ1dj>XXVo#5%hJza65#S)~g+@6nRO}C?Fs*uS zqNN19coPy*(iqtch`|a1Fkm9ZU|{=~+Qm(dbnZb660+@hEuxAW%p}pDdUMUu15k&U z_m(=Hi8->3eyh!X?|*VTXc0at#2%=%cyFKN6=+IIKJANhQCuC4`5;{RIBanx?Xb+{ zPmD(~$tt~zc>gMhIrtB;mK-g7DE8mtS_ObyzrJ(HGlv!ZR*S=p`jMY*%zfKpaFFMH z3&tb2e?LB-g9YR*q?S3Ux*w8i{(HYjTDII=*nYyms53iZrp=$EDQm4>vlIsl$Fj*w zh?IV~T1{=9f&!NR$gLcZJ58Le$rQz4lC(nxFm7f zK2Km7c`zjIe{p$ztfK}e4v{)fEsW^|;c1NY-snUD;c=sXb}Qa;V5*ung*ZmjrfAp+ z5349dXf!}34rh+Nw~xs?vjr>cqKTr@PP49iG{hnB^a?ddOxPTh6suFS(z1+iY!8;| ztSq%0XGK-LJ#79}=|sK2tGr;V&iK>Zcsh=Udik&G(v|Be~M(K8-Q z&rnY#SIaywScfSo^@aY3DhgXNGCvzNn*3-pP?6C!Mt_O#N4Khu%;XzW7=R%v1+6G* zQK^H=sCIjBSoI$z3uq|CONy_NkO;UeP$fU$NXsU--D^vW9?v$e zrWyL*{mpRTc9?kt`A|7{*HvAhxSwP=bd>5;mMIl4{&LIED7KqylGX7h8oLB95BF4s zQyoK&f>*%gLq{R2LEC@A5x67oq1}@%x>u7dR!j7}c2L}#FDTY@$NH~3m*OLcyCLs30D=REVHL6)WU?Wj~rDjO4-+KKhR|Dy5vqn7w|)K{?=XK?8A{=u*k(8i2D zV7g9DWbN0hvmOq&D-N0pnsMBkyM}Eo{}hIVX|5fN^7$l?IcT)WXO$+k(9|^emBgoq zrA`zO4ICtkctHdtlV|^DfN|G;7+L^vPy2CURxY?A?mUMsu zyz*(CD))AvAo)7p%X7LckYLr*1l}>`Yx4*#?7u&^Rqg|&aMDrZ{Fgao3wE1oHW+lk^ zY@c;TtU2!RKs!QX=Qqv@iMj)dOB@-e?V+~o-^xKSJC%!L^_DvADo>2!Qr|HfGuZ6( zn1@D))xEYW$qVjZg($)CYF6shAh7IW6@ow%=CYqRuh&hlw&{ESAAF8|O3VNDxhVz$ zC6cML+0<0e+9+fT`RG7H2+~_v2;a--t$#*ij=#-hyx}MrbS3l|?!E7F!NZ^a>RcN> zRWaW>!)VqKNZ0XB5QKtys5S!M>^mfkt^-fZ?BCU6Ud~?q($98$QNI988{Q!L&{Phg zrBVF8Vff(LpJMmt4c>uVp0&TYRw_MA<>#~&Z>|!Yiu_b7oQ&FLN(QqpQEC|@JH^@5m?%pM0S->RbMK&} zv%@&3ok19MiU#-FdP^7x(0)NjIE%XV-(kXz;s%@P=l#BJ+Fod!roslq2za7agn@M% z%BawBw?lk7Wj9|dEkFipK%1O4|D9ZA;Umyi>m{&Jz3xfGL8L!c(D1`IZ?X^<5H^lu)l#rh<)56(SK-^cRiMSiHhOwf)nNk)5B042)%9SFCjH za(N`o)@ZNOZdZOlgoYAKfQzNpsYHSq4B;mFB^x3~%R)@{W})C+`=2d^(9%Z3!{ufl zRmXFRA!fx+!4^bm)zbauHwOFDRfh78=i*53rbdX=Z@Bi?#X5hJQ;pjMnFpChy$~R1 zA@Cz`5Yz>Ag+KR@OIFP`0;3zicdv^dXH&-fx5p}_t)%nf9Q#RrN*J7AjlD%OzN zn%k1c$PK5A+Lf7|drptyjS<7RHG~RN+VO%ywyUO#!^i~|LIE#B%Dn|C-g>ZdSzs_MsRkvwh@gYxO|p_pTuxfEdV8LI&w#u^FWhhU6`PZ;>4Hx&J^;f zY`6su9{_lHL#xm~I*I@h6YB&|a449Tff0<{|8_#t(64lA-wg8hbujj)&@>DZ!GHPM zTq%j!j+vrP_v3l*z?=K~{CBoEVq!d8`vxtJFsyw3C}+XtO#>1kpV6iFRSjn<{K*u* zC5vQw>(!0ezMi<^lP#4a)bK~8{6+!dQ z+G{lWUV_!XJ2$Mra640FCMBBzBp1egr48;BL3y*gbnsHKBI|4Gmt5A ztok~oy7a*D8i_>(%s0Yj{RzOs(EI04NoQqL04G%eVnBj)o!V7k^*93fp#&Llx2 zfMW~HhKuN%joo5DG-b9?46La;nV=SKR8l6GZ8#&_Yks}|RtUc07!MK%jZ}(Qb4E_2 zhl8*ucgeR=z&!m4sFzElpLip8gZ4I%xxe|4)3Q{`#L{o$rNX3&ys!nrSlVN*E4A@)-^ z)0MANE{qdylNeSq*I0vD$d!-g^M>yE+7$%Cew89GyLh8lD<~o&G*dcN{g_R<8=oyF zj&yyh(kU6{*hSAmbJ{cJ|NTPA_d|(TB(~9!yO)K3YhBj?G8#v`-%lRXaWWC->$!o@ zYEFN+d)}4$%Z&l9MuE8IjP#e@tq!ldU(>`&lnJdK6}s&fsKNt65|KzWeswSmgl6%O zeu@Fudp>q&hT=3JEcGoyT;MeerRnGLr$#Q{xyZ5$u z0wj`tprKs)`gjo#OZAJ{sI9s646-*17@jmLh1*{C8Z@#FvxK~l4`R*YOrz<>Yi&6X zWH1641$a)=6pIf*fxR|QtzBbyD__on-2$E zZd$=ejzb51Sy4aMQlGwsni_M+`t8pKACIb}?{@kv_gY4Q>kl*!-cYNzZ>(nHqNmHt z!%Ozq1`8y^${KD}yPaQup!o2q@?hP*cNR#G*nJlBUT3=DVXl4waq&(>^?kiX)A=KD=@ zSb+=%Yat;q;?$B5srln8>ZJj!i=#AFIt=m!9n*10h*$ic>jfv9j11y_u)-^M5Ai@O z?#z|kr~Soay3r-8*;+=Udehx7jS;5VQe37<0<#U*i$q;^LT)T$e<2KmoV#PCft?nA zCN7ZMxHp;fh=vMQuu7?P)zFQtR^s3zTi8YX;^DR9Z?+o(ebwc{dB#^{MSY%@4k~$) zy#?lG5LpTiESMMsyA?NJi2PSZg#7k{l5+QPX7+jP-#9xA_@67oGUDED<(C&I$IN)| zHM~2NhOBr{`yogq=pGx(B+<)BUyUn2vi`B~U^3ViN9eNbVJjYlCuGu$tI#d5^^CkL zui`B%+SzXy4wimk(Rkk4|D!w0HTkpnrFMV#A?K&E(g##zl6-*khFaLYTW9`aktQ$Jd~D57jSdfqF9U;^mjL0)$sB=NaZ9 z4wF?nUL_v!;UkA>L&MC~^LN3%?{_t(MFT)VB(v^PXde9=MXIO*hJtX}hF!RRtwbv+ zm|hY=cc%Q99EL7>Q>ewMqOxX-zMPzZ{jFgFh#Lhib}4`=JxR*O!MsgJTB`{QlH?qUGP=b;6(Vjquk)ly%=tZV_Vots4U z_uj4*1sIq3q4`g6oa5Y=3njk{M;ApNuM4+LgNxdxP|RR)Qod$iUVF42PRHCi-~U}u zFIW^&_j?+A$9H1(UIu=qOdpRP6*VO@d3)<_j)=p^jWQ-kW|eitXIq073u{Q9WW4S< zu04&*nOP~VSURbxX%Ndvohqm>Y4VbouQHS$PwF+j*?>o-R)FMNY{@OcQJ6q`l2o2@VD^`|!D``0)L|MO(! zy>)Ar`XL$rN;(MvRtijUQG3gZtZ5xmNMGA#pi!Pw*Jh zr*zfjhDbEkDR9S@wVPeu-+1#sH`bh?v3MZ8!ks}OdlpW3^PCrJfc zO})D{@8&)FX$=XT7sN9M8l&Hya~*Qlu~16L=nUa)X}Mfv{f3dL%fT~)MS2~a@YTw# z<&|tQ9Nd-p;J2icoqoY>aa=mbIG#l}oiV1eenrn;drwgjLa94s#c+}C; z+ox4bBog$QoqFZbnD zWLvY{hdWy9?_moKqbtVA7>3t`EO9^CVR_*Dq|(svLn-0NR8H=6dyKyfz6_Ysc_(b( zzF1iJ#v9vM$=>*DrpzI)BzMbw9Qd@CZGltBj_PvMUjqVnuWk{|%*?(JQNGhDS0$zh2+|1eU; zWXZwXu+Td=%C#p8B#sAS@zi$PU@WOVcsNN4SvhsV$|93(#{{GgoPYbp#@DV_!_7aj zvMQ85%Fb#gAo>n(1(8+1l;^5#UeOVw_RwcOdswo_eXUiy(q~L0EK!%~WAh2%+wMfLUd8>~m(T2iZ} zEWCl0H8;j(d`6ckqK8L)HGI0R1CQaT`<(Ej({}Lj53I;fIln2)Yo8S%G@OrGPq5(M z8X^!_-EcPBc42<+%PjeEKpBT&5G54il>qh5ggdhH{=`tGVL9?xr}id+F7Nu-&B ztiOFm1$t&?Wiyl5EI)6GOM3s!5i7w@2?ebU2}6nl!mQG!=HnUvo_qrp^|leitE40Y zD;Q=V5He6UhK>s@u6WDJ%vsfumh;RelYRbl0}?dfM|K|O)Cx?fL}QTct}%^}Rim5< zVe&Dz)w#JMSxaN91(#c1z<|bf2+AHv<2JOYWUl{b5=Iaug z@;K0D>VZVmAMDZyuc`Ahu@lTn&w`IsGjWLL?tk?qIuJf=M3ejd+gN>yHHJWtsbJx; zq*RdLXo7!m)jZ!To7kZeNsN+)}T z?7cVNhxhIC2Yi34tJ`%P=e%Ce*W+=Y-&|qV$e0&7or?eEW$aHkN{JiMv1jYE6QxuA zPzICcKE4V1O9W$*P~PiV7KBVWJsw>T7Lr#A@wD+V&Baw)C#b)<+6$h%ZllI*KNkN_ zN#aQG#nI0MWJcyc3`$YsJDJ#k{pB5he8~)J2z=q#v5~5vpOd&=EL21yY5dQe93?na^s_dSFx3XXClsWZHGTz-XCKcmBk}BS}8KlO?Wl zdYMd`z_{CN`X!z!js&gTR1r(IntJgjW7bdNS=8A}Jau$VsK1dwwfE3}D3J8s(+1 zCL6G^ZtBa^5m52jt2nCgA|Sn`{&c+X3azfa=}ts}3?DXi#{xhSuTp%G>Aw9{3V(!OAJ@S z2sEG*OCTyv3b{61LVmUA%7Dc4CuC6v9Yr=&+e$YKvXm1L5U^_1=lxLnRrrDfgb@V= zkSW(BesZzgx!k+n3tV@5To`zUpedlHV?HP%qExTgok>U!Ha=j&{QN%fpVu1v?8Jwq zY_i-*4wy>tDnnB+HUcu--ma+?v#6F}0LuX=Y_&;9oE_mjtYvjJ8)FV;Ykx`}P*cBB z=0)h#x-#*L^OxvM*4r+%9fg*vH>EKK0}33qzw;-8m_yV0NwU>Y37`328qFxki1)hu zed7G8(hBuG?04E4e+dNQx3_vE@mUOKc-{IUjqUx1o10ehes)*%;|L1A-6@wD2#PU@ zun~1l)BoH9qu!s2TTvx1CIAjU3-Qbv2_zMJ;Svp;d`k|Zb=jPY{C6}$fgZMCM ztgdqFiZLDb_$iwz&9{m#3`}LB)(=~H6>}?8qJi@T-;9v+G9;^?#r0{k>(_?xM*tl-fbVg!;aImEGf_lvWmjgb{cS(nwJx{*`;Vd2z%04DeZ1ru}R zuwD`5h}c9Z=H7|G;!o~f>Q7%A&7SWg=LbVIOsNx|MDH_czVx(Ooey3Hy^31C%13??x+H z#ayp$Ak1ePFMtJAc%&>L(L${66&V>fnBnj-!|$WzwaP zbWlqn_c!&P`9kC!xEV}1a~Wj~luYK+>19#^$@k_G78R1Ut>bR)5m5-ZzWIF?O;6XC zCP;oG&Uj^SKNZ?w0RbNyu6EBL5nMr0A&t*#7>t~Nn?OXgCl~~R37O;A)DIQs zQZ;$Z7M2#2V^+5mr6Q&04pZkJM+}^p;`aR_N?w5QUw}Epfn;nHJ%ca=EjSq={~r`3 zwGd`>d@!PaXBRu1O0;0el0&arqe87uDY>oy!oG>fu1ivp52ew5+{w~g9xU$2RTjVL z3)Lh|T$f>B^l@u@8)xLPzkJp*nq&KY&%)$i)~)BOz|@EITp zERv?H4UC``W}dnI?M&^(dE(x6_FRl?V9nmVY>?SHSRZ!S z%jvVpJ^M)Q15YWagQI@pn9yasyPXD3tEE73voZ}lX~>=`dEM9ox8;j~7i`Bi?+1-z zOiuELUwQE^WbLo--zDdFT=}yAk=3>8it0P`MnLU;U@X$CG6i6jASaGh7aj32f+9RD ztoU^XI^y``OiKDia1<5-t{W?8xXGL;RH_XA-9e?|U}LknP#EuVu$-Opzzvp}mEv#k%)$e;Ogf`y`Y z?_pY#^WJz;r4_x5<*&SE-}g7viZtw&4pYGwF08AF$kQk@1a3Pw2=z(+o7M)uL(_@# zbQQ@wL?ZA(_WEo~K;&Sg%ht5+@kL90eZ8+Q(869-F2cI~NqkmR0*(k;N#*^#$Sla( zUZWH*P%oTrusYIoFx!}{+-ol;2a(=7Dt7>Gp=pQ>KRs9l`}%bd6)1rqUt)E%#He_@ z@;b!D!K`0Uw;w{gzgv&luPqh}rP{2;6{B(#=WmKJb2E#HO|P2~xjrL|R%JYPI~ag} z?knK)#|zy~R5nBScK+ml_gD%UoC~HR93emTsMp`B?ww3xAm1#vRN^IN;7ip15NEuC zUd~(hs3ut&)uEbU-TAEM&JtvlC1Mk@tP6iFwYjK`LzlY}yFmN#(AD$#O>Q!2q~Lvt z^Iq?!lg>C#Ik*_FZS?UI0rg{=Mt) zYyV25iEuJb74pms+k!}}d}dX#eJuIBGvZgqvK)OgS?jJ=H>v)hVEE+tABvqrS>`J5`HW!z?gvO>g!WIRRt8g%6cM` z^|P^w86*mOgvHb|H9u>PWmXY#UpJpRbwc|K7d1GC7L0nt^SDBYIIwYW&Rx4Z5brL= zol2$8AZzOk{t5}KyLYxj*vaoA`jVeqfuPJa%}kRB5l$(12u~lkn?<+0&ZYzTZ2lZ? zXSB}F&bl{D^G8S*k_y`YLtUho=w$B#kPSH}Uk*RN=;`ED(64juTQ|eSz1!%%Q6Qa# zBw8p?D|X)-R!HoWd_-cj@Pfe~FYz5~mFLPX#Hf>mNz24wJbPE0qVIFy)X`5Vezm@5 zHBw3%CY`O#C>4`IPV0~V$p0&=$J}uc{2-W%kFxDJ_}-2>{@KgIc(xtIEu{?RsJic4 z_oeWaHL?beWlKp6s(LQq;D;WktU+@Oz0X0Rc;k>3{rTDR)jtKwb!r>@)2=s+TXX9uZgeUpSN zYUaF2z~NuVCg%>M^!N0ku8CeqExaz5*>IV*87>-2Yw#e5*UMhD28jx=x<0yBR`A}X z!>A5UtxCypFpCw1Au9)(oh+OfSd%`<(<7BmjUn-67_zhM7i4APypLCIm2N0Q($5C& z*|&k*hO5gnSy^z#q0AI~HikxOowmMPpdJ;gO;nh@+UhM&2tW(U%;WTc`8-T|9#Wf< zc&&ct+NMLPlDP2x*z|?FnX&ONf{WjB9M@e}|5l<8)`ps#50bi!gF`};>pC8eJgk6E z`DYM(`U)wWTtCEV`1waHD-PFYN|AojR>LJb)uO~4de+mKf(j`3$je#pM7=wl92+jy zy73fJL56JjNbX8Lg28GAo^J5Sf0ZUeibq1zb&vB64FZ9NhPJY@qA!1DxE^9O;bgwF zwWSZaQDa}}WuoY1Gha=b2O8Kso(9iEU(%BvNVM+lrT=7JsRhnDvk@x4X3l?!v}z#- zpneug-8>K21A+?DPUK#_8tCpe6bLlY$VPkVbd)`Z*4f+Vc~LpyrR=`Hobi&dspLwv zbOegmD@+fPUts-INSF*nsNz~Hp&+gPdPWJ*gey0|s~It3_*Oc8DHie7Hb#iym#hU3B}i=4S}bcfWo>7p+&b%bgOPMsDcmfaG8% z{ov*|B%E)aN*YUs5Ctd}9td5;g=zB&^@VEkn8)eWnHKx_iX&ofv!TkRdJLu8^PuZV zb^-EIj*V9zv#6JfI3D9EppvVs!wU(HE?Txg1x`#wgo^;X7V$QZ-o_54yJvY^~O7kY{}8eQG6+j z8&xxx027TA=~Y0VNzVvJdvL_H{LYjm` zS9?d+zhdw1I&fVq){C}6x^h51G}C13^FI5Bdca+b0=2?Z)bDg-&0%xiwUJ`|Mr%Qd zmsx{w7W-M)W}jG$ zgDC-lg^jCqJk{b6qEd)_3#swlc91r@*@uUR2Z0l9!jj{l@c_-mExxB&gS}~d6CT&w zW#eggVYgjYU|9VMybUmxq}Vq9{rva3Fk9s<8rM!Gc(P5XOzBaH|-?Kr-ok6NqiZb$dd+$=C6HHJvWT_b! zOD{7<(o$Yj&M#Ry5)x%zHFn_MP(IjiQ}ytvyWjMJJ(CANSG!j6unQV7?LYe(9d`AM zyWF%|*DG%AB>Q_}>?J=89h>+}$}C3N(h(Lb0!Xf0aa=ucFU67v8b^?@n6#BMSf**n z)Pz(G*#)tw)2-xT(yC!Qcwn}@7GXgO&zZV-8~J>P&&7~BP|27yQ8akB5ypCA@0MSO znD+hAKe^qp@*o%H_J3Pj>4~W)bJb-A$XT@zLS+)#;4H>ml;~z#S;bPX7X^2@x`$Kg zrQCZ%;&su3q-MfgyboOLswsF92C}3#2)tF|>~7PNg-PQhx7xf)?@REeNVgI)(7iUV zRiQGWK}&Bl@ki!Y8X-7I6{ba|>EOeCz4P%u#X{9{N@bpX`WLs=GbBum39o3xFq5Yi z9fgKsUlG1yl|+6xlX`QR?9v0pB5mAg!H2Po?QM#=%7sG(EJjx{E2As+->qi)Ei1*0 z^!LzO%ae^fovUZBcO(_>OEJ+g zi#%b*+&sag3JP6!t`l}#<^ViKBZN`df)eUyn-3gMf{XtLMF@6cG| zI-A*SPUDY(c?%O0V_KnJc)uotxKyXNx0~J{Psx2SV(Fxu%LL-z1-;rGllz9@2>A8& zSDnk&W$o+;=3R*K_%qs9*V@_=&#G&`(!vlvPcIYvDb#!>zab8lCgiaC`$X>I^xzH- zK$QWU*ZISV+$InN+F?-*vv&5R0#c-bY(Fpq%<;gz>P>^DbyBg4220n&ISeNvMbyDL z>rog4-Tf$sIC?Yah8Tr2U(3k~U*fy%SXx3tp3RUC&BGfz?GA38p9&?~e9m}2o3zON zZiusq=th0+GRD4l7qFvgz}gB_@|Czs44s|7GX{C1fdKY^hb$DPH`$jjA=@NRHCHY5 z)Crdw>dLkaG-KTEaXc8CeYY(_jYqQW*p%ypIR!aA>^k-TeFkt4(=P)WA8}gW_!o{8 zl<=&Y_9hI%=PP}eoKooB^8N~nKuVNnpH!|k%5Pdl)xwtk5*F|D+m+#w2)+8LF=;vx&9=y(e*0a4MZg?B-j8kO!tFvSa7 zO_3LM4*DT2{yk>2jJE0|$q->j#0`y*WbuphlU7LruWn3IW##y8wt zDx?7Lq0I> z8bU!Aj5+y37V~p+=Qqxw`aq+>)JZ0aARrKW8#=qqhwI0FG~Wn&l;z{=11$>tB@@eE zg^e})yE{QOs|r{IbQNvxxB@a_)Kz6JpdhUlD6cZO_5KHzmAQhnqO_uScu@hHib%fu zosT`U`_-Gelin)s#*$h4e;n(2roYHMkZz@a^yv2|IDHqo<0oMBy53vLtzn8mycy}& zh2moVq_FqR?``5I<`3asp-TwO$;)F@Yds~sfHH+J=`7YBs)$^uZvk1W0qJ*0^3bZZ z(yg`6|DnWb`6uu5FTC7|AcO(gh}G+@$wUX7R>zfblgXZWiEe*$fiT8T1eu|a9!eq0 zSzokCCSLUNmrP+{~=ESSbM@fy^Y;vg=jvp5zBG?>C=X1l=c%_{2ehzk0*g_#yg+L9SdcH=e$0vFvuHFMgx@ zf+b`^!_U$yT+w9JWccziXi;sZi{+ue`W1za6c@-Q>PW?Kbt&p!0F?)oLuhCW~u);V$NIt;|7{c zRDZhoOz{hT=roLrgS<*YA|fJE!Wx+8<4pGUcHwK|vfqE1loLTAf{q1XFTETsEv;^? z6FgqB20>iIF3h7Hl?^92{(pDOI2_l8*aR41#nWl@95bw_KbcE@DZR6^18u;`{BPCx zzT8_QmojC(GWeL?J+Nh8TTg|?ptOwh;AI9WGa4O!S2A6<)Fqb5YY`g{4t%8;RIUJ` zQ_PmT5ey7o_Fq=NDu+QEOp~ z?gFt)0PeYFJI^pZ!}Dg`lp^0Dva@j;bUUJeJtjB z3>Q6F@goK%sr!&B)8N?!Sso?ZEhQUukQgLd|5%hQ)kMQYo`sQdw9cb65cMTHTW}pW zOzj5ZD|M%!~;k}}N&52i+$W6UXsbhYg_)Gf1=T=XruNvq| zUOiDMC#cQ6Z)=CmWLkY>@xyN?&+rq}e@PM4Cfmnnkftq}gcN|qm*N; z38Z$YrZ?e8CBv9)0qG=HJ2sk{~udK0Z3y4}s*pi2)_F zG1ERXIR&oV8HfIlDgH+n^Yd^cTpv2RN-1t(ip0p|Fi8A|Ieij62s;IL60tuL$x&|Mv&xhlSVV zU~m)&7t?)eL{Y8rQL5*$Pmdm*w@E)NAPffS%;!k1_H3f+VDTCyBKkaI%zt~$EO89J zTW2TYKdrMzpDZ+g+x1ueVM`_+JK7=dJ#wsN&MGB~oA|}p+up~IZ3deu`1F;lHk*#j z3xuSg3e@M`V7QNy$EkPYS%3^=KtRztH*3$=wkJa*#K|j!q&o)w8Nd3;loQZZjP1g( zBc7F&9)2$#{d!OI=eN31?=v(~gm23quU(PR@$;Fkx}$U|)+oi%Drf9Qyri=q#LIJ5AUxuZW89I9GM0dblrRLsc%{_XSOr5>?!P%M z9L%fNsco(Os(HTRyf4(>vi&dMBpv<#m|7UEuSf2TYuOS|wn3pq7`EVb!o$#vqKRNVaLxR6X9<>=}v&{OV{ zIlvUD^jtzhHk-w$z2OyPocsCt4fS9A`@0+41AT5<)$e8jSb{MRp9)`(`MJ0ECG5H} z^T*RWFofJdAPG8}1jQg-lEZcYM%YIE;|pr$sOaduc5>VE+f?d1w=|Xq2f13gw-jAn zI{%|hXeW?L6?eIuI+|{HclklBkd4Y-G!3w5o2lALJ5)PqK54LnA_Afv;dllNS8dAO zNwZeqFyfjBJ{%g+rxbDhI!D5@qd1p9+&m!bVgbx4$XeS&7M6Z{1ak9iN z(~5@uT{%&Y{q;Zj4+i$S#iV7Tz|A~m<6>%>v(+zMI3xrXmYhDw#GM#6=FD%{mO;>d z0SDCGRer`;@6GcXeg1Q;Vl6(I&#-aH{CP(P?YM9HCk3ywHyI1G!YpBi+-HOJ(?{=M zZz`tF$#Q6AEbDPgr%hF4v^5XOs1}39PD((`X8jAJF8Zf4VrQZ8=ELWWE zQsy?=WT~zA0sqBFXJ@dQLH9oF(iJZ5do+8h=Sk#I>F_E|KiO~LBu-9ZI zDjb3!cG^U`&n7V5!?F3Xl{QF;DJs^46z$Y{)eKrvP60-uoN!s6sN4G8Cg-qg<Sx zDgs-xWu?$MZYguCO;w!^dz-ly9tJFlpRyq^fA-zzhI4Y?;yZzuBz&5r46b%rs%(jn zwmC= z&Cv&CQx#U89VL_idC1pCSACi)T6dt1bt)yK*%8{;<-QH((!%y~(}+_P+(*Voq- zQ-#?y>;FM!A`tt}N#Iy_-W+xV`lM#821<{2*99x?#L^~LT~D4Dfd{h&v-+L~ZQ8a? zHxZI_iXWp5NTbuc%y}UX&jDCb7zkkMrRIF+i(0_&J+D89m%lh}jTkA_)vt0+{R<8$ zJlAIPCk2u8S0>!$jKRPkxZC`6n139a&gT->WnK$nm(Ll`aVZ6%iudci$39pH2#H=B z%8j2gYywytwV-kwZjfNd5q6!xZm-16vCAIcGvaV_U=LU*N?zk%4iD3{zq=+5zLA%g z6>&HWjY9=zjzaS~?ejpmmtlSJ2E@@hIn`wBXvRlel;`4OfH;jm8NbbWFVDa=1d~ax zn8?i_`cM?Q%;@OmddGOgFSeumOm8rTTIBq)gCxN~TuRGd+CkqnZlVh83Lm98#z}42E;Gw-TPMYXYm1%_Oa^?LHq)_8F0I_{`Aj+*{D6BDmPb4 z`~a4Jv>)&NZq--0791#t5VNImdVe^zy6iDFPFo`9wS40;3S@~fFNt6{YV81`O<)-_ zAFI#qm|vN0INR5R-dmK-OwGmmwpk@v@%7HL6sxZ1=FpNH&#n*DXGUvaaOQGdl~&Xj zAR)he$zGpm7_fd)K~Xr%D^%RySC{&T~ zK_zRzl0Gc(t_zjwm?ENof0jLfd^da~euDe*#PfF>r+go$>;Pp4+Fh6;{8f%OH{jr~ z9dMr|pB-#0IoAzc9{qcY7cg30wgK^e0B~32K(3*JqM{<0LkFltV{x3;hGPHC)X6tk zZIwK`fq9a%K2^ovXjX5pQ*2p@y}*(p>Z2xDtWpzY|95MvlpnN|FY?Dh)KcNx7ZZ`= zd3mw~_jnW|+K=!lVR(yAFJ>?AaF?_80NsR}+d98P5b~M3tGl~EyMn#L?)k^NQ%$y4 zaz@u5X;DhiioOE0Nb>T2yFy(w!E+^fe#Tfs+V+>r@~>u>jS#&1L{xFHi3~w)Rwmv1 zKEUZfZp;}x6{c*CAaKUndTQ`LZ@`LQG4}ZC6$j8@1>d?`EL~^V7Caz!As=VLmg@z1 z*iaE90b|X(1&cJ=dJhV>3{bH&z|im zM|4yeTm*9DdewkP1q^miEGP3o*8%pJ*_1Jd&__ns?hJQP zAdp1j#eM~Hl*#joChcg!CE|yDk!^6#{BCjZEQv|y3oN%-9Dh8CmrM~s{-1&4$^McP zN+Q-`&S}r8&ZzF@x>XkJQxzJD2gfq6lybEIx=72*RtsPBjfV_aQ(y_sG}N)!G05rcmHPOe6>Mw`NN@m zEe}F{eSJIgI(e1`7;|B-X`1OShFkYV1oeS}#hVhefJHnSW*ezLN}(51;O9s_smLaJG=#KuZM1(#ZcdZDVTKe062vh@!hslwPTN z?=cqbQh& zKv|acMr~!c5@chi-Z;PEez1Np_>mfz%zIm7Uk&`4ntWzim6>_l@8RHtvJs!5?ul1= z7dW9z6&fnQLm)lx}9LIQJa0hHqKL;sgvmA7sqgZ@e)bUo_8dl5h1ZtYfOUNT(@ z_p-CLuF+_Cb_LDuL&fSYE)3 z#9+Hrmy2P^cgddMNevp7@mfuXnrMdFLENI6sTv@WZ`G3NWuPYMV-!0-h-_*+9uMr< zhWkWk=70Er9?~YkMKG{u_9_)D&9@z77LvKAcG^ zJ-Sv>1+xNy)L7AXp@Y?bi%U50$2PDs|x-=zcf6j&d2-OEnB(GJ<9+$-g-y5FQ>EwP@!75lgA*>7|2~WPBDXvT`MJ zO<{n;z@*WiBxu!Kb%)5iic|bCHA2s8V~AhR#|TWF@$5QDr(J(=DTNpl*M>@oDJkzF z0HA;*m9bi{wbQ$6URH%r5jUZ1bPq{#bb;hxD~qDU-RBXM2jcrJo&z!ixO+&)oV07ISE;UuWJHsLFn~J>N7>; zX;v)48o{C4$ZOW00$IqA%vxw#3@Sj5bGzC1t+)PA@6XUbGztZWBV+=dgX9Z(dp!#^V9nC6amDC7-j42!N3)AMvqO%Jwl6B?lNJ#C(YfnBnj|N_BbuTtb&h z9j;!`43?UPnT$=`u6o=cys}o>SfZPI*w#aQ7jzP`4+A3-1YH)(vwHv^icLrug~vZY z!0Ez1;hn}Ehm;WQ(glGGZfUl^>x0@%n@MhK^PBuxVGNG&wd}kCo?!r=Kp*N0{~}k^ZBONs1f)59tRV$l}t1$4z6Y z=js`T0XJtjKGVx&4O)+VGl8^SGm!nkuRzXgzJ0J?8qc9GX7T$Av=jWMpu{J%TWe=? z!ae@?*Y8OD`0vHNO$F++xlzD?56ZvWZ}-*P){}w<^m>f(xbwv3k1OzojZBqmfAktX z-SVwV>kosEszFgFN5p{)hg1`&z5Cbj&1=nh;Xkj5!|9)plUAfxIbQW0;N{bT7S(fM z5>oKN_5tM&j{fs~)T@tyfjN^3*J_Eww-ZdkhED4s4S)pep=>J{s86P~w<;}A?ejb4 zPUBm|-nLy;ycXm1OiUK=>^jaLsf$iADM(jW zEl`meyZPTW0urFSarGiu&~EPMScMsjL&}*1fn;tEQxCVqClgJRY`Gd3kYe2$)C!$y zbTIv%m1#r$v&aC7x39dYV;*RQBekBrdg!MsFd>oFlqGU)Ua;?yR8y+w2e>(Sh_k0$ zWWcIYD^;<|Wnem;=z`azn*i|be;p)pQN|Tx`|b^NkM4ZMWO*yPVOQ?%f!^8O4`W`{5AdP@3?o38zEixp$;QWI^h3^`y z*Ncf+y4PW;ckusNFC2wZah}pYdo2;Xz5D+8M=gTe^~`A+|9_6!4%&yr!~MS=weQo= zj@Lc!a z`w%QY-gwW|{(;_;``|(N0$dWz*#&@3#YWzlbrfni6Tp)|=KwjJ#HYE7C1g;Sue|hw z4mVB}<1~&1Exo}B=dEc`W+B-c`fZ5=t)XN-+Z@!&oJR+&mLGw4 zlKa5;G%{V#Btw3uG-n-;snXz{kvx(>3Mrdf&KeT+5*bsD_qeA#YF5vIx75lFdR=|F zh%nwGBI#x9h;wyR({={K{zr^f68YSREmrr;`8g)8CP=mVDTN^=(g%`kZ1tLIw$B2B z9d4U+g_uAFw#Q+z;EYb~yDnqyE=l$WT8|hx8TlBTAR3;(WCr?(BTY1SEVt@9+xI*r zReplt&U7H@ZKW276v+umV?QT+HE0d|_4yZMp|2dAh7fa5P5OM!WDGbJc3A-&+6_r? z105Yss}=idA*W3Oiu;~m{0~{;z@_3AfC{S>#}eJDCp-hcJ`0G(M12W7p0v$OS9G4g|Go#)0s{ z0BHb^VOS;QD!YfkpPUjM|4=4sY+$nPm2GtMH;cWTpTa?)&f&8h$wSt)N4CBQrxs;* z#gNjU{a$lZj}z90!xgJ1NiLh?ZYR4Y0Wl0R@FsPIoCd89urgLF3z9GTP-co-6Q#Bn z?g!ANP-8X14z&%QKeu~`IiP+NY!O&vWnQeiW7 zOjxRvW-Lo5Rhlo(ih>>kau!Ls9k1CcdKqjc9vswazM6;gdY60;{ZrsM=es-Zk_lV~ z@PG^t6dx;0E3B=H3rjNPjtAXCQ)kX{_A3a*{}KJyC^IL41OGw^oZaK!meJ*F6$)xN+IPpR0ExAX!8-GWn!2+jl?-C7sHuUozy8!OWl zXFa8j6l7%Gd-Yw`z%)Z?)6#k0C9l-hc#RdjSzyXR`@gYTd1sNM`rV<#UR>Yx{dQ2P z4mzdj9Npx+ZN}&>0!m8VGDE4P95%I{seg6AQeVEm%w!Cd^1t@0934(Q_3iXGAm#g3 z1sLn4oz@)$0waoMO1^q5S3ey(2o_A1VsEp}?^Z*gk$K{;^90X8qjhItbb<$jS>_&Y z{QA|icd;ZsEx9FjR^7KL)~u8^`(ODkj)jo_U39!8;PsG25^T-hrsZ4v)7#k(840Eu?Uq$^{v!3au-;(v z;LL;I#D-W3$zM7H**qn4gp8W$IvGkgv${w~2s$mQ3&A5$|IV)E=WW0(o)kj1f=!*v zrsB(&P!ADsC#azN`e`RNj^3vB_vlqBHQ~dDp#pKjKC|a}_*phn^@RVZe{!XC%xi*# z=yUUPAZ?wGJ7=}|ZG*}+s=TL4GIW7eP6R^Eo>fX2i#91swB8I{2G23?F@dE=+O!=w zdW&FFl10!WEDfYTe)_@h12o5S1RKJb&>hcVTc!nc^S^o1s3NB7YW{)bp;(qpKjaG{E zzq91`-B(|UPZ5gBB3&Y$yO79FtInkJyR%@KSz3wWG15&P;fc{ zYW3NyeN_Ap9Vn_`PVriA1kjJmsKeOI%!)V3=y60Dj>q!fjEO262a5QpD0D=+;>Dj8 z$E3c+^>ynowY{}deTyV^0AZ|Jv}kVr>1UU?S>#3v9W4#wwtYQDmM8C!@=d=|$XTjPidVLwS?W|??Om3B2< zx zE9&h^?9$_LqT+A!^!xl%x>N0W5^Y9rj6K&|icBMm!k;m3zS0bq(VcDfl3BkpG!D+u2saTt6nioxRrLig06$Pd*h=T+j9!S9 zN}fOlzHZSorYGyqv-_I7#AaKPJ5oI(qH?VK zxp|}JSTBkdpC*8b`{ip#*{4wqnl&_j^2RfwxbFs>G2@J`ZnPW7E@g7kJ;i%QK!X#5 z6;*Io#g4k=XF?{Pl)+PM(W{|QP%c1&7Jevhr|rwP_wc$qsnt32E*GzYpOIe#NKv`o zo-*ss^sm0CYI>^q2tgxT4&yIfH^yfKBC6I&`KE6ugtZ416zxBdp^=Qk&oK{1{Ai#W zTDjWuPaG9K5fUFHFpw{y_k;bx`p}SAy;Yt^@c)>) zNSa#fedV`lvWl`cg9QQfK~1@zuHBU|C*(c)0Q@-!n8Xm^{yR^jTgCRj{)W$$|NB2W zj}+*uW@8;%w zfskKO`c`1iPN2!h`X52 zq5i0%qGE4v59Ecwj-8*bL2PHWrtPo7sUv+1xJ!d$0iU^x0N|XPEX+uc!eM=xYhktR z4sn&u3>hUQJFA5FKC58hu5!oCG7UDsqC&!h z6<^8eH`wsCa$cP7Lm5?V6&h%gM!&s%fNg5s0nX zDj*QQS)eF|UFdV^T~_{NOZSl>zQQiSW7ZdAQloWX*_uucMO^jp`S$kq!sqn;?Z~i4 zh=1~J^6%E4O=@1mQ}N0*@vNjGnh;>|0yE5s{lbvgc2!rWKOPcqCV79l5Cq2%K6b5d z++KO_?&sasO^6&sb~hrbCSd7cBML#S?8|yWE4yJCV-Q&wrgB2gO0o9${sgh-w-aE6 zO~K6t%cfQ_?#JhGCjJ0}faETUzD;2Kf25xOXVxCvx>jw2d?pQR>vae-gKIKSR2U4p zHuL)AKIg}F$ouboTag;FcHbfpU;?ewgqO3oitk|v&a}6#nus;+g#W0O+TXHRlfu4G z!zgc2spbFq{tj%~O!qeJYhqloRq~9XXHH~b4_zE`WC8a4#jAkY4^89=mCkB21m*q- z1hcA_=*;q_?AFEyjuXuj}WDg~sT2w-8Tk$Ir*f zOBalnSoIsvht%~|9UX=I`ptQn6Ppsx`pi&b6+{~1SLfgYd!?MC;QP$>kCi}J9BNvz zTGakeXYz5(`cPHHYV<8&OOuM#Y(2Zs5T2Zt z)@VMMiMa9wa(_zW{mcs=rW``57%WSm)pUdVjSqZjz`mqlhz0^Yv2yz^}XEShSuaU9V*d1gGsl` zC7MB|K)Y$PqBV^#xfgmRbiX?$(qIV{+W>L2I#hfMk^3rLuih1Q?UOrF-h@76Fr9<( zWEusFLE%tdTw*k-wwUwKxGJ^xz5)2US&4dJzYnJtpN2dC@8>sdXiqI=R~!A#uF+ti zT|u=9mV6R0aDfp=`-#;U1hWI7gZ2Zw9PS63e3m~M5s>iN3mUr@IMm2+9gy*Ma zrCPp{$xc+8srX)Op*rSWQUU^!FRax=uphXjPiHb3`h)C(3!ZvzV{X9cc)3mXlr|hD z_1WCP!Cr@=jHhpW8G}F2d;_V5O=_)k-NnI9={?wZ=K?~&?{`wYOJXEt3bmymPX`pc@1q=!Q<;RYz^2@ zeTW0dq$UQN8|1b%?e4M+;QFZHuLAToHUe<{>ChUSHYbj&xlk(064!UTda~qLY=>Im za(OsRTa#21ya}75`9@HyoyM@W$05d_D4$yAOvPpYvrUc|?LY9}ACUh6X9E8No8U~> z-9KIPx#4S$watFFI)45fwf+u~p9AUqGYju@8(mNOc5K5vEK;(6?6xcuUpEjI#+NP{ zFU3T#yh43resuL5j|`uTgkX7Zb~Yi81i*es`^;)~{r5NW8l?plf=PEwndV!>>qlQg zGi9zP9c(NuV7_`udHCOs6HrmvbX6gqf>gB$E)Ed&YsR6JP^Nt;U>aqOGhitDDeG!4 zYY#+vsXHwj9~(1W0oXvgEzX=bK$b6skN2klStxx#ChI<><>ZI%hw#l=0d5$&D*;V} ziv!NYx@1p&W@c=J5=!~`^XKp^`s*ibFZ#apLM%Ng%Kh)J_iweoGnoX* zi%>-<`Ke{;e)k-EobE~2Qyzy3C*d-@tUsZOc!7r@b*Z{f%MH+5cp-@kT*Tm<`)vsU zIXAf-4Ms&JKB*NR>>bG|$Q<15|F`1`FxMp5>mtO?%|YGa>x;JwvD4OI`oX*DH+^k< z>PrxN2p5_5hz+3F$s%qbaR)yYkpBz0>7E6wbA1VXMw{z3B=ZT&2^j-87j6p!<@7gv z>E%qLPXZ!2C4a~@#-{S9;A`(_JV{`JpI(I$COR{?7X7ZY1Nx+BgF3(E+!_X zY$m;&Jt+N8E7!zbxBOrf@&x(-bTCX=xQI|!XGv$9!$~&>O57Kcjz52(-B{{RBv)pC zBq(^YMykKGxCk%7jgy6$bo!A-gmp4L4V(2QP)dW5gP^`7oM(1k`4ce6>HpbVUff6A z2Z43>HbVje(aKqAH4NgG3XJ=Be+Ae%Y48w+J?)scZr(tk6HpONe?y`^f5nrDVhrX^ z?rp4EBw>g2eHHog&b*hwZ0qEv;trCI{`7JbeQj-Rr1F>yQ{tWax667tY86SMR4}2grR@eNLOwBk?6f23Rs)HgJS@ z?`g9f9jzYarZw@_yt*UtvJhpO1JY?-z%oGx0l_4Y{@oML4vz>W)LZ}0j6pI%GORt^ zI1XS21y+}W!c%_&++}9+>0D-qDGy(SpMPEcxF8qb6SXcZ0v=I{B^HU`OcFxUHoHma zhPk-7a7$})oK*s+GhHSfy$lFjZ&y9ocNazf=UfX&We}G%mL}Wqa-Mm%n@yFlAd_b4 z$c-OER_btxzu_e#O@sYP!Qb@blxdOG4)4c(4qfpIom>Enf+<^205_=P@;URJC zTIJ?J9UDl}lO05?V~I%@2V*R)5SoraM8|L$45>OV9kJv)z#E;KEV3o4sCDV+1{}fsR z;cQpH8hn=oMmL|s6EkT)!0XeNblHgmnDpju(~=m`Jpd%_z$O&`kUf%%Aj^?BlnYIX zF*rCX>f?O%!;j$*5AXEr@3VP*>X}TL5CDxp@Xpmv0>u$AF);;01aG-hYXZPMKK49$ne;5);_wY**d;lygc)3q;herT<{ywV14jqVwF(> zvm63%otok=@#pAdhb=6Z(%omR79il^wVRVnReRjSJ+PO_XliWixHatc;|Cfv!MYVJ zC}&BB0cFI@Bu*uL*p}wyQRlR#Wr$5p+HN?!VSncXyjIqrmE}m`U4&NgcOU=-#{^k> z4E^CyOmBi%4cZLaV4fk!*RI~RgJ@}56Nyifu951-8?bhEW`f&5kWC$I#(*fFfA9>S zon)^nPg9#zfge@l}dM+DD$M@)o()uYAl^BoMfTp^bdjEXv-aQ0s2gHr@iSy6o@ykX@4#p_vhJ=L7Pt{K> zm})qcVBW%|{60bHJ2>;-3scR*(H$dDQ+m%=@`p+r>Di>US*`$S3)9av_U>H6p;tQ! zu^1ow?0|fRO2ptyJPGwuonp1hB*okw2tWWQ;FvZ0!gM^|2Tsdt3LhSc;|G>Y{}zmm zjYlb+;|!eKQ`-!KK85G0WJeha+HxmHMMXXG;XDZ-)>|HLDD?TSiB3V8z@$uL_^rlB znODcAZXIzFivT5vLHjp^q1GNqNjU!$<0}-Wga9dL>SDs_i#ZJNi7=>?Hx8dq;gfR|;0lV`bGx~2t06ft_N4iY z`qKxEZXPBnr0)-#Di1f!s4t+sdy+Tt^!^tZ=D(PIVflY$opn@H;k)nm5R$?GLrV=E z0s{yNDB&QT(%k~mA{`^rDcztTAkrmBH%LfHD2>t}2uch0_1@n->#TG3U&CV9YZm*R zy`T4aKHu+m50#+`z!lID{GIV;w9bBxLsHThA(z6>M8Rz}cp+16*m`N(b$h8)GePr( z%!@>3Zn_u{cjcof%p=b8!MIF_S7?)%&?kla@gsvr*qFvBH;WaE8aCDt;wIS?S(UHp zLMt{AXz4Ia2L@yqPo}4`8x&7ftJq77gA|ME>S{CxK8xIAYFbKK2Kw8I{dZ?8N5X^OsI6?=5rNa$?N_9p zQ8BYUDLj!S;^e+Nivr`JDMR48z%F&$e&Y3~2^(c_6*Drj3`C1|fimdHNcx|@q)Pyi zdjq!kK-3H{(#rPprtX#3c2PFKJ&)4rZf1VK9Y!VUe*BH~HP7woPrFZ!Ne}jCE53u) z%`S=G8?&IW`fp|b>c`+SB2lo#;yhCWlC2=qUq^seegM1%KmIhq|48Tm2r&pBv5T>L&# zXB|Y(tF{?c%Cv(1fX$O9r8S?vTm9(LKw=ECeZ^Y+()hdOV|K?||2J^i|+w-CBPw10B`~3mtef}tvyJp-wnK=69@Gzuv!W%`YLS8bl+PV<)$!(*S;Vlo}nO}l^;Kl-kK7e!w(b%gr{42U$V9=!cXc7?jfK@UQaanP1 zdK7!BK4>ZMWv6-Vw?NQ5Oa6fX9C~MF{Zrs0_U_doAYQ?G(@(|4LC6IFj0=^30^K2S zS|Bb%(W-)8{F1=sqH_cN@35RXFA}=DT)?>Htym8D@`BqtNLsVsvd>e!Aco=?C4f^- z3CMpZ9x5|!JqI|BZ_Wb&sr`SfYt!{4=twx!UxEKqWMt%xmnT4A0q-lkz^l!<+PBo z;Uc6^{P4|@Dx3iWtk9*qT{&uDlXZNNqNO8iD+HL-@58pNo#sPcG{lBk-76j+FJo-g zx^35f2-5WT>hKJVK0D%%onChRx~EGIgRn#%USz2v9^NZgdyT>38MPdzuj6=0Ymu>m z8$HEC7%Y3EC){rMQIc9|k_;8WET3*eeC^pv#11E7dH zrTr@yi>o=n3rJ3o?O;TBXv`=E5gZVq5h;0T6ma;k-@I-!F0@r=7?dO>5b1OF(FRMF z&=FUyfe0oj^8LwS0Zr;aey^=tlktt#MQcIL^uq|o=qdgKEao3mjETr?e@Slq7i^Kv z#q==5I0~30hKB^429*_XfPh86V_@iT`5II>jmG>o*tkPA;F3v*A4u-IHz(@?x+T@- z1t$E2>w*K+rTyQ5&-<2cnbcD zv9?LMBL*}Eiix1ah>KdR^%?~Y6JVuYIb~-Mrz08$K9}oV6^2&B__p zkTTs;pg}(cgv6Q00gKf*T}T6ZBZhWvN7{tMG*o+T77AioJ;a&L`mQS&ml@8wKBeZ&?;ze;`2wYRXsP}qxUqaxq zgt2YeY8#EzAPiIZ#BE?8l*oYih?zFl#=z`ZcGr|(9(oN3>O)W26tzM$;?@8@1WdSY z4+#=m*(y~7ql19cIH%A?<%Tz*{lnvr&F*E^x{mj_qgL;JHV4)HjU}+< zrgXifH>fbsVCy2YWCUcnUT1S+&q`(h$Ydw7XhTaGALJI#tfI-R97~O6Z%fUJD;0pY;?)tHbk7>*OoCBFip)wb4LAFm(e5dy}ywu@};{XM~Ka) z`E^IL;cb1s6OqcE+ShnXpE)_t87d1s9xJ!vd9)+r@Ap0_hoLs#MEhN5E*Rsp$RMb0 zn|c8M3ayx9b*OLFwl?5muOXC`>_-9hMG)Y0rpS?p~F-OesoArrkiT%8|a=^#PA^^L#yd)%X zmPKoTkn5G6Ep^b?1rMlvyX{4G#om)asib|uz9=P=LaRT*JrU+1_<}<4R|JP)b^_wE zINZfia)t?phzPzUSt1Ww7UQ?wxB2BzCnXzhZ{bXS*uOiFhzqeh`%D?K5EpPT+U%rz z+ut+LX7s0}xR8d51;IdJ^2%)4^)8~_<_dNtqH09Qm!O$okYOM>x-_GPM#=CRH$u!I z<{>sn>T*^JVj87ym0X0YT6k?E4;SyGX^F`WG|P0)U=@wU6>qk^)rhSOW6@p7>A}WA z!}3u`X5MJMcU)9%39*Rjtv@ZxR5)aU5KOnUJAKus0pN8_3+U8j$54ie{+huJ=!NBi z9K;eTKnEgS&h4guSw`3Wtr#B!rSIh6;;9+*Mj_fZ&H_f!xSfX zy7EWe_P0FcRa8`D0$*5)E}OXgsbTAP16`2xPEd#k8{rcXO>WnTHs6+D&6;!@A0NkO zX&%W<%`AdffXw<@Ze~HqDmyFbX}vxS7Fv=%o4#A-7~M-wNntZaj|S^V?RoQpY3B6i z9h=}G1+c;I*AHO4BC z@>&rtD?(SU=u#z7PLdX0$SqZnr;I>66_kt8@E&?AX1JFaPL1lq!Izs9DU!r07fYX) z6j16J@-fZlgd(~OV{^L(R;q?-%4W8?GS_h9hxXoZJBp-3u+ipQB!$AP8SpTRd*wH< z8y8xb4+yd8RejTx;oc3O&41X1!N<2;4-<{KaIiZ?N~bpA3A-fJ{V2oOFnDAaUDg86 zV7_VTLwrC$uKlv3O`UXLqcwI8*Vf0Dt{!)etllP2_{HFL4FSX6e|Pn2L+*i^7;a*G zW6!i+OO^<0Yg@2ci|!3Z0opS{)-&9M{4J0>d}Z*=EV|DaKe>gVkn3PR=mM=4;TmCS zoR{Me0{lS&b*sn*({f&VvR%X63#j$z(L@zQ;qr zAqtS62<41e+pH-LGN8z^wXs>-*pOiOH!;gP&I)E`Ch!?zCS)O5X!Pmcb7z&tJ;ROs z6bS+4iHkth&hzsxKeV$ZsWzGHYUlKC`T;^s#Y$}mJTy`guRJ!+ykwSrAg;9lqZj?% z&DkW1uW$?yf>e?q(ITJiobV&`Dm#@=DPJYZEE>6b*rJR;@2gZK^ANNAsFR51aELhZ zMl0$PcSA2mwr~{NPC{Q!MZslhxcTuQ*uLi{9P12k$;-blMJ>`6Y<1{%JY)l_lZi$0 zb4c)D!DIjyMTGd5%ArmVt4|;Q67=?7skHt98V%kiE6K@lj3rl?Ek3-Ve`JhUbsWvX zxL82rNQP$91R@VQwU>fg+EmUBSvCey`2aBuoAmZ3RUIep9zg42p?xlp4~3DyMghmP z1JQ@U)$Bm%dfXx5^ZPhert*3E zA1s)PCI%LPM#rF#0OGB|r{Pk8$q2!bk zR9C=*(pw zC=5J*&hHQ3KN&KjZd9imr z+p5ZL2pULueWie;|YQ--n=lH4CG;8jFv$^Xl7enw4n;ePbTf5g;_IhhbWV!f#<3xNM_zf(&_Y~D`uJ9G?X&`511C`X7&nQIrI+ zdzd=R1N}h0*3p$L@t-$0pSGD&n;w;=y{^9Je^htWG5Tv{F4l%y>aQm$)M53Pel40T zjPsRvT}J)Evo?i^gRieg236X#%pBR&jLfc&e;z}>>q&XF={ioi1k}GH$$n+>N<6uY zK`lMvkYgY*Llr(rTIuP1=U{#wZsjz)dEeF$ax0A8NYs3sm5^Xsh*Gqkb_)15C?^R$ zpDL6~p`*{zO{J2A>Ib80+zVq13PSa9q$^9fxJo|McqK%is-&SL<9`c>H{_^R?}#t& zetfpKcM6%a(2L*c`5cVZ&p+S9vpR_~8QI6v)}bhf3pESpSJsn{AR)Lc7t?vZe4>rRH)q;lyFyOvMZ@m?9b zEcB;-4R>wIKljVmubnM=^@EvF?}c*pS*Gu6ZxcVV3RwIbF3K1uYf5w*Su1H{`ruMp zc%=20Np5@Iy*wig0@23ob@B4iwv?-?7G36=1IM|~o$oC!w;f7}O1~V(mH%Gz5&OAr zr(#UHAIGRhNF{wkRmK9P_ujQibd+90@3DcQ=9B#~CB9WbgXs2@I@T=6zizu{vS{K5 zD}Tpsr5ag+sg6jHN@bC?fRSyxyRu{gH``dr)@JCg11;Jp`|Av0)t398+z)R`-kY~H z;4XVUs7{VZC4E-!No%03j@Hi15iBYO-roHcoo-@>5nS%0me5gK3>y-;F!;3_HvG+h z;MV?^2~B86s@+z&);)~+$8=l9^v#aLs>W0*r}4N#qEvsscYSEI$9L<-yi%P>#o58y zpy59kXmrs8?7pN#>vYik*aOvRnWPQ!@vW-SOv7xfhriL!aT^}c%-5HUx2ZN@yBVOh zeJ0KtOMCk%$jH$!I$*xRA4_ljawS~`)BCeAyU%tc zKXSq6xZDT=TqmneNfbF6UdwA)c<{Cu_3O!HuY0~n^%28nAm42sRyQARi>oB{$MTM#NI?0+s zYct;3#Os5W|hnygHASv_qm((m9>#|1L*f)?}tewRlMW zh@%!j*R5I}1m~O|;>zMDN4Ih8+bq?DUw)k1Nl%y6~ak2_C4!2S~ zLwjuOia&+SZ)Vbv`>k!ShZexRaf!9arWWEpY!u9VsaG|MF_5Bu6>4IOILj*@5Kd*_ z%xBub!^UsV9(Qe3y?1e(Oe=MLjET@C*}dU?nX7j+e0pNl#fCYllC%9Zf7HnZ<%MNd z&NZ<=bVNtV+(Dz7)3DM%Txm~Ivr@GYnXjpDp;NG%XFGi~Oc_!ZqJ)+@1{@`9r^zWf zPCtc+tG@4v<~Deo118J$=E@**`3Z)y8mK`?=n;~9yJj{`D4geeVsmL}!!Z?X(V z)j#z;-}h{q1BTW*H(8~v@E`~-=|@eraKBlN7$?rC!a4nxw%VR$ye@;VgF+s~lTrCf zdv$L2%kH!}7Zt{{kF!m6Fv};zJ6;xDKctuV170rOr9s_-%mIUjkuh`eU8i1n`KVr*cJlJd$aAkb(*UWppr(gpGe;!J+Md1)VS}hP<@o;?=vgwKWL!?a zE-Hd`_eY54^7HxQdkEXrleC7ltj`QOYU$6py=eNz1BvGlU=%CyUghRE;b>eli+C92 zH0AQbXVy~PUwn~>halY{S+7T=jATJqlFa8EmK*fBsp}$@k)T0iT8WJwy@cJU==hmq z&l=Acc{k`!r+nwnev%yQITvsByl5#0nCso_;H(k{jB?6~L_>+TA&L6C(vk0w+)O1! zhb^r~M?}Iy`Yxg#&&9X_&61rC-}lGKBdeDbzOkA=HiWEyu3sNeX33J8%(m~PFAjWH zZu*^F!?_x+_OnIm9oxEii^TJuuk3jIeVpFjDW=N2dk=gJIrR*LNvU9zgM=Lj+G_4p zT;!`r9Lvbsq_hHA9A>+DjorAG>;#tkX*^G7eAa)AZ*+Yq?lb;SeM%{r#p2>=B_6RN zcTgr7VBHs;xtl%s8TLW_+xv}Jh7A2JHx8i~0YSyk#d0S`>e~Z_NM-5LnXEfG-MFRW z3XfhAEQ?SJQxQpfKIg_n%Xh7+yAGhyJ(LRB#@R++2S-eGoy19xpN}@?@qef#pqu_a zYWDcIquS^d>+Nc>ZQ0-2OM%sT6HW0(v%37^#ll#8RCC&zI#|rY$ICTCwo`qh) zbgjOl5UsM(;15qV2uPQX8ah6XVefWbz+OE3cJgy?Yr}gjEy6)H>Upu|{dsm3JX8z( zh58sAy?5X9_huvJ-pI}P#P7#B=aplhOpwd8DvtI14blXmHZT7K{(Om)=C6V9aq^|O zh@oY^B$$4ynEU6=iaUeiRkM zk~^GL(i{|IcjJi)6$T?4dB= zLJ&TET1wO`wKG=Tuih?+!(4SjNXM8?)y(=wSEoVkFKos2nnX;%f90qHPgPQWEBN{eTUt!iJP#xMSzm6i)A2nYMk5gc(td`U; zKXDx#kqmUDVF3%RP>)>kVWVuQ?3=0&N|GPml&crtPvC|`&PwuzjS3M>3=b$#UFwV< z{|u>ePSVT5K~G!#z`s*$8`?PuyRjoQ8WK{LIP2kG`&C1TR+WEo;hwbnJUfHBomGJb zSJ@FcY2C>$gT}uT(G=pwu=pYQtp(ZGdjXGA$-G3#;p0Q@Z&GN^^S1UM)AH9Qg*VV&%1sHI%`RbT$Gj*MCwhC`pVzaZB$7qzVB>#_0sMtT%7+jCJQ(#;rJ9W=TyAi#;?qDAlPskd2Q$sV+5c1S^H)3*mL z3okExM~Nxsh?Uh6b@=(Mi|J8Nc$QtE`(6y(6Wn@}s!;2##R+|hAecn6YdoYZ9Fd%|YVFn3l6RC}KhJ$fE2mlfhqq3I^TRiu=1p?IvZM$U*h{ zN4{dCMYkKz;}u#i^jDwO?{l6J&Q`!){+trh>OSB^^)N21EPY;e z^EI$UJ^OT=PiK`RKM^UoWE*`ew^F?=!DYHXilz0N2Mx;T>t@z-{&~W(duBQ8NY%6Q zWyl5kTqz(#ma?eKNdIM5<>!|j?+I*Vlbdxk`|_;U#C@HIAG@bX@vv!X90kaFoid(Q zuzsUWTRb$ZIS)vPeQfz6D&k$6?_yOPW^KAa(RSw~=|=6?Pc2(^GJ7SV4VBHAI{Spj zX-onl3I_}6F69RKs(4vZIrU~LKB~LG(Y*RagiyX{gZ-4N^|#|&=VxUoq{Ju_MYO4N zcy+|4PS!|*j9KyYSkhJia+L^;^`KO(aD}i(_5mLB`&)B^@S*bi4zeb1?*=z7b1`4u zAteWoM^BB6BA0!1NQ->ym6RnT^}k5USvQ=ecFr;F(02 zJ5W`k&2tc<1)FIZKmTUPn#M~Noxy#tJ5Rp2V({~)5^aY_cGr_b_vcm4D;jzx*%=w- zcd99m)yj>UBk5Bs6itdbMCFm>4;b%0H>}X$L%2eA+YW;~?|a=tV~w#e9`7X#yato$ zh zs$F~Ub0QVxB@p0n;Q#;tf|R7FG5`P;0ssItV8Fgcn$t%izCK_bB(W2w09tq5)mPCaI!ZC*_Z(U9&0rk7K#g-O9zaRKL5nYbW z*{L!7bIy++5&~c-8Y@{U-v2qp3Ch#o0z^;)uEK4MRRDjHHh$Lv`up0sRVa zWJ$mT5kP^oGnpoUs0GlE(-^r93}A6ULjnLSXsJRF17d)Np2ed^N`T2GfToF)A}efw z3I(X@bGfgEiNG4AP+jfB;bkN^VUFJOBVWhYPSk17)H_7{G;P$QM4KS!2k!Oaq){ z0CbW_GBy9%eiu#%2YjykH63h+i31b?1rVz+gvWwIMY)XXvZ6Npw=(K1t%x~4B#_df zAECE2dl3RX25^4p><}k{n1GIau=ZmfK831XckS>Z^4eS4KXjRNDpa0xsoSzbx#fzr zZ#&r2zQS@+^ko!BayG*|MEwuMPMSwR4Uxz25#Su(P$_gZTveHrg;G!pET{_S3%$j$M z+ijw_C`-5aZMv3+&h`AEDzltu^N8P~D|>OHM2G*tquJ zosjyF+z<%-_jqY}-wqsiM?aL3DQpz-cs|F$-2#t7(#FH7|ON%s@wj!l+jLGKJT8s!w^MoS;I z%cB8?bVYt`3nL1P2ut;CBvKbG7iC16Qu^Xoa%r4&`ouy4a{vmZSR)h*1v)jDn-$q-q_R9Wz zc$l+O_zyYEINOmM%k|g8UY_a^|KbUY#QZt7%L$t*H zl&qRLR^n6VH0pNiR&Aj1#&$ROK>74NtwUG_Wd#|uvBHYMR(+d^ZjKm^vc;14{aq4W z67?GQNv#5UzLc3&i-rrfL+qI_6kW_@2%}VepArKj6{(WVYT)GN1W?D4HXs<(8+$3Anm;hwG501M--MBB^kwBt$2GAkCViUotJVd-#<#t);D(? zS=?=9y!`p~PUZOe?;Yt6{vvk>{)vnvzfEd{{270e$Ku~3VP#(@$taiciN#+g^dMaj zQoKc8y_|)@_sP*|(wq&ao1uyu+Dn_>vpy$fr>PsFItqdPW;vk!z+UF?uis7jhb~d= z(Ff5IGwvy>Y38Y9DJs+vsfcQ8OB+l1Ru{UIb$mW^pGi^#y@Yz74Mz11r4=Py=gjv} z3ejp+=GjMTXG_o43~QIV_GgsGXT40Dp&O_d%g2t#v3+{$k7WkWcK`a%d{4j+!rQ_s z!*nFl@`mHR`zSqgAE$SmmymRzzzuIN!2$gzz#K7PI})JX2;h_jM0Wx}fB|wi0lEml zA#;e)ade`a0sjvqenm){t8mWIK<;+%{J3EaZy4fcWmPzACF;tMGa zoY1Z5c!lbQY{85~)kmvF*r5@iL?e$xV98iYZKT2{=nmv3u2Hj5%cbw6cTk_wbiDkIJY1ss2-|a_Xmr6R-1H`_Q_5((YH>Q&saSZLeY=@>v=f{W$Sm6%kW_+SA96^&PaPc_I29 zJyO>z58JooY4PEAC^4lFvpUU{U#GHthG~U)=ui3HtOutX_kz*+uc5MSxaYyD$7&Zo z7zp4@2qgFmr<4G-KMSj{gBK){f@~cUL;3?_)OL>`3gavJB4kA;io2HT%_v!McH%Q8 z&5SOx&}dO(amTC+*40oCjBXKHVO(L){L!p3yc3L7aMrk|I_%D^PHu)2jgSA(9gf>Q z5f$RrbD(mjbfa|DHkdc|d6jw9x}&;deY|`&-yYu3zzV_oAXwTYZ9C}qi0`zXLL!Pr z`R00zbBxo6VE=8CHj=fFN?cznCn>v^RxlGYyPJZXP@TYU8sHk?;xW)tQc}rN7F1nS z^{dP)aVmRM7-kt4GFEJ6xhv1hO}f>TvF6@?a#U}dDOzZ@);M@S#Nik7?h+?kEwDEU z-GXGuX|$|gb6?$;{&cq_*CTD{9W(Bh{OgW)Sio>>a-F%(xJr76y8+$n-8S9Lz+=Or zlS3w+278K3hh2wTNL-1UD|1$qTecrfVlV%x=KOdn3T6)1M#?6S!!IRwF4yHcNNaT| zq8(&%K35fS6Refox;ma@L9}o@Bt$<U7AQ4YIQB z#9gL$_pNNYBY#e_c?{o@@l|@KcJJG&dXK(S^trk&ju|NGd%`6Jgn}36J8?Gi7DX0d7R46g8b_B$ zFqIcNxSPdE%UQ@m-oEa6)Xm+!{akzf9kU*J4;g=5nZ`x%kG`mU$d4D@YLRYL zVku_yOIkD98gdf)36c@gHrh|Qo#KBb^D_Gu)Wwy9Rw5_yY~rltElk{SI_}38OB1v9 z%-F2Df2KP`1})nhGo&g(p;~p%GSLV$DAvWfz%FImHQT;FH0R{pInF-+CgmL5#$0+1 zr%#NIGf$Q-2me_&Q7l|41pwxF>SI{3ObL1MrN14nd6O__5K9r1?=QeMyuFU>MkBqD zOMdrrE#ZyKA9@>G<#A-s&Pla|fTn{b9#JzAug5 zmFAxA+1thQ`(b=czK)+dJrz9$gEJikga518(^4mKJ8GMgf2#eGdyAK=ot!_NTaEeo z827@7)hYg1ojtOWIrSW01TT7L=`PPyuZmj zeYT87Wb`>-fdS~LX9uo1J_Jj7I=}*m0M()+oti)Z2jCY0zPar!-tL&F3=aSqT#ywh zM4J-;Km;@(m1&`|UkdRKMz+cW`e6e?pv5{m-VSzuqR2n=IdZ4k$pZjC041E1YbW;k z%ix8zgncHjASMV7Kmw$o_@nX}OrJAdaxksGwTMv>G5#3`Tk+H25&M@uLkduavL*sU z5GI0I>?fq{zj=&;CjL7BMkyFf6ai(O0fig#cI^}nDiHePAFUj0_!VmW1E$D`VG@8q z{63gu8Sr`Th$JZpPAvL9Ww{LUThx7ZwgaL^0N~!xj2;;d>_b1F!hkrG{vPw&-Ts=W zbT`rtHb2Pxvb`zA35#RrhB8cI7>BV%`b{91hzr72qnP?LjAR+tnL4ot2Ue|{{BLX? z$gdP)-H?Go$l$CnK|lTPqwfqB`wz|#0Rj6^l!!pU5vb?3&RrZSsu&!gsrd7{xjsRW zdn-md7Djn!T{Lk~?RqUME9~m~dXs@Wt90!4m)s^YkyMrg0Bkb=0OvRWVE0Q<2QvZy zK4AdB$~6GMf&&2H{$-uJ4g>)CouovCR6W+t^xShWmhJ@}w=!3@AIyx7#j*l46{CnA zf|wrubTJL<8=qxm+${WLdJr|agoN~#I3prb^Rh6~YVGA_dEB~v-QD20JO_&sHxb^N zL(1Q5V{tdX$o5uv&AT*;fDxmTR*F(iDMH^bM{5-`t8M}R3Dk59`kx`QR}6?@E+kBf ze*&sFG^t>!VrIHuk)@RDE%f4l(~uMY$-aeC@BTOPf2UC${{PdZI{x2j|NH8Hg^aiV zztFFF{#VHVoA-Zy{l7w(>BrflPdhSQ!WwuD;E30NJg9aW>iM!{smeAq&D0UtaN$9L z#B}mXQ8(vF^5uNT7`5c0F`~q+wpe~ilBCEERndrygwf8^(YIPDpQ>gt9U7_o+a{tA zQ1IB6v$D?9z*`1Bz>~jNTnv+?Kg!}LHhA9mZ3EIfa4XXsTP2wmyqq7q1kfu#xtx$8 zIr8z;gAe+rmbAJo77Ms`0fHm5YH$+bqRI`=_p;FS8==_MI&Bv(c(n!%PNDT7T zkC@2L=$wei(l7_3cgdU!@WQZ#siw43szl=OL`dWHEf~v&ieP22tycPz5$dw%af`rx zD{;*9ttNnpy!33PZu`>y?LSKf*zdZbW8Zf_h$OHVWPcs1Dov#jOUUwaLQ{trKKSu> zn;16$Xgokn%~`rjLISY&ci53GWQ!xv$oV`+pT_nj`M}z8M2wEU=u@e-_gzm>9aSs@ z0}O;L<8m^Z0{RoE$~bqGr34wXIl-Y~KxLUwfUjrD#m|7<9v!;2L!3^KQZ#2;WzdoYseBvTUBgRSSG(U@gx%C9l&<&B+}+)U?N1ZO261>i z^3tI7hvu2`q2g;z+SVbtLg)199V zTdAz(^?K2wIB$Kuh}(6TCX@EB#4*WnEXA<(ieVbgT+V7$6)b=@?dLq~2Vh925Cza6 z!jEnU#lmAVn~riGM$y!;om1hmIw&g7(HOzX1S(5sP7$zLbkFiojk8CBRggIlImcSp zW=`ApH1m)wSf-_Fp~GjGM`2Xwg2fu^8^-21HmYN&;CGlNZ6PqDl_n8P1#Lu&(yV2G z1r!+FV$d}!{)B*mO(Ky93+UIhI|i*9i7n(~GvCq!Vdxc$J;&*4r2XeWH8>`%whH^6b^k898Fdl)D2+@mueWaWr(n*c@6(I z5Ev-DG(ACE&-(7~dz#Hk53+-j4J>LY6ns7nu?utKUTN5QT-2re1I5I?TIcUY$HZyXes8CA?g1vH(d{EaL)|inCom9WO-;=zPsa zQL+_Vc=B}W?Tq%)*0Vlt4h7uKx74IzJG|R$@ldjLvPpJec4;jkS?tKOr_<8XtZG{3 zhkqX+HwWWT?3(5}a83q5o*P>0R4G?hH_J+i$s?VY*Y29<$a3Oi>H>txv*)xWicr>O z*Voock`g6D9LN z_CiH2NoiIw+dMmHpzN%Y&*lC)fyV~&E84}Ph(70)E&e_CwSskAzK`;jb-BPm-5IaC zm+8KWs=AI}jdaS%tTKg)l$p}fR3e4QCbWjoYpAvX$nhh5$A#nPu`!`Rg$HTo^d7T_ zP6L_dQ#DgS9^_cD7MaRFzr~bms7h5yagF**k}_??VNl@00fL2A*0#Gj;e$qvRYx=| zjsrz+8e?q~lDaeZyb4rgsdpuZQZuQws>)PkrFXnDu6hcdwTE8w&U`Cs^aQkg$DVn+ zTzNOVGs)6cHG0Qhd56^LaVgr;bbR}s+m`qx+@kgbnrmgL7DHvszo?~n`XBMlgVT<;gp(VtgpovBl%j|yA<_<&^umj^^c-rj{IIM zFZ8$kC)Y?AzsiNe(a$b$jkEjIc&hgTFvky@U84c+skN1J8n@8Rm7OYZ?SX_eR zStrIS5$`0U^>EMN+i8}XArsFxtwpQx*V5P!x-Wpfx&~c!B&6 zPwwp63spUB^|jgAs|)YT=^Pf7Lglp$PwM28_9NzFQRcZc8yPcY`Qd9`hFrM?bjRpA z?H2l-#dD|m?&+>)QVC)2^Nf=avGF4x-Zw`cgDX_Keg$EVDj@=lpdwJ2_nNaF3J>CjqFS()~k zC}9Mdq57LCa%Gq2q-iPw0?o8eSLy_g7n93;ndopMll&bnJP(Qg*|u%Fjgh6FH7?LY z6Z-s(d1iq^z-6^wuHIGP_L~}K3x+~UQf_T&&2?SYO4oB+jSF_?yU0z;}7kKyhVpMrdCc|f*O)ZOgyM@C0RB(>} z0dAZ!jhS)MXyT8a!1FYW2?iQi^7`t`Y41#c-#-Hxxnm4m(ID1LqCEgnW=Zom=0)vS zhQ80~Y_^GYgo`@MQuK~relWRAWr9qm@KaG`sU$6|)7%}q0nIO#W5g1O8xY=1`H&n{ z$~gA(eGtS}i~T~{tn9aeL3Z9>zb{_(nsnS$*Eh)^|Q_7Rw zvqw1GHa~4wSuCbWy~(o2s1=wDtJG_~{#A^e&9mI1@xa6MBe#dn-{X%s>T1Z; zlz;^>tqB+2=Yg;~?PSa=V{QCNdZ_yv4B0v|s)DmVCVDd6?IBI^AWpIA-e99{_yZ z^xtM%(Mz_JGEKsneqKZ>-*P?FtLuIlmtp92ITlNg%V*m{#iVW)c}QpJ&H224yV&ef z@U$QQTK`GTOjYuw&TiL-?p5#j_19RAZA*|X$i_-lx==i-R0*Psa$Rp4d*GJ0=?^8E zq<0{@BTF(X*)Y0)g0$CoS`F52kG4TzvS4_yhwp#h18>n$g&we zt*k(Y$oXyZ(LDu=`ODtVi!Zj^V)M+b;HAgye!SV`t|EiBdLMVFnU*SNk(^l~JQUE8 zcgh)Orp1$X@u$z=lcDd8IaiuSp_JuVmc3Y!&YSV;Z|BmzFC)=zV#0;LB0c4$Jzzx{ly0#9Y- z@tMT%;ZU|9nWBx8C@6E*M{^qOqLSD00Te|>A!zGG%qDb7s2D18p?Rl+QMQ#7kCS?8 z5V)WyIH4-Gs?f}RmQL1p@3V$|n)DU>>NeXhgKa!QnQMzxKV?7n5SiE($nkHJ_4fp-`3+_{3osr*CJ++BH2c}BMYO{_ ze>?W<^QA5g=1ia6SdNE3zVT)<=?DbuDPZ9#{EFI;XM&C>w)uGtDM^mz{m`Z*uU zLYyU>3go)WIMSos+GoS{T?p_eAcVrM*&HSh1yeT32vN`dtHuG zX$9gSb!yybmaz?Z%g_K#m^M>*?BHe5@i9(inH6UolQ@@3nyR|DsZ{qZ&vIor{LuR(b?bg0+u2N0BGBE)0xTR z)6vlZx#!)jm8?y-jNrRY()su97gv0jds>B!9yb=y`NtT&+CnejT7mu4=uKB#4H%Xx~?SBIp%@;G+s+MKH z#9(c$-Q%WP{>=_L9h=y<=6SIhkFNU|rNqRV*hbn2brjSjmfB2AN{P{(Y80O#)H--b-$_0_i73gnOUtKQI)6JG8+;b8 zm|gBM(|K22f%G&vvrsaxhchnk>9cS2-G7@G#oR=CtrJPxNd$`Xt@77 zaq}G$73De4Psxu+{Kn?xd2qb+KsrOX1mK}8&?2%`blK683Je_hOGRI&NKP6SChs(~ z=*MuzX?u#gXy_M~DDdqs9vmFlkY`Jh!n9Wj*66prR94k?{)?ii@_lGKe&vS%jAeoSxCKec^Q^^&Q!&PAN-CA;MvHLnY z%#n}&utE9VG~SWgE5;P(t&qOokKpgKHzNNCG*}A&O+{l@p}L!KTJhq-430?k9^%0u=`C`ZYr6}@qcw*lI*86)RK6hLNIB-&Q9$}*+s zVlget(o|r_>D|rNX5xWlf~gFF-b{QrI(*=y1giX{sPYWVpe0 zUC7{t_x5?QSY@e5RPU#a-NG6w=RsmdWKb3aSdl%?c8_qXgT zO2p44C9Kau3Pq&9(-u+L=H-gSD@s$C6Qx)wvM)O>2}c~g9#4Ena@}clI~jM)=H+qG z0YS@N?`8KRxegm8W64%sD`ia}fI~_0cv(r(m<{uJNomrt?3$}y4LX+bOwWUEmo_;^ z&=gQ`Jpix-P{KaY~*+1uE%e-^WE&3Ce$s@G_@j2!X#`Td^B*2%)6(-)l^t;6!?^WS>=@_1g` z4e;Ij1ED8#dEA#y)N-78ERoh7|BxW@&sUVG#9#0oS(BL}$k}|!wRpysaz6h#DKZWN zb#0J>cbroR^Qlsis91&Stp>NORb+&+bnF^@P}ZA31?dvAlo=*@&-opN=pBPxaPnYf z%1!-yl=`_w^GSQrlx1^KOOp0{RPpyCfcAt-#&Xtj7mZ%%xDAoA_gb+U2%=^F>t1KE zGv7%HeSClK^?QFIOCIand~aJewI)t>;0*_ftHDo29&}yyycS9jN}DI|xluGpfsK>R z!+t`OrQWEPXJ!2u3}?tnU&KMi$EHlwaft!NCD`67f~YW5V(gZb5Uo_Tl~|{f_3QL| z0DmVk4g6T|N&e2ZDQs8d%jUkln5rCN_7yf~-KqhU4p( zy#&!iexB0|3jD`=AK)+kR|C*-yB_1GYc z0Ci3%t7V9|{Rrjf}B0wXvUSyFUk zo@|tKikNN9^Lt5Fi%_wt(K6ZBTpnx1|4f1jjRjo^!9tXyV%(`pFQ-)C6TmI{VJL+C z*j3=U4yql34M<|m9HXh@WE)KABgGKq*pu&hFaLrg_I~krKmn`%%euAS1hz`;e8Jem zOj%RuweoO=?P}gBFyOQuJ|k(|5&u`EMU&Q=VCfy$#+Lu~-1pwzRwLVB8lk;eE>t2z zp@}fXwx~oBx9@q=Wn;lRS;-P&hN@m$)^$A(H!=*{7H|B!54i5*k>%aj%Xod9{e^=nMuXPm$aeGP-CnRyZ$l}zFyFj8KMj!I5&Usl(72tAccNew+!EHffqT%~CwfZldP<;yU| zZx`Ozn8r@W(%OkCTO&-KTsEhgi-NMXD)Uv$kirP28Yx;Y5Y6~ra8Xa4NKzvW7Mr9a z#n6%L_@&EYS2jJS>!yJLOI7OrS3A(EsT4}oUspfJXAr1| z=WqVEAaHG|kM}h_mzoDu_T`WFyxdfIUp777bLb-BhLG9y?jJaM$I6s1TzmLD(GOZo zW;LwKchP0E5v58e7S=U`<<20Yn|V**I8RsDQv{_(H+Ud65}m>I3GZV8tVl3=M;{n|)!Nu_f#(@swB$Cyi0b0(EKa z=J?R~Wr8E~!J+YNA)~&@2Rjc#M)&}b1;4JFuUt%#paq3R$WdCRAw@dhIqNm=Yo+aX zYkSD{258`pyeyt;*r0KW-LpHh@nK)OTVnGTZNs78^g9%VRMz`p$Y@|+= z{t{&4?Qc5$@wHRY1a?{@(3okczk1{z(3 zz3EHy{(%1eW$Gtn$+Kn39`wH>p4}?vBb;);6EL&l!^LkppPknAZrKY8(77__cE8y9=C;zmcAVzR7f@7@?0-4v4g{f zor1;~O5G3c5+nR|#NpKkLJUm%167743a*mn4mPJDGo?fpB3(e*bL>qBnz*S$v{9}L zovm~1kR#-4!@f!1{l#8kX5XU3rxGAV1CTc%_;zEgYsN0hH8znGlzzC_sm;GYLN#YG zAHxG|Z2rIi#!MR#xr|FL714NW(DMowa{$#kMU!nz<|(2r!Er&*5D6&DG_3%;?{7 z+y_6Gsx;#9xo#>f@=mnZUB7VD>!HJf>#z%cdw*9!AWpoP=d$^BGLyys@pb$CM59l- znGAWZk#?ey^YBjWsZ>i9yeQ>{x6Z*B$D|-|ofjM4d>$uC=MRv_5E_5Qkx%2x6A#O& z7D?O_Br=4h$)2)W6pk>Ygn_Bu#g!%xao~&zh})fgnsZomBry7RBM>xTxI9(#%Yig! z%oJWO+xQo1saffe*+VXA_H@~N#aq$(+mr+V3M}+TkrAX6h3#?*6)~kp=DV0s^AGfP zYTdABD-nO$T%CiA?;8el_*^?22wTMN-*xoo00htsJ{r!VeCL>(9M$6+hh*1D&eL3n zkreq?x^>Oncm3dq8;X59yYT|#h-=~B{hlns-zUd7T~ALQ1ROqhco5paA7s!BxUUMp zixZE2N1{Q)<0_&ud>JM${ej>#)YNHo1`lhebqIfq0+L+=0&UlWzR}+d5%3>D081%g zH>@O?oC8A)IY+UJ*Tkkh8PWG*EE;i2)rgSm+f%2^LDatr8L20^wG0iR&jg7CJy?Ye znTClIzqtM0xX!O4HB1mx z?>zyBn3b1;uagbEC;vi2#=v}%>DqotEm=_q74=!twO1%IyN2fk2Js%&*aP?A!FK(g zAAq)C_#Foj4bw<*+KfU!%mzZlO+Qr74TVrpuy-esJu#Y)J>_x3Qbe5($bOxROZjbZJlg1hwnUBXz$<f$r`s}dhS`W&Tv9zrW1z^K7J1;%Ib?rB9{VfeXRf~2 z2Q2f9_+%am|8jff*IVOd2JGU$S&Y;aSpfkF4Mp~Exyi#^O^pt7La!Ws;7Fc3>8ZOG zQ+SP%w2q?z(&lW;#`fjJkm&tnl+mzv&$X<3AHAg*2wBB|JR02sO$4SPW|dsc_9Lf> zgdaw&psTkaW4P3zP@tTfq54cJs97f!GTLscl8wcD@~U}Jx>T8J9WLaTkZ3h!9X6Yn z3n?zSg!6DZ%YiQ+5?e}Y8hH|IEH_~^Pi>V_Xt2?UV`|#_%L5*h@mKZgtMs_`&hg#H z&8z5*#8`2$_c+*4a-co{H~Ao{%=eqkmE`Zx7!1EA{&Kzo@#YLgZO7^N%hcxwI5%Fh zw(=%pK`S2B;o8&X8m$ozZ(@3VgE=;9=!0Y3E4)`<`YOWwx zps5#@E=`-4vloZEt-pi0zTLTVg~+r)`HgW6mj$4@ehj#$l*{!ifzF}!Fm9)r1Rb?E zd!F3rTJWohBqtJI2sj0g+JeFu1`nQQyWR@5*N^Q$+9$k6i@_>0=SXn;Jd_&-wq5?K zToD3VU(+i!+lPBH0g-w!=$rPrIY2~1n1??IN^qEKfxE5aptW?V}X zn4vNzuAaB$r<>s*z`wKv4SmxkX*Mn{`(n+ZUmXf+!>S(w!FnL}dkq}Ev>|s}KNWti z{XwFNH$TU>!U`M~(R7{O=4orN>6_q%Z^vkIShaY+QXGeIzz%g^qibj9)y{1Prg#m} z+;2@zKX@(cgVO3l?Y&+OAehfh@oT2iFyNs=kaS3EunBSs~ws&@;7^DnyUsUQz| zM_{I0esuVT4+hAjgrpXF7Nhz8?y}cNoM!hohMX4vQRfl2IAG~j=37%sBmvMhY>+y4 zt-O#uXNqdn+mFGbfAhNR8HNrnjEe%Diu;bV(?2o9D^V&w<(Z6FG7>YUy{>$E+>%qb zuWFswwLmrjZw3!&6KgVe`ZZrEe#IR?qZ2lzT8to$*gT*|oR18|v25&guz&AxQ0LL7 zv>tpzh-GG+k=|JgXYH89O*!oKrS%O}P zskIbi&B!4j&XGsm0oLYn8H=!K)oCJszA#+*Vm=5K0j|)n^T~Xs~_g(pdDA;xKbbOkZinGd>0@OHGUU&UXND>@Kq;`pIEyMEHw70>n z0u4?(fhjdQA|pw6(U99sQ8IF$tqoSRp&QPEi=?Vw+5D^0FDqR%`&s<`$-EWJZj3yD zuIb%oAYq@YEsyDdW$guk(wd1k&K-8q#_I&lfWLNXvypVLPRo3$!ERy{fZWCk9y%OF z|Kv)e&SMf2q}J& z^%07fxkHKKY{zUJos`4QHCW7J#=b7fQr#6J+_L}z*wDzM*aBs!`Jn)2^xr`sPTIiN zRk;9NDik7c@i1C84x7621aU>KW}pzl8!kkpyF?<1c{r~Q<`dJdu6!G#i7|J5;KArE ze&*zrk_zSemY2U4>OcN7u~6^rO?|7&SI6pd91Y@29ox1e4GNb>xjCsj5aBVJaBZ&wKg7 zuL|nO#mDr`NeXkz#Gfc2>f0aUnLdiG`)} z3`F?k^$8PoV^J^LZ=Zz2{25p8yQU_BR||AOelCZ;rb;TV$w8yFa{scGK&gW0Q(C&o0Dbs~0H^4ZaQCB{7aPyQc3skb)y?H;8@IC6Aon z70hEQ9+|^mS5mqQWIHKn|#_G4?+D zrHEr9g%>3%>gWUkn{2xLKm9~G?^Pf}d6rb&FPB}nf*^s@IKemb%8`@K1pW}^IaP+ zR4(RQ?_l8H7{>Xg31t55Ulfan zv-=A!h^iSG$V1C_>Aj7#zso~f*v8$L-3N(_&bW?8~LH~L>1%P$a1w-amxdeigs#hIsx~NVhx+p0$N?=_Shn_#G#Mb zFg6Aso&ZuJP^CaHyVuIkth;V2B1zrB=+8Io1Qsh^?LHMWA}YP81>Eo2*@dH6qOpto zfrNpq$p){{YXQwI^APRRSehi*&?&cX6cPMOt$~`!^cEXWjix$+aj^OHDc?Hql;6Sh zta*2J_rsKG6L$AzP)HNL+jq`dCCJX>Guuky-b4oIezAt>ks3D3GT-7t%5|d*?sQ7j z?60;JyYO@GQ6lX`2UjuA!*OXIbVNvDuy$i@Fa2fLtSr3jtgJ6_hIlU4C-p{zMG08c z?#z2rH;ai-k8nRx*3r`+Qc@9Y5y4%48z_DE-5?`=dpwCm+;LJm3&8wLnLz*a18~H0V89MK zlGXeB4Tz?Yx<78j3$<5$AOmRj$V!gg-n$(S9*~%iW?AGNpzMfhb0<@M6%ce z$ePP(AuYIgISbz`c%!U<8w_M>_7r>5;T8rNd8m8R{-*`>Rexc+1ngJF&i?knpzO<5 z@gsr4q=|N~IoBqrGR<+0%S$4Z1PpM71s9&k=gLT%oGve|a4cKbw3sj--Hi}9X!vi$}eh4Cf2{PBS{zPU(hzUl763G%#DUy=9pL)Rt z+L&9{@Rj21!mOz&OIDz?slxAtA9?D?H0`$YyD{TNikdjq+;il#)Z|khTh*|7!Qp@- z@gi(fIEsRPu2oK7CnfDgnR4eor}bljUHh>Z3V#FpO+10YDKaPisb7X6EdZ9;w&x_; zq{GS$>%Vu)^=g|47k@qSWGBa(ggR{wCVBh;3ilZE1dV;}Vxnr_shAeL+;tOP$lsiM|b~zn} zQf7bM&5a8!$>QTV?O9ePU;~A)1lw3iDD<%&eCWm>u*#-G2U)>P#uu|?67p_-Qn~kX zA{CT$H}mQfv)Ws&mjKw=7Tefbzz%T}NETg=zuLBf`hPVz{G@9x^y^7`Stno|rk!w8 z#(8NetWbhkA0w-8>#UH{!ey|RD@m~uMuty;s>D_Vs9$IZ&cfRas}4JA8Y@gt- z4;YH5ka)oXNCj1#O-3VqnuNwfGX&g)s52**B850DACEVA@T1>P*|Y}?>kA#xtnTok z0ou6h&B~sFQ|=DY4WxvShSJ0md6sr6?e~Tp90qbk=wF@#dmAKNAw+5q zBf_=>x_L`Z#oufMFi^b5p5rWze}jk}lKmmg9lv2ih#}k54~U1=x`^x`gMHOA=k?2m zWQ6RI7H)(J>wb+9jY5M^-X4m>);8lQSPZkM%6!ypg*PbILalt4g8qh=9Z!Q;1?H_$ zXVA}9myL+m{u#)umiZUQfxS5aC@mOb^N z7bPPjvzwS9Y?{*{&z>piIldm|K*?<0Qo2T2i`N{y;~+}&Tw`=%$%-301PlbHp4DMk z+{t00Gc$2sXeHI7H7ae&tj>l6OncPj^@P;-t`eE`YwN5xKfL|SRbOkZ_UMNA+z+Vz z`_{gzU<0y(_`02wG^=ydKlJ_;4>;75;$rEV;!~trCU0YQUh&$GhpX^^JnbHcI#Z%6 z|Fp4nhU`8<`=t3{D!M3n?tT(k{ED}(1NrWHz1zhb8;qj$0HIf(zO(18~JTUhXb z;VfpWnbw`J*F0L<-z<$34N{dcS#}aW5YYga!df!nLJSjm3n`r_BS@JS3NbgBfvSd5 z?$ljvZjv)9<}kHE%Afermvb7yg)4r+{BLkg#N>Q}T4E8YcPPzlf1q{k*f}|Yf_b20 z7LL>3Ns5;-$n^>t3;@xL7H`K{*LD(41t*@|t*ZcHN^u?QCXyV38|zdyN&@q&9|Z># zd5h z?(XjHR$PL+TZ$KV_|AK8{;>Fwu+||nvuE4G1rX{ua1>ZgjP|#`>QZ|?Ny1vpLmNP0 zMhA`2j%yI_l(1g*yqV~0XjTn zsc#%13UgCBI={AbouhLVLC?o3x#_Fv?XKsm1=2B1E>;b!Rs=feFjM~_gRuP-G?hKD6+SpFcAk3ela1vodL9Tn*7 z@EP)He|~5AJ7N&sc3X=U@4&W?t1GV-D|8bUBkO^5`N_vw6WnqN$db%N_rO;UyEyT5TP={W6%QPEcU!6NFe z!3?rLkmvU0q#S(+74xm@1A(Q1MsC@3##1Yd`j%=pZQeSXUmqFhXm8 z8weA4;FD48hE%ThX$zp7Y=3>HUL(md(9LkNjrIJ7n3c|}(5=Zr>3Bo=ZLR$JMGc-5 zQ7yIVo&{Wt!_GS71TI^XSZ04veDWSfw-GrBdCdqfHqV@x4@M_|F0JIABJuU~dJ zDepOZr+TptYRV*kHc3Wj;LfvSs8EZMS%nO$wh)DuL8l!m<@Qb6t?`2G?)f3?<2jC@ zu!=A3ExR>#f!D8-wq5ekNKlQUj?}A=t$UQ2@Oi%o#se&P?BLXW2JvQmqdE;4xFGrU zR)*Qx*?NaLaXNzq*Rm+MuZ2C_dv)d$s@3!HNBrM-B&73vO0jHSKT@;>&JzVW$AHCm zzJ_Bd(4DdUaNH+$$8F$0{J`+@!-t-Gb2+ysZp&%X?}yrymIKG|>u~?d^nO~1X*ylY zu?FUoo8+7vOnmq$<^VrylR7sWw47gWT7;S}n?KQDZ1qWGS`?o|%gSK8!34jkqHKnO z>rG%m@-xM%?6X-?pp`}8)B$QL2IzXnNXtrEqg!&Hi3=O&p30`dPfD?w%>=dgs=CMy z-Y((Wkj_$Vj;o#N7G5#q@t)n{@EWec{q(h&77pb0S%OZ1#-y~Mm%)MYy5iYwlrKIUx7v#6Xf7BdMVgju)zqb zJeA88)VVw>*#b`L=Uy&WKhaf5vyW-^6ojY5pGJa(XQY+##@;`qVnAd*kN!<#v%M7v+Usn8%4uvFys(2IKlfsEBV_w{L_!!)P z(O;vpK5WWyDN*pk)5?hE6N}R=zKig#E)(ROS z&o^8K74ub+yy?=WSuG3USn9HnP-;%u+c=Q|q&TM`N-3dbE9VkU-&%d9{RX{+O_Pz4 zGt-e$je&ohbo=Sg2ZPQObEq5vFi|R_6~HHCKyi~h+Hg1GW2$x?d6;b4pvg3N!?Upt zlos`YBQk#J&m*fwN1`Mt={OC14bdq`rnX=$EA0P6!Omqy)=W2O>PNsfI`Q^=hJj4D z#Ij;y!)U27i|MW7so1O!PSvusB2{W(fYdeLq|GaN&L$8KRsc$njW*Kdg&ftJdQjO4 zsO63vkD0WKq`fq}=boRoN;p8|AZ6hR$+BlD?-5#+8n66F1-mg2j$bV|vEz~0W43*-#r%^l$A6d!4TjWL7SkgdYxbtsZ_MeM0l!os94A%}XCfxX zZ2;z@L3kJTeA^WZD}L571bn4?d$#7(d6R7Qzd1})r(8H_NF!lRZU&1_X=$X z*S>YiovZZC4c^y(dSNLRmU2VmbfR}X9VZCyi#}vj`9}ZJY$&O-u$NqjmddKi1h#u& z8QcEFZ@nCHeSUq)2h6Fh(k`Emq?TN+qnCPQ!8VugISRL0@YiF=0%Pxmn4`@-3A`Y2 zMT~bkPPE|SBsI-6${;MBEFxcF;RsF2x_EnPYhD5K<>gujz^0c$z=ad<>Jx}W_VS~W z1YPup1doz*&TrZpH@y5QF_YJ;Y?!$SX8lLYqX7D(K4WOlzxeL<(ck9mGR#+r;^k;7 zuSa$JBV*3)$ji^qg!9vwMDy`T#KM}UwrrpgF(Nabg*!gYx5^~8S&CGom8iaB54@@8(2)g-r8iO_YO(wh!k{j$=~zwej2IzI!wsk zHDy!sGFz3?eSf|*&Si6Q{L}7ft}gVH+j<#X(|$4BOIr1|+r$zW(%Dmv*12zX(ZdJw z7y!kZWzv1M*5?V=-in4N{q-&3XszSIp@-Y{rS-DToW92B6Gg%(4T+q`(_=|Wl?E=F z*t_i79S9|z;635o-v^96^Vdl26!-EqvCf|w^kuSEoTxES^*~i86$;4sR7F))9jO^> z=&7MEw)7}!PqKWauA=yPb=D}qN8XoIo#4W%hk)Za1?x(Ri5vuLxE!ap0 zlu9LVBt-`3b-rS;d)!Ln2FyRpd9&m?W~0P@HQQLtD@jdbq9RDX9C)>4JL7{58^|C}Fe^kReUT z{PwuBA!)5!&83Xi@?|r6_$6}|Lz)!0N41nCN@c>Nm`HHG565rlg!C^Rt%F4Q0%A~0 zJ-Lyxh{Hlf$a)lp>#O4HKW;1FGGU8&_izO{d~1b*2R3H+%z{l7 zsiL_fYfe7<>E4a|WdVXP&ulKUsZ5KxVxH!Lv`x1hA5pcxw_JKmbaY>Rb$+#E|7-YA zp;nVFVB|`H3+-pj+O}rfaeF*-QZ&jWscvfGy5)2CUq%~SUck`ITHdo@IP!e6>$xz6 zYA~NgG%3mGNjQpHAvZUtY&toSJPD67KFm-w^!8-yq9}~XBoo!1`>C{m%VwS3>X4o+ z$dmvd8PgYmz?+#sboZXQD;$5XH?H7_rD)nk_tQg!5$JM8f}~2Pp`Ko?SP_M+@GD?X zh+e+TGSu)5rCxEJ#DEDyfg;~4^PJeqs|JrBG& zRwwCd*}3{!?&I@&lu0OSB{NCa>sG!07xXx&7+>FeG0~pa-(l?UCi>#43b^!C()`Eh(Z0-p}2a|_F>)tVx?B~z38Isa#a<=*ZjtPE)Pqs26~ zZk>)i8oU}perxxfRpgc`hrU^kq^xJxny5KVw1^(P4NJ5&8^nyh_!_}i%Tde80Ux(@ zn-+gvXeblcotME4gqvz@W-AMAbMS`iYY*SM8m@z>4|4;}&H_VDPp7R0@S#vYEA?+y zDhDkrZcmp$kUk$-C~n33Q8Ts^&gLZbrSmqh9wp~Kf{vyJIV!E4M8lF5p(`Kn=bIFn=`fap`84msOFO zH^*Mq{icKNXLi&t{MM(fb@GCb#+(_qx1|sdujq{i?R#6Wz;kAe=kwi(SFbN(=hZ6R z$?+l?;J6FCTLbl^==*w{wKqXcS2eF;Nf2MYT!Vpp%jew=O|5Lmg36MP`(|)Wm!QYS z6IwRpjKj4iPc%gE@g||n*%D<{w-G2(5{Tv22jN7Awo(73 z>=gqn!xiNf*0!KfI^5-GsWNL$6eJv=mL~*l9xpca=f|=?%XLN=&nt#(#o!0ex24Pa z2QqB*vNN6M7ZfnxSXo&)R=35DzVjp;SjzC+X`T zQ7V~Ce!we6SA~FvH(y~^vntm#p2CEI5CFs-Z7eK+cVs$&Z=r;j$;}aiF-Mp;l5ur@ zQgT>kto13x(qp8w0at*fh~yt$H>YuOCE8kA(L$FGf?ZGE|IQJSN(;%|l$o)R;7)TV zxt&;}mBJmwlhpf!nK4mGb5B}l6QpPjfEyS$Ua{bu&(oa;XzUrVK})Mqe9Z%#f#1W@ ztiP=!JI_Yn6xIgUxFxBrPAAWlPbolLdD2x-Pq$0?<(LUu?M_&3ZtO(omQ?SHw*_KU+!mP?;Y~#(g~|^>YxQ z4B~v7OxoG?TC)n(eLPR`AvVIx_TZWryI?Sh;CT!ciOU%qiHfQ^9~xSkoG6L!OAZwg zbN=?j5f!29%|}1V9zHJ@pEW)Z_wEEXI_T+)XGhLtYA9JF#otZvesyMpQwEQx_{31% z=c+%)8p{48X2l9pQz5U#2k8srdVAX6+8UM`CtpzsEbn|;T(fKc=Wea(cvU^{NIa12 z&B@pBT$fP8bG-glzQM#z2T zvJ6K*%i$&u+pM~x^fw0wW$5|y$!C%_mr&as5`NXcW?CZ}>TC5afVCBfgkJmlWD@}* zxQFHLpRlDZ``3jf{nwJUH|K*Ubv>t7j+*W(+B`bZylEf^vsh!-v+hkv#@i?4V8Y>}g^HyQRN2C90J!{6lh<^y@@sGwKlYixSUA!N2V)cU6E0io@>ATKd-;% z*>Q+0TC}6i0YPz9=1+NmJ0kS_o0mW(`!*c-p8B*i|2fCw(jSo+kH^$FN6;s}YV-&1 zPVqXB13T+no7(Vnv6612{1|4<*8@_pwvkqjh%aw1_k3G_wBXX!RTTgXMMRdwXL3=y`o;S7h73w{Dz=LM0 zp|!KLa%5vnLbn3)900V)m|V0g-?CZSxLdY~0SP{U+izW>_Zl0U5{INi(TP@TKtl2! zHdQu2o@7CF0q`Ck;2emCpdYQ(*bPlKHZ}3kP%R{f5AOxK63&B!L55*NhvGokeo3}S zDIlV600DzUkRLaqiKB(GJ}mh#naAm{P>Du@M||8ea86C@G0{@X0y!Q#JOh+nQoi;#uLW3P2_sLwNCq-ush=Wq3amurX8~$pVOueIj`61lWL#C zzye!$_se`SC(};0eB*^93Ej@Z!Eur;tD6YBo@UtIgL^@)qeFe4t7QTC9s$Tb21upH za^tFIvvjo5egDEv+$&1(*J&?PNq3WZ7n~mlN!Q~e0wi*aaEtkDu))_&zoq~XFWgu1 z2ifGeT3+OVRdlHSMT{G-ZtzClEaz#sM;3H$=d+uesJ#l>TGIEf3`Gmod7ECle`oD5 z+&l`+nO#2Ujrm+@v)+0&HgNBKbETY<)pbsFx_*D|^LGRM zhL(NV;^d0Cc05Xzt)r)ij$D}h?){J>FZfz0ZnJ{RQaSbR`L-(-adLb-#d|_O`hEe@)_!yZL7BPr=zB| z=;Tcr(#prizEpP@0um1K3nb8$S(t0C!AxFS0|>9nQ(z~X4F0M!r&tBjr-0<(0VoG0CZlMb-y&ZRXveu6Ir zoE;^za&;OLji@4|YRG7-rml;l=wCQd1zt`Yz*16D<>lq^Hlt!FxK-L+wva40U*O<8 zvi4kx>&Vvg@MO(8UFm`}G8K0LKKF@V5`;c~Dm5GQGHwVGVM&=IOn~0orK(NCP$E4b zoZQuZu`s(@?|pOy&4=o)*`uSR_z^i6*SjmXvC+9d4?9tfz$GP}k*V`veZA8Mw*O%Iy3vT0KlkpTv<U_z``5i*cOU-lEXVl*u%>1PVGV<39&a_x?Peq+f_%C64+ zeVUv}yD_%VJX+^*A^}}p3U)oi1^5HO)(wpwMLGeWr<>0?pczQ_TL=gRwDE#Xb0A5T z)i}=Bk-Eg%^pq1Lf6ntaRZ&-=v}@?5)cv;3OzmZ7$w#CLga6WTatfQceXo-hT^HPS zzIs%n`&Jkz1zZMSF^Qa(bV27h0dJu>UXvvx*}f37v!8R7207gV1!U9}8+r8;zW-K6 zRYgH}F<<2A5UH8AfRs5SiPy`ma<^8)z=L4h9&Fe1JtJ)C`AS7SMg1Ol%H3-C1K$Np zXH$3HWZXDYc(F8%=wz`(ogJo#ql<35Acx=cf*$eh zX3Z+pHH_NWOy8w%fC4o0Dr6ED9UUu8BOJTrk?I}HbE}$`@mx1xsPFE-c zz8nP-F=|pD$OPRXfq+>&^-3fA##@~)V^Z*Hm6+q#XM12gC8B50k|nEG)1YQci$Q_xgg0YWm6kRZ zXKO7N+IHOwv$Kw`w@Vj5n}^&`Sjry~-~Ao493M5m*6kORa$fbO=EjizJiQIC*H`}@ zc~6gc685`W7PH-}2vCAl@tfxoQGdOH5j#QGOa8dqss+{1%G2%1`#*>fy>7Gf`m)34 zEYM7UFiJt3xsA=)tckSU)3q$H1r}Y-jx%;!FX_6v5Ds5v0^#=i1h8N|J>dRFClP!( z=Q~Fa7WEh2p6a;pzCPok8>h4Dd~*Z${CiOb^W#K`zq2h!);T`w$0*?m*H6^+q5pSf zH-M)%^sy4mo%VLtRp(_r16b}vAW6Ek6Ce>d6F(dOADaw+<~Qlj)`xU3KK)M)3ig9i zL3MexrKOcfuL8C4nkzG*u}vkQ$2E4cGt5Erkrs8HEv_9e0ng_`&n(MhQG&#$vD_Ai zgEg<0RTLK$o{Q63r`~uJ=#SWk-Yig$d3t&RP731}y}e+{r<5YXfl@gll>zqTndBc-Eu(;%MfG7Zv9RNS`MF`Z5r)YSB8LWvHUm` za93?p+iilpAPobPYH5J$KOiahW(){6J{AB-=9_ns2X?4P9V=THCfm3{H$67ie?g-Pv? z4pPoLF1p!Fr+%8vMeqHjNm3GI3o|T(%l*@^v$7a@Q)l5H{4M+Ypdy@)iq@dfC3F`8 z|9!txK*Z*&XUVEk0E7=PW_hjDo5b+n{j4GGDj%!hKRc^?CYGY1Iyr5FWIvy`)FggH zuBh$a!)Rl;*EPh-1-Y-G} zoG`q$#gv%6$*O!Lo||Ez-fw?Zd%SOG|JLoDhmyD*2Y)`h`|3Hw!`@^--Gk4?RJ88! zFS^e@mb{Uv`(<~k| zwPZhTcX8>yLO}?KNTC<}*9#lim#fD6G1{B`wg9N#aQquBYWI9%Ggl%HIyg{oZpD_( z;e7o)5JOEvcQn%_L5=Boa@KMORLs2b-RO7N+He!-H5w}dfAy*_(Jb4y*j9H#k}Ajf zYLu$y?dc?JF$gnXd&w5`G?0_bsOx!N0~P?3-!1Pw*{%H>{phbT{GLGF56ES+Ccey= z8qbjs0(_6pRw^JgW|{F0tN=@Kv0|3xv%sP5F-uoNog?6O2dv#D(HtV;hhbPgw2h-G zw@u#bMgTl`ETJ&A8N5E-mSj4Q+10e}-ZbE{b8;e+N$pZ{ZMyH}Q$|ejJZGYSJM0f5 z)1o0S5W0`&OQyIp^IPL=#iS*9;*4;v-@iY5CI?p8G4%ZC94k#ysdmmvOqeQEUP+9X z@<)b)sdKMnRRL6Yi#w@E+NlKE#ZAvG+j*E*kB{`YZKuP+GO#n7s5$!nLf2}H6 zuB#URru*nps#KC`E9fgqtMPa&_W{TUhYHv;?uj>wsNk{b)T&DL^+_UzR<+g=)i_&3 zDf56Wji&(;bXL2^)6kRd^Kv z@JF01s%*l@b65kjGsvMjeO)3DgDDsPa4jkqPDQNd`{gl<*_;!se|nB*;+SKGh4De>h)0{yM)s~V-Z>f_U&vwip6T<8RS zPO4J$GTk9A5T6->*B7Rew-H0j#52xy2HDb^{oe1eu>O8G`$K47Qt0*SAc}FEe9FbZ&oJV9h#&VAdU%=^#i%N+G%vN=#=Xy>Bt*NI z1|j}`Ey?a+MAPDqf_n^>mwm+h@u@zU0l?38n!2+Sn2Z!sZFxcf?jU@D?)b}bhwBjm zdhqZW&-upvmTs$io{46HUYhefmc$vqH-u};lMNGfBAvx*HPRy4r0e!h8yh{H+5O-4 zf18$&7B)y5rk#3?HR=y`o`Q*L^6L0A!=1O51bU`jaX6YXoFBp&ukGTf>1>(`??F4` zkr1D8ir83wpE)z0aR7e)FyVlN;TTOtJ)m)&j4iz~L@^Z2C>5ujv};)|IpEg<1lFy~ z2`strPn5NK*ghzT4lRByEK#k$bLgeH_htQ{RJkwT4GQ8wg<2I%P*R2ZdC&V>mK85J zi*4z49XJr3fzq5BohHY@dYm2mWe1}CX0_7RLD9b068=81?gv`4u;u2BfA&O&Skj6N17 zZiB+t&pOK@#YJjbdG$7Y2JnSc_$+uwnWpfIMH5Z}jl%7o91CGJet8T6P>& z(9qFb>o6runirkrGU%qcG&I`)HaPn}pS9l_qM*X26iu$PG&dn4*X>}p4bKES_Uf$r z^F1bkmcNTmi0H?6+k7>hU8iHPPeWvNPjw|*dusYvzt8I3?j?vluA=Z$2)nJAdYd77 zptU-Y`~u!-DQHUsg%!I{IgFm`-B3EFtqOJ2Ua#Yv`*wf5uL!Oy6Vq@*+LVC!|x+3#zyNK3m|h|BHOv;}QOSmcwv) z-rTqMvweTQ9PgbKudDJT>7~~P9-}|5dg!*$$RUKH{+LimpU}|IA{*|vym|mS8we4$ z?_};}qP%SvV01s;Wz=cV&!lgUK<9~)C!fYO8)q1h6Gwc8$t|y_z_$5NMgif^lJuG_ zxUrYElBUNU2dVQ*@cWYnEdy0>0LBi*AlmHGzPDg2=80wl3fXksHk*Kr#AoBFy}kYT z_;{SL$NIlkzgW3ThJo^&3g!`*`j z*g9c;;w>N?JQVeX!LaM`FhiC>R!NGHd*xOHsoe%a1_>)>@Jq%Qn{nJ^;XlT#D`n*& zs4p_Kqxcva(8CV=M`8stRg_pg_`xY$+1-fK@i-a=4`&kfc67&#V=du^c#F9T4pZ<* zb(Fk#pLL7Y;%q!-oml0x+b1VmS?L;Rtu)oB3B!kX9mkm9?oOK!Q|mC`&O!x+Zx zMaiLHr8WM;3$%{&+hl=Tp7&KhXm?E41z(?UjyF!KTDHP}koV@c*Yh3}DczO%b~LW_=`IPkE$r=H%7pHyU&~F-Zw#uryOfvz-9La#CnB-?wi8%zX>qlf zf1$Q)C#z+XriMBu=xb3?ky>y54EvHVh+;^SJV`+*DLHv6n?u`!mLR4*Izy_^dK`V( z|0?_{is6e*?RfcEeVH{7*jAJBHujA%BsXWi`4*{&B6f^m=xt(2uybz@cYa@I8c9>d z52jxqNp9>W8!Zv1uAwP=1|;T zlre-J>fA1#o-3Sc+Fq{AsB%0;-kx=QPk(FLb>H80de(XxvkN_4y?6M`_6-v;AKvWA zY4-e^l)M0kYQ&)54!cU4c;M-^9lT_W+xEPLkL!H_-R(S|`Sg7Vtpwn30TWo@rheG% z1lOkKw+go3UK`ZT_l`*4^SCgH98WnH=IfmbFe7+ui0kbljK)ZwK&TM>P#`|9^SU^8 zSRlvOtW5*e%Ov-9Aavn*)L(F~>ANXeY4PX-0=fQskj5ZcP^UUu? z03IAt=hKojNZt1utt8v!xOLc8=)%mZBx{Z?(P#G}X7QHzalZ6zT>UQ1>pshiXx{lI zI}leMbdT-lbWieBK(oi6PVhT*h!l!Tzn74E4`4v0Xv>UCj^+G?fhOnwK%^UZ^ZB$( zo-+Y$+5dji>tYb1zYi3h?##|AskcL8jd*I3r;ma}o4dRpuNHrt04-dbKKHu)(kP5W z=RB@E`N2mj1XxCK8qA-pZEc(BE9&bVbvJn1qg+q5P+JERY)0X)ae;=op`>#F6k4xk z-yJj-MDv#e6wcv9+KRR7{D>m3G$BW3nS!A6m%6>-P1kE1-|Jz!D!fH4X|UI0l4K|$ z|ISj++pS4Y+r)JzKq@;fjJ5qxe5^-~%H6qod4f?+3m6KLU1 z3camqVX{^YkFaFkvqI561yVfVP76Q3g`YpMdOvCaZ;7*3p}i^SIfP7|Jkm|GkH0+XK0LFNJ z%v^E8rPl!pY4Pg;Mp#Jb1_G@4Z2Nyf&CSgRbjicyEQTK#TPf*{sS~GVP^5qRX|$RH zl>~2t6*b+*t#TfkkLgKPysBw!A0 zuDew$pVy~YoK>%yE}_>`u+1?ThcNYi?OE4EOCxA!Fzq!)>5lhU`l^myt z-}qw`XGv#j7r3v~xIWh6KSTEGuHf;>W5cLcbd%;!ZiX5~?*TP#;{7c`m-$g`U zL~@v~`<&&iz$e=?hZk`=vpmXLXQ#fUHr_Jve;NMgF27e^At|^{&xO(oRj^Qf3K2@s=~_F;{j0U z&FMU+^mAJGUa#$1Qk=gq5LzK9bo zXsF7mp02m@Wh*u&ejk`Dyo)BtpBDYjr*@%kp+}R?0f;(J5WecJPFkojMxou(f~N~h z=3jMFKGA%~sl-_5MS(TlyT{L4Z`Lk8Y(cbdERVNDj9t6IOoA^2umdqddyhg}oVBd8 z@9SQ~w$yEISI;qm*GVQ4j6Ij5La&znF&FsQqF;WB;xtWLDp$~zqnUdQAH);^qyMhxfikraVCg`ba~#EpQ&Xyuw`E@R_QMp@=tlxb3D%P z$?G~_ik)y)W?a2}8d~|!%>&eS0=DYzlQz`U+Ci3K;%k6q#USEz9?s(ve4UsRZ0&(f z3n6MWo5*x{`7jJ{>c8Gz9(U~B2cFOvMw6jo5!avZy`cS2&{0M56u{jAF?@&I1@k=2 zGu3t*xHxP^6U}GN-#nId-PTd2kt;Eqe42$BALZ^it6KxMwl0IsfUmy3 zKeV;iGCiCETt^TEd@q7#DwX#Az8ig^!=!<1GA|?G&{h z%`Fuk<)DgP44`wRB^O%j6boF5)E#husdes|_8Q;$H1O=75De}XF9vFr6$=THK7@vd z%6h>8$rXk~RmSJR`Utjh+tqhwgG=M&_ih1m&g z*6074>e3m|RE><9jRd&b1N00)`Rg}%s!|Y!iRYhiR%_QgkFGXZ*{tDyzr6FZBYA5W z06HmeR4dfFuAb-s{TN+LROcVyD zIjpv0{r85W^m|NS0Scq%{rfYC%Y!1a3TJ|Dt+_u@Z9*7@C29~%vI*ICNYoeWHFSyo z1pRF9X@5kb`-nX_Z2hT+s|~l!sG)*n8wQ9i&P(tUQCSnKb4Lwf)$@~?G-W*t{oAJ~D#R3zBeL&bc#HGO@jciqY2j-b{|8I#djJI0E=&s@0VI50;`Gu=vm1T5?T*)udexF6|4xsGicDq- z&L%=dAbA-MoN>Paj`IIh8JIpl@w3n-6zrcUxb)^07Mg92CbUV&@FG!BQ4zTGn>mkknuqbAB# zU(nnIkn+Sci$0M7Ociw!Bx{gxL9HWg+n%DPvZnfSDVi>i-WR?f8Dv{T8!x?A^c~_$ zw%HG7y$9pS=te|axN6oPFPVNHiRo`6KYK`oOu(SX^2bXiRvj&d#{>6JM?M2(+yv^( zTqwflF1DrE6KnbC&okoUB3Mul``7ZtGFkbGPE)XIq=Fjs*7uZjX9E%K&2X)5Y`S3Jt&P=u? z2nPuf#&!GAEW0I`C_E@pt)}y4jDkZFsgHpeJw)25=%V|%T0~VzDZk0q*0vk?4JwyH zZ?|ppPs%sTA|A*{Ers64I`V4g9FM0oz|ZFNB(qOVj|IGSuL!t`xo!GTG5-$wDwvr5 zve7A2Ak)A0D>)DEu$Nsldj4B{YR})bgAoQpm$GwKpSzoQ^HD~=vyYK*JbOTU4xrxw zmD|2IgA%XLcNojilt}}G8EXU_!GA#I>Rh!+xR}A)>o#!)fBF8IKBT*U8ASJe&sX?X z$)FRtHuL+n22A{Xc))A5sNQi}FU?JOyxEqqyLw4jtf}lY=kYny?Xf6@OBNBv-%Q{AE+T~hCLp~f^G#WU^ly7L1iw~$1igtZ!#z5N7}=Bi;k<@q76LzphXOP6Mx$am zl}m)1=-wBwXjRkg+Am4f`8u>#L`msyKpJOhvpn56_brO?2I5I40NlM8Rjbt$dI1`zocr9hR52g;%_J;1oepnl!F@&6dnb9&c z(n&sjqqX%HBc`aLN7J$=OU=C^u44B{OC(B=(lW5f`w+P6rpYP$nFk@AkR;rezi+Rh`I`|VanWX(SYX^> z9E-{p&agnECBfm2pl9hjB9V%Y z#JkHCku`Ev(+?A}JhYa=Wu86UoR`&o-H?mfF0*?TP8WcPQeT?yjQA%%LoVv6!M4~(+mi10ZIdCD6oOAgks(fXkl+sSW7du`bb~PkRfvz5`sXyy%i|a zkrgq4>|9Ix^J9aJV2TUHqUp#d%P1|D$5+j&h-?Oq ztG0B@@zCxW!{m`nW1(&=`!?|6?Yy-q5_Ab$=7v z*nCHqD-PnL7Vild-00=J%enl5H9%08$&Lzf~7hL&;`@QzXZJDAI-m;3p zaOQ!%sM$o@Jk1q{cL^)a!HAl<(0BGnfGNtFc*d_0Ri4;C7-g3bbJO_G zCm&j@Oe!%ss1ZmNf!UK=t3S%QDmQ>k=zR|8?Jz9SJL3&e*c^&&9VGD!a%G?7)cZP9RWN9es z+F%AaW@g<_X$Aowqz=MkNf+Ufoiy_KCn;4Pw?Jk{F|EVu_=fL4# zmBIyx9OG&KQ3lCho+!ZM#UqB$<3_ubAALeaK+B@|=gzMe$N{jgQf70P@eeUGq@9>q z(yg|~#sluymP*;EX{MP@!Uh3x zvm(K5f>;yW-4lP^M+>2;u7SLfp@biPjbg!ef33blvfHHxV`OFoMw}KUQv$zkc_Zf= zqyK8_cO9!L$uoSM@wE=hOt#6=Iu;J*DYFP@>Qi~N;uk$E-#L_eMfRor0&R22Z)v|s zdw(Uv3?d1|TGb*!eNxHAiri36eCMTm(e5fGYz>9h`knsO&s4i~a`y1ufSMcN1^F(z zoo05$2wU&impa|<<4C zFDdDt{yGKbL>a0m!RMVnHHECaVHr!As6Uh{4uu>oW^R&L&yrHfQ1jlc!pScoRbW2Tx=f1eT`<`0?1_%jsj7o@?-5QSCdfDLQ< ztDhFkb5Qe*7mCMm$mb8aBZUqQY;oH+?V#P+Z&#=Y0_BNHGLK!EQIyaV7z)x1Q5BPT zaY5KhG2K#dg}l^#L2xt*v1kn6XYsqMVlgx=j9`y`>F(Se<12r`{)XpSy<^EXI#eYE z;K1vJOl_`pUf-I_ui}xVXDVNi5JonEnGEe{F4u=sUV!xnfd0=}+%06yV{o6d@1S~j z7h{&cp`!ebYKHkCA{?QuB>e+*8Jd=0<=9-Po0Qx^hpvj=&>;urgbEW5GglF=fHXa# zNOo(EMAbtK2`ZdMy(8mZzA*?V=8raZRrHCs6W#0u?VnN^GPP;(=lHAZ=eP7+M|3&U z`0jOc6XTz!i`^ld;GxKxn(u5=)UVb^phgeNFV+M-x;3=M=|`^B6y&!ug~rTB%&byK zy%RI39B@e@QTqbQryG#Z*8|p2htNgIa2k8zpINiwu&w=pc?QaUrq0bDmLR)#ggiha zFb`!$WL|6p8j_>EV-k(=ED~l=2PcwXy0X&#M5B0dH*02EDeNnKQsG1$l%me}wG!5E z%5@Z4hcw5CSrexw`(XqbQfioy`_WtEwiMXl6q=I5>ex4lQ-Q zU!lC!qrGN90bzDmFd*u!C+&^TL-4`zJ$6gWB;JSsNCPI2*}nd0=`B>tz9D2ffr&x* z8mI7+wx)HcJIC!bl>KOYvK9YWQ0bwbWr}>~r<1hP;-olv9LYM=*VoWTV@7xnM<}}D zpKX@YxIoP{b}R1obIp(3@4gNC3^ptgthuJ4hTE`liAse_aR*^MG+!)94^R~#wFi-k ztf@fNd$Aw$Estp?iw&a15Lrd?PEM)NloV8;H;*ZkedZ(1t z^j(7Ib0>?{jnBR@vvHbKUmAW9ZHmxYJ7k#6;!{66*uu-YAxCH`NiuSaWqi0l8G!mw z^N0KEQY_nf9t6>AR8=e*CU`4h#vt-T$i#Om*&QwD086J23Bjl|P80a|d$Zq)tDJ(D z+L&1%gCp6L9D|(M&c7;f8Ort6xh8WVUggD+QIod16DL(c(a*6BNF-%ssHY3l2B%r0 zt%{7h1xRK%8oKw4(&x59`!AuAw9d2%n}*gLp+Tb@U1VCF4}WE!OO)m`^ceD?@K6M% zp%KOmyRO-^2$Ld7Nhd}_Oo>YB^76{-mGWSqw+KFA^)o*n@Mygs_>@y`F@G2Oo{9_& zm#fy4)p2(slv|$N4Mdq){`4gsuD8S8&)W&Q=7N77RhtxhSu4vjX91v!tH5N_M|X+c7(_|WVtmvxq&J^&!=HAptvMFSTj@<$iOrjxD46ijkr4kYS zc(4Xq9oY~mCc4&XC=p}{-oepF!Rt}YP}I7`RcSAUOFOHatK}Sqi-d*muqSrKx*QQEu@g}OhBg`bt3X1nGy<0mM2~y5Yl=f;QSfqf_ z!cCA*V=S*%ahG44U5f67NIkVAoH+%~>p!nLT%%gd!cA;GVI%$7YHSHKfVWEQ4u}8w zlu-66t2}0(GtzhzLxj(TG7yQXK~my=9c>;fp?b#)ESvT4yfzmqa>aQ&Ktz#`_pzjg zB`=)_W$M;5a{P4(b(hRH6hVjy}%fNR66z^Td#@ z75Hcq}ES7qq5Ug1qu9(udaYfjUgAoC5J(Vr$Q#C!<1f$&bW$6n~33Rjp@N$IIJkh zJHs*PNmwKvR#zhth{w&W{osHi;EXmlTvQu*O%J0sk|k%`k$zRv$*us;>rZnZ>;RF<7hjgLj} z_7pn*6<%7$arCx^V7SBR#C^?}k9&%!aQA-KoZS$?FFzGz;lzdp{{{j2^xsLB;%R8hi(u1dbgH$O~$C->bX`$SaA@;k{yyZHxz7B9nzekk&{7=uiCiw&RKMCW| zLlt)NPn^IKLs19)nfl7ToBtgW8osuM!557B=^#|w7z_M_ZBp*FWLZVV0)E%r92LAp zJuXEFy$D@VzOd~3EOp{BKJ8TjipbDEv7a(l+GYczib+$$*j(>s-`fo|S*AV64{UVC zurJ`R)A`lIklp(H-!2fpYw9wVw26C4)N}3qP91yDY!kE}NzyyWb3622`XIN!Ki_V2 zE3%AS-8OB5g+n4JXtxy*f5mJ+)J&ja*`jHw5{07F)Rl*mqY)466*oYTv z(7Y5lzu=1Cx)EaqDOeAO8)J7D``u07qFhEH{N`zHbOCi23AVcKQ;0ib4pwkjuW``k z7Y8i}at`u5h3?iCwuY2w(kVSD?TkCQ7S|TJ4JO<&(bO?=|K7m`jY%jja}{g7p16E;GG5wdXm<5aKc|TgV#@!KZ4zV#k3oVPq&BO| zp50WO$4RS@g@OEbSQnz;ME!i^=`w{lXNMFlZ~eO{GU8Lin2%!hL5{uW&@V&njI_DA z3Uy`GCr{dh4{guK_aGd_82WfA(tj+=ZHj1^HHR&aKDAbl|C`@=Sj|lgYB$*2ke%Ci zb)bgH8b-CgWzc9bs$UyG`U>MVE1UtH`FnFsNljf@e1j;PI zY_Mb8?;Inz7DN_}L%jE)1pW2XhtFME;r!Mq$&(D`w<+c&3#Y|DRVOOx3gmDtKZms2 zi~f3z@djBUCrl}}$HtDm?OPGamrBlWw=YRJdx@=oi)Z~+P={khK6X>F`};|LGneex z?u*KFC^5NP+QJ_kTT&Py=Ay#q*VpmHLw@--t6P6oyYdnZoYBwfP00nQw*;Jf6SAcT zb;;;{eP6WJqGoh@*YQ>S{cAa<4$V-Q13ditD)W#>VPwSK*BpDp8YL||5dVOIEV*od ze`>r~lK~Cz<9vMRvV2SKb}z&CeE$6lveZaox+1fF+w{AZ2H(mWl(x;EBZ7$z`jQYx zjw|^X7E;LGkBthwcE$|}&7@<^d}>J5p))rj9>l#g$yy`JF4{30n%Y4v&TjgdwqB!R z{WrRAiohHTWRk?3nkg79{Q?`w7#rb*-p9_6u|B!xxylzWOlND0<6Z_ayx|?C9|jSp zXbG!bfnRkqJ|!9v$NeSPHJ?U6>;2P-KX94biPVQ!fHFvvjXIGRgIWM6E7`yOey5%K zDG+0d&UJ{0WsM-5GldN_ao_M%*jI^MJkXJRs-Rx`HyhQ#o3zVA5rO(gs>)VFff&DT zg+nsCrm6hbSwta&nBsAZ@t`7?{fi@k0Q;OJI{nXfjwx<9AN5ol`q|yHlR9Yzre9qjDvhw?8$WV1Fow{604bq=zs=pPOn~n=Izfrn9VSCZZabPm^k)qSK|B zJbs&FN)M0lGwFUP5a!$U+qUTD!_h%1s(L$Efz-rU%SjTOQt}ZhJpU3NAC(P(>66@cus|UIe(F>JRGhDcWvya5#&HhT8 z5VHvSwQmumP52!hIb2}py2&adynjU*0Th1(B?_*{sAfl03V)({a->M(9jCP0@_N7Z zPRrQb6NtXIl8M(LY#i9)@wPmpNIo-%d(R?^*wZ)0>p;qXmKJm|*D~Og7lqrj@WwOI zts;SUv=kfjosuc^{CNA-w1tAo&lJ}>3%nn8N=-&XQR=ESbFWEo_7~n(U3_fVZQ`Eb ztv#ph{n?^lp!f}+bM%*mS|Ga#w@G|zBjD*UL@653aZgR!SO4O1$TZ#0!Qblm5X)3R z<+*vvB_|{H@CSB}m;wSgT8$~)6vjTDU&9cYw5NIM^CO|jveQ#jmNZ!t&V#65MYtxK zpFS6Q!it|g_U6D~|53dM@gb5dZbpW+Gi%C>UpnsZ_3@yde>!#;xOZ*n zhkk^-pw8FKc!%a{7+Y5?#Y=Dez7sM10a27_;LIg*0?CO!vF^k&R@QA{vEBq zz(tw|k5LTSo@}s^F67MZm8F7*d_3qnRuE;W&8*B{r@9MP>6{e*o5%0!lavt#%4KFs zeZSV@xAH5Z0!=e(GpFdEG*I7>$mK6)rT>a}z967dl&q0O9W(kl4{eO+ z*3fFVabQSQf#fy2*#Um!N9p)^(P8fN4^MpQQpVNEIDLCf3d|{661D@X^fCSE5-rP$ z5UIQJ=QeitQ*^c=XhG}s{KSO*?IW9*%g{{*;!AUzDD4okdjYviDywn(t!E#k7JAPag`nWiT=3c5fdE(jL1uEAd>^gi)c`T0CR zN^Fg=J#;-dz#~cbE17C*6uRNj8Ckukk(CT8v6e)JWk-`-tU3}>xge*4Mr=Hy3t}== zvi12a2CwfTFPhO~*4tvS#7SZM+ofB~C)X$5G6O7#FBRucQA*A$B3SD+I^>3NL%KQo zKwnz6-Pt>-gl9zYIpf6mG4!qpeLFOW`pe*W>Ru?;9UIl^a#=sBT_J(rN(FmorqfFW zSQoGND71oy5V%h%lBS5=@g%iGl4}cRvM0j^jnPQD*c<(_W*e+| zkh1qzm#s|->AlpLD1`koF26r=7ajr=d-w`J+IIAvmh6oLI{9Oq*Nw+tBy_+bUYFO5 zhm}R@8)W7d(=Q}&E=wxp(M#P*yMJ(W9ZkIVEaDnFhmZrDFV;`zo-Dg3m(Jq;g+>F- zkb`IEJxi^*q75uc_?XF)iuJjL3i3Iom-8oU35_C%5Z(TxrimN#uUd=#Tb0ehPm^pq zo?DjC3SysK$2K{_0{`q^pt;i;Vx*&UuMB)rr)eKB^kLa%gV@Zj(6URT;7ODe?otO;P`Owz!dNZ)qcLy zP@TSyEUhrQ*{(H3_xg1OUXMmL{=Mj=w344o&>NR%u>kFmUNfGhyX%8kUvi^`7US6K z2fk4%CJzCop=)2a@VKgU#*No0&GakX5>MCdRCtcR+`2GtjlU}KZ*==d>()AcLDq7J zURI53uo9y18jnP@=Buaaq9v%V!i3)Cj&D6)d##sO@=fu5z%8pN$+9>j;S=@<6?@Ir zv@wSrVQi-wt`?v9kBc>@IN~f_*i60dHZEoFH9l;LuRUb!OU!->%eGm0NeXK(tdd@e zVMv))YP~M!!EQe(SUvv-1Va65RT2frDO(40pOo(v4fEKFrmaUwCAS3*hSSOc= zZ{w60Qtdbf&W^(7S{QBi61-1{&I@Z>f}%1-FR$ zfopjQ>nlTkFwTGC3KHwI@!8p53l%Mj$(;G1Oqa3q`0BdqfVD;G)>%$*C#4IHEBVjq zTXM0z1lgXUThKnvcpR>c8?-o0XOJ7`TBb{O9zd|*ck5HQs|V&#kVeVYx+)2|8QJO( zfX(dO%Fw<17J^Q6S6W(8!J4i#F$P2*PL8~mS&E8^;MhA!&-w>c-4ZS_zvF0SXbG}TO+IhH31F0}}ok56tc95dVO5CErgu?K&Sb5BTDGF8(Rz{K&2|@;;hT0 zi1)jM9`bJ{3|3z3j&Ix@RCe5~N4!-`dtdt7B@Hw|K?1!6r>q?U1gJN(jEq?GF}`+# ziV@HPvVSV82Yu9v18{lZU)l4P)+^D)v9PcdYm~6hr^)5(>FI&ySzi2wEI&Cg)i=i1 z07+?meL@)=bx&6%QTyFcDJhS6WQ7u6Zh{h>V3a|8jy>O5cRVlRyUsUQV(ZC;nF7F9 z184Gomr3NJISs@BsdBE*miJu62Jk_P?Bh zRDtZei-Q?hg0>M{AV^NahfsQN;y%9|Q5+#M_B(x>=^s0krzG$cpZe_T28K~8$%q@+ zLLjp)f1^AXU1TgRX(4H@XAJ&#m#TW@hV{JZvSQ%VfbO5~{*C^>4&D(~y1-?KWL#fbV>TXP`p}X$;QKtBK%N)Bmq+ukYBjb+Zvo zB^K}yh6@Jg;RHB-Tvva8Zs)w3=v%08uQStovGMA#JR>Mf@1V4@xtV9&=a8e{v24Xg z|0*84V737yAW^=#o^|_^5o2RT;@1tTXOHHtPV3sje*I4#b!DLC37+OrzxxWzwEt;)!Y!G0$MqKU z`lHBv_ZbQ~JL!~Dgu!si>-=XpQ~3~8p(GZcn2_OeMe<+ps2KFAhv;qWhLK-V_?cL4 zq|30){z%e&!2Pl3l%}?Kg*EbFe}>;7Nc(Pp=PlRS_~uyD@$hdL_OOs{-WTP4l8yXd zToTYh67$$jf?%J@_PhPt^KF@&81Tq~W~`=$257!Mo*fz!MnShUwJU)8VE?PSz|N35 z#QBm(n{Se@^>KS4vO0pbeK%H~)%&ozA7TP@Q<1fWncjkg-zmH|V><31VU*Cr)ALa= z*d19#$6i4yXuu*v?vFZFs{1Jyiq#8|sk}~ruWuQ6G=n-pEhoSpdv>bo7snRjn_Pn!+UlhK@;e`Kqf(z$E7WjUK1rJlAIj_ z85yaO&tCpI=Yl~n&VQ*!Kq_CL3_uKb7ab2UY{ql8h7;dT40bG@C3(p{P+dQF*OZAp z-;Ui=RXxWusE1;ZxlXFeqDg@yLT=>)Y-n*|DOJG_C&K{wePe#U#Mhpob z=tR@*)|Nb%3>WGf*wb_{>R$Y2X^SzIZjKj&l#e^y%>Y38e}{N@k;m zL-0beDXkI$JIjr3ESNokug-kF?jx9ZkT+{!PiXTcqS8OGBD9)7g4HGE(bQp7saUHCmF^E`^rq9X) zQm{&efUSAE%JPbe3{n5)i_J>t;hKa%aEDq zC;j!<^dJhz7_stPa+o=16Bc{<{bD7%vA6g;pipy24NZ)Wc9;X&xp(~Rth5LJa2C5)RkL+qfNbd^4RzA zxb&Sd5WbfjsofWfJr;NG0G+8*`|bAK_XA`sQXM@bpYu$ofb$W)|J)3cJ6U;oG=$OR zmBuTcU)wKaKY}maJs@cHAg+Rk*xN3~+sLbo{`w(T^)7t4!2#m+_7Ob$)w+W^b176ZR9IuN5S?jDL%2R(pVY(t`L7&T2&Cm;eZBTmllTyLL`Y25wU*gAhqmsP!62m zO<*Pl@=QSfp)#DkimFdyN%=BluBCJAV=x?M>@~IIaA7|)%$N_CRYQ0sz^Bj07wcH_ zYwFm5`u)3iUk;kV-sy_tPuR~9tLr&murRb(?@tzI2Aq9lCM6TLIpGySf-mPGT9lc* z=MARPd?~3S%jI7bUjxtk5x2Zf8na+H>@KvP5bGQqBO^SZ z)V}E1P>$^1h&tHxbQlIR%EZK&aGS;H%i+6gRZ{bY)98-dtxHeko)1%16wQ;Bdah%J zp2A*3?rba9E&Bu03Vg6}eKzlaxdHcc%Cz%;V$p3b>!}fm$4lp5zgf3lT&z5CGJLwR z8uFSdj0Q-K2z6~{O8xe$n%rp8v!tYq)`yelprZ?9ay!60Rso1m z#RlPJKVhzQFzUY|Mf}fCaL?p36w z9oE;^i!r5nN%9ve?j~QWX1f{%pTugo@4Za;ae~X6>*u;!` znDpR%WtqWyNt(a7EeU^I>*!#ndCE%9`93u9-nVWQ*=*F1O z`B8tU`?ee-+^Z+~hHNT~-%^ZjAf=Nk;NNY^>h! z_;t0iaLpeL9~e}!Hctf41s*rozF@_wt+dSSKihVGdAGi37iH0HQ zdhwy{?lRm`)ch_I_l?Y?lZr8ZucKkJKi@`+Q^(^~ZnUWFbPfsJOFh<$LMmv@6i#pR z3*j;4G~v??Wl^IhpRLS}XOacZ2I&z}+=SQr?`Mj&%E4@3)7Y3P>V6ld`i7L-<`t?M z5U5&>rU=;IQ~~D>Na}RzyXLZpwv(%#j(HB24Y>auj1%;k9RW9pgZigve(cTtJ@j@f zX>500SRao|uDUbq&pzyf+@Ppq^YP!6SO)Bt;Ikt!H$P{iYIh{)bzKib_9m&5_r-e4 z-b%S{y%ktJ52h=J$9IAg(SdDv4VZ6{Fv!{0B2ejS_Z~%I5kd5&g5_GJD)cDS%)|Si zn$7O8sq-fGbfOXt%EoQtDveD_x5XPgXR`}?*| z)?yC(++R9RGOyRpE-#lF{1*n}-inBb2qbb5W7^gW^6^~<%s!r+oIqV)vap>VHrCE~ zNnPr++f=+khpZk_Tx>aYkPDMG`VR+e{5sbA%XWLT^C&a6^YgtYZ1osEv|r;C84~>S zfde~O4l6*o$=9^=AIo=rt(BTjOG_Bldbu9{^IC>a=dJ3E69x~A7mp{o^KeQK6NPV? zT>jh1_k(GYWOKhp2B<~2AsE9Puk7{C`tKZEn%)~WY9_5c3YNeHw?^7|!nD6vl)ejN zz@T_{RsOTh;$Tnsb2*N#?@bYQ+mmH#eET+aRFm6IIH9U_A(O(bOT}f#N1cu}z=wpb zbX2O)KRiBc^~fbKF17j2OmIQ3Jcr^L0Ei}Wsm9*L%}u}FRnyO}l|C%sDd24O613CY zua6BCoNYd=&7Ofy5IH&d<_2!JGzPd2qE99R$SnGG@l~7a`!zOeIRJ;Zuy^R^=Z}O< zez>`b0Aa0Q1(2Fwp0JEwv(xi)_`n~o)V|k;{tq|Rm6>ds)MK1cvQP1?G_tY5a47H} zV%ZamI9Wri7t(LPU=k;-*N6w26wR>+wKj$QX?BmR-)S@pA?1$R{X?3-Amwrp|09E* zF;mbAMK1qrdPJW>$b+2SSsdWtwnDmcqzr1U6vf5G!Rh4X%a`ErM@~U7Qo~HW34&Gu zwNHyN;p5&%A&*1$WQA!MgXDk(XK!zBzNqY$HzoC_-M`sne2yo=$|x~J7fkqQuVdEU ze1$%&^#jApG}*;}n{KE{hgRvx(5T+YPSBhF=!@ei{d_Hu27b01lPj3c`egI~Mtlo< zxAP0K(^7N3R;jwWn(x)FfZxptZ~4Lp9ia0}>NN2pEBL`~0{nf`#RO=GreV25E@#@H zoFkZ=5ErsW<=?bEMkUMMnbaN1KYs{XrOYv;gg!Kf5#=Zi+a7W>z~N z#eC`al({X<$lZV$W^j6U1(OT~y5h>c`&W`MY$bH?XO^S2^`N=FbjI*cYrS=b;JH#E zR<+C9ja1L0PLXCo$K9Hvnb@n5M}<;Vv8Kl6jo-gYco^TwJ%sWMD;XR8^7B~PJQotX zwedb`fceZ1r$dk+&$r|EU$$A%OEf0rnacHR{r1+FWM-bWOP`3`w~cB!JzP8(64#H9 z9eqo*O3M!z&h37?bar-5t0N;Lmol<^E6-DCa@`8gzq!E|G!+mOoHs&4LyN`MNvzlE z9vLauAR&4C_N}g_dIpbAYzLHsPNxe2p8ZxZB}%=+{<%P7M`HXB!t_Y_ztJ4ig!=%k z^aV6Io>xdXfdbe{_ElBF!td~Qpkf5!!S|@oLc8`s{pYQ6`I0EW}po_obyod4p!dsI`+hHnaYOLc~`0Bixy#MiZh6?bXwn^G2 z`_9925gSI7J&*^f9IXT(Cs&gMah}fCZV<@8Qpcm;hN$`#%N;r7_&AO5pR1m$EANe1 z|HCG}FtSSiNS>ix-yUb>Bv!GX6hYPV?zbZGqp^1>Q8$k&6%b@1rEfysPFM5YRGt;s zCb!w1Ey@88KKFswJaRwS{c3Fb%dYo7i`GMjcSAa$_jCPii-(7uqst`=ULk_#R~6Aa ztOs{{ty5ewFMfC4;*nuL`i$P0a`|dL8>{tMUKA9xrVk()v|B2m^dZO-m`pLr`&1L$IH)f4d#Wuwj>$VeT&F(=7e1V`^liqDyxz`qr>VZh2qTlcukXE? zHc4o8ZEdaAKSm4)FcR4d^KQyFKureU3m9gr(4(34&RXf%razyvV{}(9=5ETk=N?R# zYO}pz*@%!e-XuBW&tP&l3Ea8;icK||F2pAyVmLj-HbYGp9F{X%uHRUqS-Rb^M|hg- zIs53cez?@ar_J*4_;2J!f5#JIgMWDbl{Jj!H1H0(sE-U0yvAW0DCeMIR6&OrWyAg6 z;fUQDNKC)V7C~~aVDqHA_n(KZulQD`w-v|y9`88byxxa{*epp0%(|G)+(xTo9!q6n zRIXM~7-S%SD2_>FF=T#e!HdEec&;Da{T$0F%@(iVO(qd|wi9_y(PYnTt{~)8X^}D; zAWIAK4I&*SXxQM7({K^d*Sv#mu5UWZBLzaY=E$_2{CG}Fu|;oIQ;S#fL}fKygD4^g}>GkP!P2=>(6RGvlzKujh%Ev<1;N^OWLPtOIx5ybEc0991%Y^&=-Q`NJ zl3mgr&85ryh6q?f#C{pSqz#cgeYGc{WtEsdU6D5x!O>7#TdI~nWLGJxlD``+r*n7i zncKqW%%&1}hum-d(6DG=_i1}eG0v*ob`e&ZS?G_yx|ZhSnC<)hw8&nl=p|&ZVJ0e~ z6(ei{DcH5oj_(Yzc{_Z=wZlmhH`+-O>tZ!pFY^N71OmBsN<(~w(NA=c{Tk9k{UTf! z>fl?L*dj#}`LhuUqfYvp@>~%$Xj+8X(X*Kk-Fu>*${E~ zch!TccY!wSfpafxg^H#n&q_@@e@3Z2Ch2!|=Y19Ny-E`{J)1o>2OWV4m(1w<%?ag# z0Iqt&dk<_%QF?cm88V+e?qy9evT25`iv~|YOi^DURLHTB@M3{_WsB8OPw^uKE(d(D zRxv5K%=443-RO46z+mkr;RJCWbMqH`)rm08$&U;42WKfHVoq=nH=nMXk77aUD)zPE zfA-3KZ{GXO?sgo>9HV;THJ6mDS7+C; zVY~kvZ>g~IY3Q8U9P;C9uI0#Q4y52Jd#(wAjift-B=THo432G1ZwAt9oLr8i6Vd^> z$tAG@#-^V)P07O%>Lj6S-jwFdGS4QuT33H!%>(K2(H1aM5F~y;ZM=E4aS(1}$t?-d zJU*$EPKChb)5;p5{c%Z4OYkG=cfsf$aR2ex3-*sDxSIuLBR^h0OLJL|JOH;aSuZyy ziQ@F9jExOg-}A%4SUB|48^VUMo=i#_(zlhjx!V=_6-v#AliZ(AZysiP{mC>;YHtea zCAa++w_pqvL4&IlIEOtn*9W(bA-VU&s+s9;-~z`jxKrG+c3}}x^1NYY0kxe?-aphq z$}Enn#NVBiZ1?BAHV?y0!JNk$F{bQEeN~aB$M#Ot^O`hCS1`ZolB-K~WalCld&c3#@0zc-`OkGd`DO-rpWX zGQ{sNVbg2$O+!Djk8AI(=f_OkOGGHkh>iOqUnC<`{HZe3~ELI*wI=)2sXiYOwF zxubEnUQ{y4Qf%P`*1&JyzTICPzj?`_|EK<75(^8>sNOZfFM>X7OLC~*b|Tzz7A%qE zvrvGl0CnlFiP$3E>zmzQv4!0C^VEvHGL!?-TK(qEc74Wye^^mTX}Q)n+6K2+bX2=p z7|a~e@tXxeHv087YxU*7T?$>{-I0pN19mlC{ z3cDF6#X;U%1nvFB>fZ8hyD?gZ#iRHybk8KIM@W!*U%y|uRx>3TQu~Jlb7o5gBbxpc z5D0$73hP|_Q9O)uI`2A9F~)mYZk6D3#PqR4z3b&suti>V<;*XsT0u>?EW771JCF3u zHzITH4`qnO=4K1hQV1`^O&%#z8@RDNtphO)>ORJ~P0>TRO}f}(R7X5ATdd$Tn@$+h zh3ak^kLa)chJR@|+1^#C$a&14v6u(NkY9XJ>As;A;>(Ak37l=R9;W1%tPHcB7Tm5$ zc~L7e?|@SfU?arEB#+n2&*<|x@izrzI`d?=B8gu(H+psAx#-ynRF#>>eir$(&0`KWK=o?yxKW?TxNtg zynZDbI-2e6%@ip&4`~l+A8C!FqO`-b;9!JuEwTyz?Z55s_CD^RP)pz_(BXB`XlEX* zum1zb#*;8-$q)6mQ^ZjpXW9+Dww!C{9_UZU<2K)pj*j+6QB06s3=R$^FlxU1Bf0*i z2g*6i8FJQPPNGiFhDE{e?N&vOqp*3TVzgZ-5oX@Rdo*v*5 zTD$+(E1jMufhN|`|Nekin8`T%A@q_gib^P8`wt1WXEY`3((A{Gc3{;N2srasW;&fGj=+C`AJ(Ra0-Sp3OodgR z6+4FcUouKjKO5d;lBmJaK_x}S5xKD!807uma)@=g&H!VHF1J|e6Geg^Pr%|0sB`c{ zJG4K*wrH>Ya#e~f6|z;xZpDJ;%qpnVJ2YFgd_9i#7MsqC@d^=Ci!_SWyu7>~(r<=| z*o@mh&DnEYAC7bJu<)!I1xc58A_(ydVUUP!20T0>U6RqfrM2F+&?-?I{9%oPf-ws& zcuPJB?)S<{hkBBd3^tW!v4(E4?#sm2Z{D=|xAEvH`dHn839!<*Wx3d{aPe?4uU~d9 zc@9njE`u^7b=pa-SQAu;uduGtTRvf-Vm5i5u0sQ0$Y@*cjOH4Dhgr?|;Tf!W76ec5 zUF4~G$)4gp>L`527)Nd=+w~Gs#q0}O?4aR)j%Fk(;(eC)3dOcQ z#gybdPN&5}frDHKII~2U$SNz2eHc+;OgNY>m-qWwq*cn%H#avY)BsZ{)J{|&a> zS65fX48=)o##Xq#H-Fd4%9y`vxjij<_q?i|Yc=ggikRziF;G+c*Ia)fDfteIO3-iP z4s*XvDtqXrNwABKmq!v}!l7Sg?5$AsKJQ^54ADoa$Ly(w=*7zz_D(IhZy%=RYx2G$ zu}=1!UFU=$)vM-69S8kOiZ}oLGEr{adUGW&I#V=jnA3i5h*-ohl;IzdDM@1e_kTV3 zR$bJiDY2QTFT}+ItHLaC-Wb0Y_X-`G89|hC!?3Q_*&JDpU<)7dT+JaPeQq%!rlS^J zyBb+ID<&890sYD|vz3R2o|r@ zt|5d0BL3T~;bDO{F{_o*GLm>zC)An*H7pEwj2-32U=RVu_tRrUAl1C>T!a3GDTYOLoE zWZaFQip=+!6#27nC3=Wa!d@epcp=fC%KtphzLATryP3Ii-@KaV%u}I%{>h1CMpjh9 zKJfBLTRp?dZ;tn+pphaNWXsP!>gvmZ4A&R`ANkf_oYK8*#d~~-XZFLyMgPAyD&W@q zcRNZV89)dGxL4Aa4?)$%T>rS93{G}72jifCf05egD9SQZYdu$@$z6woUp;0Gt0)($OeI6mg`AJQsoWi{aK5;KXgZ&bx z&!1ggu|GA6Y2ZY&JD!V8&VLdq_#c-Y;DniyDT#<0ea9Rje|Pr8?k{RV_v~&#eVGx3 z`ekCk?NJh5p%S>b3s78iOiKXGdsI?f31*o6R zt*yC&mX;RSd_7aM(I+7H0VMjF3Vrm3VFCL1XY$2^q21{teHiE^&vJm}l!B@7XC&S2 zZxi;sf&xK)ettp0AqK{Tq2*;GQ4eQl`UX5k$ceCVv0OeAQRVLWgChXcDx|sD4@1g!`n%( zrml`CadLH4Q2zPMn6h3x49@Dbs~6a!P|?xv&xY9wl`{h__ci0jX;5Pycx7XI&Rg}$ zt%#*7XXIlotgXM|0JgqWZL;alRo71S0tJw-MASD6_8cV?m`Gp9yCy6+UC0Z^Z4e?% zI8$*XfqG}hTlXIb8CIZ^3{xxCC_dwp!otJ^sTsC||F9_p%$Hj43UHk+i9iOiUR&WqZ=bQH6 z1*l3C^PZ5va{Y!xbcUpu7*pO<%VdI5tv^quytv;+m99r-R=92cf~_}NZ#Ocw@8!Px z{gp%995=Z1#A+5elRvv0SW#HD)?=(%e}RZ%rp(ZsGu4c==g*B}=%|v+LQkoVF(PJ& zkNUIx(mFxQ9VAv|c-`R5JY4%$IYZcQmwmVfMa9vmLb{Md z*uvS_`6MKQ=<0YG9fA-C3Qj4CR!AJNG=oke)IG0tNc*@WEAY}&lUlqdw!x!rCzE!D z{p0%PDt4>%SY*h;OR;yrCw=AP$7@myLBHdkCz>znsdO>4p|*p?6n2f|0(R{3SB}dp z3!dLgcF`fPNXF9mZ}~;o@_d%i0!BmD&6caX-_}N&y)VCmbJT<2xKWiq9KeRLGjWvG z^ozB|lqd{&LIf4LEhxo2Me%_w>c_ilc?E@dI}e~a{4e7L6w<*y1$G@E#=?UM`D0bvt0pYBc-D~w zi(DWfBJ#XA8JE{)eLU&LzOc-FXjCno0%?2YT5p0k&A~)EZX0m7SGe5f^EDnlnb&y;-2cw;HM zLI69{26<3aJg)J2rIdf2ey26LO_I82h*kzX-T_c=5tX`Fj#>|xUGH00WEx^w2<0=c z?>-$&vj_`6>|_Q!nd~Arc{fExMFH?HN+rG{XKGmjAL(~MLc24)!rpo}>={sa4*b|{ zZEeQ) z3OJYA*i8}X8{r1jlWqAu(|Q7BkQ z5G6h+C@6gRU^CttqM2P`&{X44+JI?JDkvm$y*t-EH|YKR^mxXv6LNwE9ve3gkK>6J zP7|NTvggIBmevB%gb~B#`_jpp}BazAX@)UD=!^(~}O6l)c((LFBTSCJBvMkw^GYtbvvjNc)E!!|Vrr7(+3GPM771oN{a);B^bk3O%$P zIwhKFk|xA`iEBx1QOiyfb+`+~Bm>gl2qV~~&&6(xR;eaq0t)qi4WR0&JLX}dmH;42 z9vK~F1zig8U^O}}yLxyiDJZ;0p+*uAJeJ^*V0>O4B9-UccC-Rx3 zO7wPm>f$6!xrMs~34&G_m~A{FTzmaj>Rk<@IO;3Q#mCDevC&1PX#w9pkHbaQ0$#|W ze(eSBKSUuErWqJ7$9@TqKKA~Mng^~Nf9=Po5_kc^B1%KH?jY}qn*vTgwsb!D>(iv% zFaElaBDLCE&lTmiW$5}NaxzZQ4<6a+Zl)G2!^*#`v z$0wucgJ^u#LR|y%!7-5E8V1`BZ$eUQqu9gXKeYM_M2o|W;u!B*;Kjv5Ld6u*y^fd0 z)M_a~1HFcmm5ax2GEKzuYLRMt{!V%cFo$|ha8vml94CL_c3Obige9Md<@KnZYCR!~ zF2d_id-GD1?TM9lx3~EPg?b^d-W9vWU)6qTF&U;K)FN+|h9^oVVWbfLc_9y*71Mzq z)EA1m4+~-;#I?)|9nfb&7QLb=+qw6IQm2C(Z$~ReG1${$)m`Okdt2W)_Jany6gxx9 zSgmwnlmGb@NHW~I9yV(bR`3G{?Gd_Knhz){MoN^_JteF1<4^>4lcv%U_Q*pzmhjiz z?5?lPaE7acUTsFJ;{HY`on(9^9vGGr2B8k7k$v$(`Jl#4SOz8ey1R8aiIpiHEn+S< zIiYym#^#*< zDlF~m0W{-&*c$5e)NZ|D9uaVBdymQkBga2Za=)La>Uc2KqPofR)p%&PET3=l9A4L; zU9`Tf?AW3v*Q$3!g&(63Pdgvyzprj9eIG2aP+U?+?z3k0c6k|5AzDE?+f0M2e>3iY z*O6kJH4Vq0A$ zeVDG>=4}3ELyQr`Yr|Mx*i5kD)Tizs4H14;sEGmcWWYVRVyAOCMBtzHiPF6}z3p$L zdeR`lUOlEd;K<*j8I9L!kIBeJU-aM(gb{!516!#i+jr{p&o3=OeK>{3$*Qt`rNLn#ib7}|)}#Hs zsM&IuFw&(rEL@-0iRAj0ALEzNCy}TPb_TmjB92{9nlQ>R;&WPD1RLJ}!levaU->eF zgr~Q*-|v!)p|^lAxU{$kuA@wD#Hx1OhM9x$OoQS#yMmG9@eU z2FcU(cYWr5&aiJN(LciCfx#39-z0{afq}vP+X$a-qJQjNj|I02h9}6ZX!E_!;P-wl zAaE-s#_;T|XwOXwsw%!2% zufFUhp8X{RU3N14pZ2cCr{D1zkh?=}u3@4pKD{;DyCV@hV=MBlGfYEAg>3Eq%s6~R zLXi8h9mgi0wXW}R3&QmUk2_KDC|vENZV{8q-dBCS5lPWyw}XatVYEJ8;||EJMCu!> zeaYW*OSOs#=W^WdzfJ5|*F@>jqW}Cr*e2h!`UEdTu2=hDRe%D~CuF9DyG-qyY}8>6 zloFq>&J0jp9u>abFiK$5DpPH7Oge^D&bst1_a<9HAPtB71I^qvI7RF!%m}q3LKx*; zZ&_CY@FBr6g^83tCr15OTWKU5D`W(CUA#_Wd1#rx{1$La6_j<6@X!PQN7h?FMb*7= zqlXXyL53bcBt%K2yAhET>F(~3&LO3dMkxgm>FyTk66pr%Zjk;qzW@8(yVjk>axG*S zX3p91Jipq$jp-E46z`nZGF@0JpX4c9{m$I!l3%0Q3VoyUjr^Nl3U_6G{?@n16bWC@ zT$+B3i&Fyk>Q0?MX_gU5%A4m<-hqpYTWL8SmWTgTe!q+LenFP}(|!|oLoDb=&-;65 zXk(#8S<3V)rB;)MQDIRRe~y^vwvN(Ovq2V@@W3T22a|GBDNys0joUrqH?=l&{1g4o z_xSKMcKDS-eEmLA_$$>8P^#CH`_?0>U|+dY6;KV~^d3p;&F^m70kr7*x_h zjsU&(p4%%2fM_Mz7!cL*@$vw2qfqo3?XFq)@a3h8_54toN$;J}A^=CItEMidbvWye=*z~KJ7m)u?SJ~D3 zT-Sk!ZLL0qA%zUz8+S{~&Ez4Y)4gfmqtpJ94=h&L?&;&^9GF3Wz(mR)EBM6W9-Ee> zqw1mxSb(uY4Oj4ju~tv!HF=_BWMs5}@W|BER0{vRR-(KRL5U84j{@Dsx=Ikz&ABMO zq)W!dBMz2sZRZFNbKDONePVB*%fV`nV+* z2gh2k-r4M`pUm^rcD~W5H)1}?dbYeUm-#)6HOwn=Vs{F|w^-0?FTd(jLOrv1rx(fN zOjaZ`en}!Twz^FvwxhqD^Am44^f#mCJEr4C1XIpNcI)3_P~xHL zJDy>==h$?m2K6%OISG|{8-4m5YBP5{Qp?N5*^_i`Fyz>)rW3t85&z6wlhe-Q;*YjJ zgi@k;wh@kVe4{_UYNN%hQ}6nx>-4(5`nu9>H8%1--?;CIf#orBcLJkIRCsv3^JSuL zadma|*`0(8=Ohy> zDGQz08neO2Ku2``7Yvj2iP9w?c0)!+DQGeh^f*};{@kpX-Qctl3t*$@=;&0TcVn`( z#XAez_RC$kw~#OIk%iJXY;pk(LBZMnez_u+pu^&wP036e!y#(TMm2#-_?x#mUDk8?~Q!xM|P8@k|;T8fD*Py^<%gJfm@5drw?8&LuB^GsrPAVPs^N zXJyUR){};;T0*yfjsUEzhE?o#IMV%*-Lxvi1_|?EPZP`A8mEV+uw32iuY=sg1gKK?L@6lD%4nHtTwK+TzTmN~0Z#Iwy3_)*F#%x^n z=B}?J_7X6&+YNc$_VqnH>cqad{oP+IHR^1R0n_*uR+{6_f0@Dab@(dx z1l>$ZtSxb|j$5Mh^)=EusQalFfOn}M05_yzIu9IQ_5B!xj?TY@v>^oih8aTOWGS`T< zQuDdIFe5>j)p+p<*#r&}GBQ^0_tDMb=5tLLDj?L9>0H})rT`YEnr}klGIeaBlq0vo z^XBxM1p0x1u+0UBSjf!i9B#GI@T%M$^>98iG6D+Lu5>;4Qg(RK3*8#^qF|tAV@Qal zi6rMHqN?y1wRCTg<|-Rz{|#&{1&X<#hvK%Gsxa**EmZAwNS(A!=ky%w(_kCIT3FyjWt!6_>a;ToTSm9R+ZPo@pij+Iq9V*suxquxKD zxSH$~9=zbBeXjKQTf2Xd5}%75$;o0>f*!tWxcBTExhvVuXe6jum8@vbity6*eeN`O zl-)h3CBH3?`^r(j-ueCwOnf-~6{8NLO0iCRrzU3{lG?^E`WAzWXr+#)?K&I#{jLHC zWn*(@y=T7+F66;~?lg=nrdS9dLXfDwqW<+hT-ZBXopC?>o{9;z4D~k;mta&jUDC62 z7c)HxEC$Qr%JW+S0uF*rxoZg)%?KnvB;e%gzW-9_t<{MCs}{sPsSo1a<{XMw+#IB&2d(-z){^MuzFHjgeWft_nH-#A4f!Dp4~l89u`ktS%12y|0wLX zMc^%zGW9jK$T!?_@#dzLYH@n+lTgZaVM=WGKv!S?uoipwKu-_*IugflPX9sD3+Fr{ z&FnJ00Gw|OP7L0Oxyg~^-p4a%ni4N=Jk-q*(ap`xb|SS+^UMW9`hS1M$h8=E^|P*S zp5P%oN5Azmuz=tO1tv%xRfZ4IZ4A}_B5CeB#b27YQXCzh2ajs6m8pEYk3wlY)8qC# z>j!_|>{TW{z>9na1%&ED=A+r{`um{;dgTrH2;*OC#->`32-_zp;+$=k4+Sk_^PEk> z`;BVVB>Jziz2t+PlxEuZ~82o&iqkt3*nr%u~ieAT*P~gyG(v92FcntM$ zd*1HjW+bHGd`r=H%HoPCS{G&0Vk*j=;xyj)cD-k#?XW%)sqHtxTd$HwI-G0d{S=bi zoxiReC^%At5I>euvg_+<*0riaA!x8Ca_qUDZf-CRG-AX5cR6<|pUb-0nfc?sH1qA} z4mrM&qCY8T>tlAkRou~sNe{xdIqcm<+B7)@pwFuLep`w6>)(s>vO_=>%33V-jS*6I zH*0ZhM&q<{Ll)_uK-x;WUrW?=d}*kgg+=@nQgoM}B^Y-)nnLLuG}(GidVg)7fs?<& zZs~0mqHujuW_2*5`Rx-n#X<#qNUVfX10AYbxCuaG`g<)uB{1*E_M44}NgYOt=Ka2@`{?#tsU6Xt9K?k*qBbNJsx!T^pJv6&&TzAJaQFjOXks5SLO z&XoQ`RQ5I&%gQOkD#_Tu4&w3l%5?oc3=TFCX7YaF_+sAI78dbP7ExzrL0NEL11;w~ORMA~8U@ z7gK;mes$Yu)m`9aTz7u-gH+BGzje85@rkS5T)*t#PjoXAV?k*zU{j1G5;dQ;}2;={BzO-MeWE zeDC7o@;dr4=SSISrN@_-=PB5$@vrFz;YK-cZ+eSqy-^8zv_^CQ@>NneUDX7@eGkiv z&?Q=cWvkVz+N3oO40V@E#XSR=G!X?v8~S?-J6p3~jNXId>%?jtUp7y*c=OMnGIm?q z-m*6@-T>($E7MCvh1L8Uysz=`@uZwqfCe7R*JCd5ngH!}6gjWU>9K}9^I*}Qi+B9r zE?ukUJK5a!Ownw8$9yO^X~dV6mz>gaVqVBlh-sou#~26DPOXvh4~Bus z^lM_|)(2J8e5xXsE~NgCi^a$%P+rZ|__Vc;woi_JG|>o^WQ{ZwdnpEbWoEtF2G28F zN=kJ9=nVM)H0-fLt)!H=eAWD7y+)slkN=U!4mN&>hW2{HFj-R@r&8m%GrfM@qTsG6G!k)UYphJTdMz!3lg}DG3 z;ukt~PTkgA|4F7!bgu*xq=Q(iTq|z%m+xb^;#-Q3NxG-TrX*M7dGZ*_GL~@J&iu-1UBI8<0LaZ_lvuGxD!UNxPW3 zi0C7ts|UyAv=SIhfaE(M>t%|IjlX|DkxsotfTaS^(HI!ZzoFys4|z0QC7Bs%b6m0X zC+F2Wy8dGZ#r5GLp~8aO=jof#M*PM|=!AmR-r|EbmMQL~{?h4Fb=y5b(y=tcT6L|L zw;j_14i@siU2Nv>q4PvN5rGFg*gNq6psHPlm^U2-`YLWVkjk3U&yWyiq5-h(YO4%? zweKpH!3J#XZ2c1Ds#&uY?n+`_{skrFM8)&W!}ccv1Zhr2xIjU*$Q+7UN#9#C zMi905p+N!-3F!xQ;wvVD5T-t=7tJC5)9#7fA7ufh4J>_B2y^RAUrwgBxmxG7sRS!@ z7!q~o=eZ_t{@ya_Ahz50t2F?)?41_w+Cm&T9=YsIJwK~nKIsIFZNf{5-V~0mdUl;= zpV_(us!m6GDSDh;K@oKN1nJ2MLHDb#k5)Co(8&IlE$}90MI*71*mn=OyqJ0w&5L3TPv}Q_o*(x5CIek0ie=vd|YF#VH;m z21uH*fJTZ_Gg88cyxI`fmg)b>Tz2sX`*|`_u$enDDqIBJAtbIHLc0IR5c9aSpAO#X z*v_wTPw||WIDnpjPWx1~KtAe53&rN^Uoq)gS9)A2>Q_n9((OCMNDqS6YSwoqR$UbT zW=e|x0B2<-G5Sj)5UA)MC^6tH;KeazI`4&xt#D@EGkHKH+RC^ta}3l?=v0X&B#E@> zGU|r#$52UoYO_#+Sn0-8c>yv6Pk)VygdDsACq2Gx$3+#j`_=1-+my-orD^w8rVWnJ zoqhe~Q{8tds&xe{~$d7f;IGS^nh zO!C_ABigMkhB9B39)n?MH(lCqSS23#dIW5yg{qx95%n4N&EuYpptVxj2HIP-BHfLN z(yaII??W@b_P*1nHm2pg)B>5Jjc8;2-)!e<+yQL;ker`Ms|gEfbFw_gMuUvYT2e}C zW4gLnI-3uy5Fl6t(5^dcYi5Kso@=}5jh>qTyvbF33VavclO+}}Jv2RlCs8&4uEsrH zUCcW)F>*KFo-r9Ik1aQPo^n}@Szp(k09#@*kHH@hwWOD=DSUfz6!DQg?CI`&bu&=n zfP^qEv}ZfxXLkTi7lBe3!H;AQXe<{tB`~1yJ~D(1nV0anRgE0;ey*Ic0j$_zcpGuzFbT@O|-ba z40JVyfZ_DMJWgnTp;H6&bO2cZ1nl1CP*x{6+f1pz5XdLZ2Gg!xda6++_1}Ijk9#*0 zRr86{a`o)_>2BnAxC8TIx>w!;At5z`HlJ_zXKwQfQmCu1FQS=jZ)xX=U2mQF5Vf7% zUVjR=7C-9$J_RTE6sO;+B#HPv`STZ<>VNXV1`HEz)8L1s zAPZ##Af!*9KJ5m=--i@J4S=KuwQ0uwXdoyB=j3Z}pj>%HFes**?QX%~94}CL_iI74 z%zjU(kx?zL0f3W!*J$a@_D#!g|9%jC34(rZuKV^t>HC1QV)73#T!Z=!&^pKnb6jTa znqPHtR*kyM?=i^O?7KiR4)@X}NtLTX#L}NXpdbT&Xjnk&Tfs7bH}ZI1FhK&6ZXXh2 zRH}7#0$M41WnzCa{{1HRX?N!1eD(z3#K4Im;!^SQmkr}<06YbL`Fi)GXErKej)=Jz z_SEzR%e{ByE6}X81lm1TR@PxNS=zuEkOTH7JDefGayrqbTdEs~Z1`RGP$5y+CvH1k zaQIk)G$9#TN>a*w2ndu1`n#_;dy4`221v9q@T;IKG<;RD_sa*IP+RZ1V>|MFsA6N- zSVsn3fnFtText#9gAL+wTc;d60APPCwkl*k{$=(Pr`7599Jna#&Qr?gMW9yEsrAUd zte;(JRwzMl5^5T%%u2ce5np3PT4axLAH!gjVVRXqtxU(;bMM9nbo?m=q}&~k#`;wY zH8o`DL3^<)SP!;HLqkI}9Fo+JAEl;=?$)@TE*TG{q`WK;9&{I-k;d-|uw20wVM-Pj z7H00fo>4}oHayDNI+uKPU`4YRSXYt#kXf2QF2#}LMLh_sYtVTx&QL3Z*XIzlm4P~|?d{EwG2nibR z!va4{8s5qMPVBGGt23BW>segqW)#m#&Bq!h5jQ9Usk|@I;%dkpz$Ytjv@BI8<+4sr zNU2;Hya(j$LqkJgPLvaVc>UGt^|)?>6YI<5#6nFm3o=vXBE|FR;^u3EIUKyi^*PnM z(MbQG*la)@76{gX)zwwZ%nz}#WoIpOEr^!=efuD3*2R2`XK~$zr9bDxtCMBsrym$; zXIm0t$n>f)C6&b63omvJJ+VxvGsflR<@Ki%a6dFYYnokY>zU3w61~3P|A|*7YZNRH zT@r=co+gcqCsLcc-t|xNU#IhWO4yA6(x6P89QtgPQ= zQk^d333|M$stvHCfm;(wi4L@yTik_bKzaJgLkQ$P9 zV37y}noNRS$M<;gb*0tlDnV*_+!2@~1kyp1)>Z0GNFJK`S1W(Ku(fteb?o_T< zZml}lq~NSYr;*oLq@0#t74r*t$*|BgPC9=6l>Nw;?J(To_$&~nF{#Bw6gP&1XCsYt+{jle)UC1q5}qGEY4{Ke{c58#W3Fda9Q58`XOg2^Dr-Hu%6M?o z@NO+ix7gLy73aZ&xM3^tv5890ae!>2Q-R0BhYz9s>w>+)t#DE<^BRk#XYRSS*1Zz} z_aDyHdgeH0_oVvEc*klMgvl-@nsM6KITf1JO?xsb)v-bZ_spjL_J<4QV0;fKM2PmiZ)LU|_`H zz=LxYvLqIDM#E-QzK8`;k3AAoVNmP#eI#JEBL$ABvwG&!6r{jn^Te>nj|BdV#r1XlMi#{ViiI=dFO7o(u+qsRV#Uk6kiU>C@0Ft)awoTINw zVW#hQd=8&mBfpIQMLqKDAG_YJo#6B++NCW z1nw!qAtn>lzLZ*D8Gleky|Oll4n)fLS%DAm3EkOI^bwE&ZZEZJlQ_a2tFw#tUiA@{ z9S7-CDTdsH|I8X!_=%-gD+y=E*$tKJvV2iX=u}v3lqp4|cNbhYBq^2sn=LPaThC9_ zfB#X<_KX8C3_<)B|CP%(82>XAfX4CP1#WoSliUGZ`4D&-_>H@Q!EhjX!pDg|UQr9% zh5|h4kXpdZ0^bl}L=t7f0>gdsm=)@>ZWUt<0C`i;OP~d|9!E4$3 zdGy(wL?4JLdJW_skUqS7`{~%gg3_S6RWm`aV|Hgt0l)EYkW6-*-|4=Uz}>I>&lz#P zM`v^>*8T4@fhNI3+tPY7Cnh1G(qReU_UfCXK;mLMS(a^l5gJDe3ZSb^Um!9ty8&U9 z07+{)?R2_0-T>?N@6|&Ab8E}HPr=^vHwZ+`bc2+*cZbW}ip3o}VPqgmr2BYMxbNn4 z+AjQQSf<;0%a=0ZMlge2`5MdZZktlL?ZB%YkNY=n1&8($j}>k>3sBE3$-A zO7#0Ur7~cl&!pqy;{i5FG&H zw6um1Cg+Oby3G#WvTe!DL|2@Ev9($S){IWDrFdY0k_s3YwFE)jtLLa;Y1bq;S`td; zv)LSvYeoae&&DK3} z=G&Be#2=f3m@w|5dAH`l%Ll~Fs0cvf1FLEc=um*JquFc2u{0BBTe!sNGOF$UL!hBv z0lFhlLtFf=kQz3X16@p`Z9gBR4&wOsbQ>`S#)$&nW2Im0C_|Dm@?<>b`f=anNVzSp zdW)O8)P@y*UmWk01I@T*r4^8WbV4i^KfVG_0#Zx#k&l4u>I@(pK^~ATSIY43;fu4q z`L7mnXsp<$JCn5YO$JNB$;rv9aw*)FBj1fx=F$FFGQ(!9`mEZ+2!Y-zb4&b)!3U6_ z;7{B`lrD7u_}B>SV!XAyK*1TUwqLe5o$p#4vL6D(QYTZRRyy_0;P9+)8`U|XIh}eZ zZ*V=pD@g|(f}b^B9;e?PU4hom4va(3!CioNoE#rk^t>LAw8fnks|YDK9RyIeJouo( zK3+kXgb%m*SvIp2oHs|^bK3alL0)TGy{p*Emyu{oz`L6xmmz_^G2WaJp4FR2n9o+u zb{`A=d4Uk+{=;Q=AE2j_2mrx`zE}^j&=AMRPND>m{=#QJe2|&TVju?cZ@}Rnw?5Y> zC@9r7lP*`w2SV2usRBNVxvEicA;VUR2Mj7jPDf*MV3VBcx?5!rEfXC+Vv~u&Tz>AD z&t>vLPCHZ1AlM1|kdWrQy6b^;9o46l^=+!iRIM*?0S^zo*tPXP{eW;=fg8bJWx zj)Hy+WZ(gD{(UHF&9Tf;A_6}2*$0I}kD^uxs~19KWj$$Q0gV?hoSvpl=M1DCo*W1| zTm??*bCE_)FID9$GrWG?`5=k;@5MQ&vq##71Gw1kW^uzOHlHwVXDM=TuqptGJ(7g~ zo2qi5`@2<}`6@wL#@87+gT4JnXGcjU9DLZF4$wZ&IqTpdz_-uyMs(F27qnt&tXSGp zs_oFw&@`DRq9+}Ohjn`RK^zP z_fCfyz*FD`%xKRp*Y~_nAbvGOt&UCwB&3fYXRj-`+p6E30UDy9pa29A6=*fvZdDaN z*Q`L_$N6Ph8J@%>*TP0Aygt!T2g;;AE*Nt4gY&(AONnR}C*Fbbl?G?Y5AB^#S)YkR_<^UIlWLqSnC zD>-L$8L&venBfb~Tn9)n?mdU$L^;PV&p%bFgIFY>O9mt8uftq4w6MM1R}!IHtd~!)%XNTN2qZT_ z-!&`qUX@s@HzPr@6tonAF3Q=;guO~RquuoolE|7XpWRdqJv}Q1GyrPrmCb~@A?FO$ zj{q|7>+ACvI)U^-yWn2yUbc(%f*7c-1<&5sf+^2wIr`zbHBet%`lQIMuJk62e^&?) z?PG8F3`l#+N_Sp&=q+eHE2Xb@s^@zoyc`|N%yH$ODfPq=K;}~g7NBmE&)}0IBe~oB zbo>8RAct|`B_1c1u4-ot3Hj z6FT3H1E{nbo!%FT6Vj)i_vAit9bC1SOGJ{s3`K7X48-*g3upe1M{!mY_M~_O71GfI)wu7kGim2AjbsJf+W`)=99TvxrzfH+1J3C z$#Z2U;d9?{jLP8*N0_08bd#^fym?)sxvej;;df?=i^K#Tu#crknmxLr&nE@nFYct8~>CN}2 zaOpKTm1@^ILLk5~5by$X&A!55p|XE#-_7TB(VbIvu}pXc96HgD`Fkk80TKn2#K1mR zCJS0W6lCNdZEc0Fqq$0E;4pGp`LvPE3RSD=xmKUGqBPJfsFvD&^J*(QM;XVbm9+*u zj)1yOzG{GSwYTfK312wd94C_2wZMEAgRu zUlalI(qK3wN;p?Xh4s7ucx!!->=Kf13ZX|^zzh84Z)t0p*p;Y|6A#~ zM0jJlp!dILKR4>ReVuPO*^oNpdA5fuOM!N`HrJV4fy|!uull*{fvD&(5k#2I)4_eT zCxbmD1s@v_RA+k&gc4-wTeK=ph^&H-%eR)_#UI`~gfHb>p$3}pgyNEHw%qknpwf)X zaZ`GN3P}XuuDqr~yYrxXVXINn8pc3KSRs@#A?jT5=nxWy%z0hvgk+DJgTW#-QTWJx z;-Sw$t{Mr9^sfxU)tPc-qzP|sM}EpHXaQCw(<;2@9hTZMj&b-E;?W=VpF~1*XayGu zMm$@8(K{Whc*{dfaAn}g=;*M=2j`=7aM?wTIenIpSoQA-3ZegCVKMi2iKW&!78Rry zsPm@VvMvIhz4cPmf#3Hy?mqt`r-9_dLs;EmDp*2pFid2Pl$3PE@92tHU+K!b690de z;`m$de?PptmWQ{tB*Wk?vnl;Z`SijD42<~k%!qI+)4UJ#gS)l3R>V#-t?)VK|p(o4IbXE$kcAk zMo3@XlHaG#g6{vJIFxm++-?vAd>*@d#PRCs!cg-?a$f$sgKIY$8&n?L@24$$$%O;=$?JU=NR^>WL8klYXHg98M%#*6g8aSwyKf)k-GBd-QhTAdacW!Ld~?Cb%xnjQrhwYE94+EpEoW7A_7PsZsh^!I1kh)K zrOJ!+`oGh5&1pO?hCL(nC}`MSy}enHOYQ%=$!r3?12qMjX$F0!M<8uuSqW5i_dVYq ztqtJ71@v3@9sr1Ozjv_tYfcV3779c{LIT3EAOzT6z%mN_=0+e}7w8GbW)2;X0B$@A z?j8UDv%h|IJ9pc7cd|28y)~12#2wdk7rpVhH9)mcn^5Bko>7D2Xb*rpZ?BdH)rz%& z0aC7Cle3L6xcO*+AG8;G4Q{2XIh-kd05=3(CDE%=wLx87A6*LHzok@zzw+erRZ9yy zB1n#wyYZRrigg7&BT3j-j}9`pttZ~*3=egP-pvEw_W*{&C;)qyfZH!1Ur01~D)oue zQ?)noxmtndP?hsE;Mbv+J6Qep?EFxjqqj_85C!oj2h31V&jO`xRjm!6y$V%*&t_fA z4$%2!lWlL68WJP1WRjcuFN;O+0qG*$jN!5 z-Z?wpgFvMM@~d&h#1#ru%Exl!av=T7fgOhI&3ck~hkFNc&xsziu@n^*0sm@+Ndv+E zvx%5!OW0Y)brTQ}IBid`2EwSs^M{Z{u4ey&PU$L^AXPK#1uwA-dJJem|3s#6do_9& zeu6_q^EJDRy9R=h1&_hR!GWCiLtTQP5YXZl$7pc-Oe|U zfa8i4ngOi%^l(b~WVc9BFkM)MMg#SK??X4A?M1zuIC`f8K=i6Y!9N}Wb9rO;!V%K4 z)IBm^!k*Ug)F%g0M`;$>7MX@mdVIR#(a0KwAfz8uMaH&On!d~5V?L661Wb;jtLxr) zPDZQ#hj5k$t7Xc;U>T*0=k7ToujxtG{=I2KGVOTXaZ<)U0_qDUA{i-_oKegEjz7|+ zua1b;1~T{^|AttXNN0}Zy~+p0Rfd3rVwIEY_Jl&Qtzhk2MNMZ8Qta0A4Ps{90(_Ou z*;$Z3dkrcx>1;d*&=o$5zk>kyhzxb8<2_9@0j9x8<8S@`ckki$MQ=?+X)Z}(t^1N` z+BzRrFIbBVD6q&t@-iR*!GKq;f3pKL11m3kk{H$AoEmeb^sBnA;0RyY|4_q^$`B9& zvW0~OeO^{3ChOmUQUPc>4L6f?Xyq6YlFQ4g5lw@fygfqwe0-P zwHHt=8#x)E4dw>v!=eFboR%}|piliOq|N;Bzixy(E2392PC~BAZr)ahQyH8z1HGjq z^u4`4oAdU3C1pKV;SScMYp-kQvuE_K+$YYMr+~@T1BnwO70RGroyK|%dOaXs8D&&U zOHBo-J0{(r)d%R#1yCH0M#Z-0Dd(4g0Gb5pdk|I|lTHH%4Gk)Eb$!ikI|G2%kDzE% z{r=YA@^t6GbqQb+HhcOR@yRsv{MHjCtIt2_)q1se59NY#8e&z8F0Wy0uC?`F;JkQqJb~@Mq%(jP^@Q5`9E~;?M=r22R~)*vpNFp-ktx(PhV^~2^*yZqJ|zIkYEt< z2Z#sC{Y(p3)UKRcQxYq;ufEE`F!AQ!w;Fc@`^};dHWeNf96{g(&Yj&WzM>+s!JB_W za@9=v^2VJ+Ox%+F`gMZC$2J2+x>ux_E7{ma$Up&5n4#nD6^8V|x{q?wWqHnngzoJt z<=}gi@L?obOHfg~wT_k(6UJip3n`_O&NQ!5d5tcPj1Zybn%6%+-ie{-dHyOG3HLU- zYvTK_@h3)?Ug8Rru_AiZcX22^`I*Z0;JAuLRYu4j`r1N(hq;RNMZfC9eVENR_1h!1 zGS)5#9m0gZwCK}7j}Z3|%0C>~L@prGGAVZ%Z@K4gFnQdbH5q%OSkzfwAR7al~mV%H0(3~!#?@Ae&4a}L2^i@#s~BV{!j~YKr3ns zn|=)B08xja!y$a6(~MYFeEl1}&6h3W#w0&r7~!!rVdAlUsOm)GNRqf86%XCDj8S8r zCO3)Ps+dHiU)Z2QS*;<5X7`bRgb5d^3|o@Pkkz-|0O0HZau-1$p@#rTQ^Ai+nyF;8 zplALe?U|}CW6G&rMK?-6JYZD4`q6B$NhZh%CkBT`6w)vf`=$67rq zsE^t--Yvl&c29joLJoYz6t1q33@wrf0r^sAWKK!=Ipo$$&(f=m_D46 zn)0Ct@(&0F;c!DtqAmhwxl&?#H2Ch33=5Yg(<7=|FK?JWR>+|6JxF`s3xQ(HXw?6{ zft3UmD;%9AwX9_}0-|aOplJ*(OJ?gWIcH`}BlAcJ&RtP5lzqhHQA~_>Kmnmt0v4vBtyC|6Ed?W;wf;;biZJNn*@0 zH%#gn`+}LlNDNHX^kG`Y=i~{7%}PB5p%@Ta9~29fLvT1M9`s(+&@Tppx4_k*7^Kt4 zp6?@@!)pTtI@KMcqZ{inZA7hLFJp{*B_jTpb}InUM(KbM*M~#MSZIDos>nZ(OA`!` zq!92HRQ1@5!L4|zkb4nJF1tMMZW?0OSitqffFYl3j$0`=zj!Z7y`J6sqnHK-6)v`Z zDr^@A7MyrA4_oAwT1f;tH98NnDJmA4yXAWn7;XtrFHyEo!jO27f0M-;Ae8b|at6|L z>uu#E--aaRBn5VZPMVkK6Q_*{E<%4XqX4JJRi*_ zVor##JEhU#X360n1sD=MzSuJ?!d27T93(1oKWWQT&Qn?&EYK~l)7JlxpTbC$Y&QAp zSIN6IW_+?93X8Te+ zP2`)kokd(-p&8@uCoSIz^7>Ml_#<_sJ)U*uiz^_DjaXt2vQsDO{LIiHVvs{?4#YwW z&iiv)@IQ*o*{kmJm$!DCN%v7=(5YIeS!B-N$R;BZ9ljLQXPw8Mw|5u)ASpPiwW$Ud2gmaAF_CfLs7Q?eA ztC#TR$0R>RBqZhz2_GCCdqk~Zv?6$jU2}|R<#*@Gr>T>14QW~!-mGkIH`wj@HKa0y zhJba5I|o#~`3Veu3vBT!brCip(Q7>{B5=x(UB%mZ<&O2B*t?b8A69}${v!l#9N`J8 z1hib)Yu^G4OmSv!inSXBx`ZcY`^j->aHSrq(;LQ!%8Hu@DVYr#{;aZ|n=z+))M{5G z#6*c42pJ-}Ht(ZQiu5TNTYDwodXTeWCiZr{;S9~ph!!@0&<#jbv&N{=ER>}~CDGwx zEQ9pQqzP~Ghc}erM#z+yVz#>JiiImQiXCOr*Y)-vO}?Xy1B#XS-2(L(IYbvo7lErE1|$E#XFc%opA&;qqKe>&>#jY*TR5LN&F~U# zh3Xa{SH9YF>*O^b+ZA~RDkxB2mgO0Q$TfO+53%MBkUBVi1dJNBw+C)C=^hR)-i|m= zmC^MkVM;MA%~PS8jKRjhpVRWv9V+z%)n=DpdQlg~K9;NP&6z;E8S{!D5{q0dZtkZZ z!#BN18)duQivVUHtJPn+h3|c?jV9L)zFz%uN_}L8Nf>%db*VNTWzdX9g3MI>Hl5Ge zvU^^}yU}}Qw!sfU7pjPXDn*$L3x&|AVQOkg-$^UQrMwzX+&{^-ru*qX36NfXDZPA@ z#}-(UNoT0Qh9QxlSU9#GFRcsg*~$z-iiL`nZk#zP(~Jq2m74jAxqb?OS&k)ChsLS1PloPw zKiiJp-)L3{37%2R&i_a~*Wb|d)sd9+KClx#T_p@ZOK&=m*XnrX+1?J2vpL7@?QOB% z_qsfuUjXX*sMA2ZFXiHusDGE54d3RE^xXDNGt9330T|2PHi%-&89j*bYl%qfr1=4f zxTtQX{jJxiy-+OYGR_w4?o%;$ntN;;M3Qp&m`3nf!SCU5`S$LYKjHWb@Q(PTkLfn{ z_9wsTNuZMC!x!^4WC@9?e@z0EWBjIP4iu&CWVu7jVa2+Yjt%+5ZQf)z#`AkbmwdRCavlBpsF zMAaHSIGN>{6=2;~h4QQ<`L`@+!AR~=iLdnORaWVndWuDZQ5N9AN{&rULM#6MgL-ww ztSK*FiVESQd8iCXP6v^)Q0pgS~A;vQNsJh9PtH zX8&W9nS<`>Tz~H>^ZDZOXy>Kt^P=@W;X+=r6L$-Fw)B{T{vG!FvQ0W!Hnha`zPr;V z-3`Hky0CPSs7hC}AglB|D;D-W9AS7tp)P3LLYu@UC;cHcAn(nsx5XN% zPg2#3#~eOymWVi$o@*wU{(ND(IJ{Q8uE|?1wK9g>;y-xbMCgsS&~;YxnwOAA4@GSY zWjIW+v3rEV*Ggsb0TjiY!R~g&&HcNa($@tSyx zeLa_jvWs6r<2dIkCIpW%+|CknlGK70N?yyy(kK|>h9mW20+IN#9Z4WMjQ2;w)Ek|0 z2{{UR3eghD;(DQ{Cd=LGR@RotaN$?~?&a%XeIV09_giRjyo`QCgXeH|{F^QTNM`RL zetlRdHygzC57I}Y3U<#e3%k}CJSu)c-L~4yXxHWU02leOkb-xeYs_H%seAJk@wM>B zI=7pivsElBY)AuVz;4Q&`nlRZ2Brm2>o?*dL2Zr#dY{d|rV6H1Ylq1X@z%cPw$$dG zpyj>!oz5;La#&R~yFF4_+Z;}6Kaeh`^`bq;JZ)x+>+U%@#wy1fQe<4V?(v_p-<_I2 zn$F7<(0oDaQmEy*s7sw+k*`Sm&E1I*lC1MS>1eCyA@n-iow=kL{6qF=vPe!RKB3Hg zSO}`Ix9@B}EK+%iQl^OKvNw6Tpb-3H;3-?3L1P}(y|k?eY%8vrH_|JWMU_U=V-K7K z%RJ&l1AkhXJxr@rFE&+4WH9P!Hv2l&HoWBAxFZm)s1&s=;FiouX3`#ofvQ%BziM$i z9l?rk%4|DprkpY6%=IF<^pAn%3MnQU<<3CA)+t7l_jJUgDd(BKr;QR3cEmc}T*FUN z)|$D!6pedtgiq|;w~oh{n{SueK8zjRzpUEXFY3y<3~(<>64#f%(fI zuN;{k$#d^o?y3q5q(mlD$V8O?+O047ytz=l)ONhjpm6D|V0R?Hb5wa??oC2m9R83& zSMXEe_fza+k2$-guKr%zzT+mZF0bZZS!NmVJL1|wuRHAAeoibxJ@0i@YB%xaY^yBe zcwNA3i8a5^HJ{sOq9V`cc^TfIt7p#eE;|N*M*(p4@CH}wj69!$#%JbimbdrRO|78M zY^FKG@DY#eC`Hy>ZG(^KmV@wLx4IltGLm;ixLHHO+gD#PZXB<0pc0R{>L^_#b`RyP z5k8mOAlf-Xl#{dFRajCnvCVCnr%kGhnPg{_@8d?xJu^G6-CTBXbNCRw!Et6~>p zCVC8n4vcHf9Xlj|%m6ASOFko6_iuiev8B1AnkNC_^_pCk69QZrs?Uvlr+x1SzGhry z#{AA{f09`{TL;davh^0!s}~3$fp~)OSa>||pR5x-fC@d23l+aIKDWJo$5j@6;kn`u za7Z6kquq(Q{_W=<9rAtMJ}g~zmi0Gkaz*Y4=(o?at4I+O+3>Vk#-rCrJs6k$`&B+8 z`kB|2Ph9-#YBrLb0gB_dj&I8~QqV@*Vg{^^&GZVj1#`U1Cmz3);0nQ{ob-Uy8`g_y zU2d$1UTlmOZS4>Go?EIDSBedlcysHyrs=sEC#|yflnJ6nN=H60QtB0|a4aw)LZRRP z@)T8l(hM{_Fsm|2dBx$>)U<7mI?|Y!R=-xb!Go$0b%GK~!yyll9wePzW_mIOgwy`7 zK0tssi2r~@MxqT%sS`ny?uqYOI z#nQNOACmU&Xq-^H?Q^!JA7YS@*!sdxeQj3ENT!?JMpI~F%t^&HLTBydT1y-!t}}V* zQGssDKGp+MH8hSDJ~%SS@#){@imW!ve9)VxIKzgdie98+l6qFjVXlc?5=r};#YPWuTk5+EZiBakjB$yZ_kG>Xo-H9yT3r9}~ zcZ7EDx2b(o*)NXI@=;lSxz*=CNY)++Ue)|m-}R;K%P>+tBd^^wBQ5RLJcTpDHx2s@ z;R1fy67I^}Cu1cj)(r0auuAWje8d=IW`Bb_KJHzhT#MAeBHA^M* zn4<@%wDmm%y}T+5`g3i}V6$xAK`D}s1k81!tOnKmSdXVcs^Eh!)ASwHWA7SBfFIa9 zQPpg3Nlkh8xh<3eDE1%?dtGu2gDZ>Bw%-(y$TuddK9QX{-*n#=b+rXwgL*Nh#4ZC1^$(pc7;osl5PuWfzU z%%;Ma0_wUuiKFuw;Hb>APr0+il;qA8d#E|Gjitj)lbgb)vs;CO z#HbW#Sw6q-nvIQmkG$OIDTzxr7$^32-u5`(PWnq2h!(xvIk-S4$@)9Z6092w`+5N{ zzObV%d~#`@C?PK1i)(@c;85d6(u6?}aAk0-u}$cP;Be`~B=)`xzgLKCoFYDp9tK{c zvzUM=5YiZ#uy}`q*I`?jrB~uB7r%APs^Py@tKGFukh}L=wiyu=5?<0{gp36Rx;u@r zP|Kx%KwRNknn$mp;RpAL(_Ng-_nnRxORAC4w=xusC@XZhaej5W{qqS zX(U~~+d2#>wOn8y=_BbPB??}Xp$4a2D^2k1Z5W(=aruW;Yd+I!Mkuv$U~#&c@KR!r zJzyS!{6WX){tYCULumaWvfw7KG1WRzD&!SfMe!D((4;FsDG^%&m$P`jECB%FLh13^ zH*r2BmInQQrxR(vq+l)9T4MngKdjNo`Ku0F3~x^6?X9(&q2vRuf;pJ;Ea11Jqm1$f zib-`3T9&aWg$LQuM|OfJIJ!pB`pMp;zb;I!tbdK{-!(vN4%!UaLg7MX;wZ;lvzJ2X zSgO$t>ro1W>^5!}i#|kKlK?{CYb3OS zE-^}&={(v5P_d6<-PLT?`syL-yJJ)Hs+9oPDEMTrJ;EwxrGl52O@hR>IuiL7{P0EB z$5F7l>KK&gbYh9yL)?UTU+7C z2|zS%fl8HXoxQwHbHHvrBWn5w!SaA(y*kPFlC-MbQuhqzmW%gTM7@Rmm2+54=$uk; z-5;bn3BN+%>B9)B#Ul_pKj`3tolI&8>V9H*WPY+B=ko*Cq7mXO(&&)1O5-`FoYm4puNDfrrHv;zUvRgY1n0 z-|h}|D!inYT648m#PXZkSMlVpk@qn|KHc5Ko;;1KF`5?}eE-AzMYDw5BR(tJdS)CP zswa6?ZV>+X%&@P8krBuzD$7}eiouBo=e9@Mw2ZBv((i@}n9knbysZ3sIZ5-$(c{MY zx4tMfGdvRwu$Yk~sn$fDJ_oD>z)IlFL$O2nIKGV}8xn{Kfi3#j5$$8peKPWFL>R>O zJouf)ZMYC4%go#y?DD0H1+~-4X$3g&a0K1$r_qmPa@$WhfLaS6J~{bvJB*FZp!v^F z`LxxY7eruJDen+$)Q5&+v_GDYv@W$KYA!VU*cZ^pfWkOl|63OUOK@>oU2aasZO8t6 z@ejPSaN7W(_tvmX5zFCZC&QMjqlt^IP$ZxV%pZf}KhO$W1{TD?&KQWCodzLf^f6f= z0Nnw$A_CU$otIa@{)yd8X$&b3lfc_MkZT8SPMd*B!ocS{>yij#<<!r^L0jomU=_CJGfDa+BBXEJUY&c++MbCrz zU!-DcN$iuX?&S5A&r5A%W22np!)as2!f*Mcom0%(9xNoUprFI*0;Kxq`O}^u%`qVqzJWrCDE_sxb+d<1KwX!JKGh>SXWvPkMQ1D8Ql8~HRrhMhu2lMtWPFQ_flA& zijw~AC}O&>T7B->*x0c0=XLovj}$}3V;-*-+Bm`xTfX?ITdf{y!bz;7M$21wR2GJ2 z&OeehMD(vVK$m2+CMpc+X5)0Z#s7}FNbMXQ3?TKKdtqY6n3;iLg>wbO6g@mcA;B{L zblOPjF6SE2pM$}QN84)V>Wjk>cbr?EBLLE12z#gmT%;^{KOqFqMCYrH6gGIG)sRCV z@?mTF&nuSi(2Nvi;Kb1rt8V+bIdpy;{Wb_NQc}|DPwF8fx;nnfSW{^-PTOhUrdbyF z>+X@373cing8=V8e;6i(m7_3HCk_xoM|sp;I_K~G(pj#6kBe(CK4-gfi_-=TNHR^d zre;Ba50;m@(u=&oS{e_Ik6&|ZAHV32+Y>oD)TkX}=$_!KG5RwmiKf)M3+a3+7D%=t>b+%>wtJXHjw4L`&nM4oCDtX%Wc!D zaMjV$d`tF6I2G-3T;GR3)rv()kk=18&qk7>kLFJtYbm(>RwFM^Fr{(idHvk}T%XGi zPCQ#dq(CWeIjCWI9OxEnf4&D1i35S6v-3ku_6-#u>n33^_8K>)61iN-H$ST4dK7@`ExbD5$iM|@S#OPVowhlt6=?izW$O18s{&v zeduaF;N$JRcjXK4`)=)ly-Iq8^tGLxdN6AfiAVp;zKay5;-z#ARt}Tz>G88dKu{l?T4%V>s!}?<`NB@}l4#(_9mz!B< z+42`UpFQo1h2M8c+JcwlS5KG9&5+J-?QKwHefIsVw;YP~jj67P2tR^AeGZg3X(;)g zzi+h6^UH;FHGo%6}zy96e;ZiOs`y`v;$9xWao++ILBfm*fsF>LLY#HkPaaS)VWGx^pFbZ#E9cB>qi`Txz%gL4#-3OdVGOS8Q@|T-fg3%R zh$14qGZ;&isArb2qGt*P$O! z<+vz_Q=VV)bEzfpNXabE=WuwQ)y&GHp#9!Sf6+kFPJBIG9lUFEb*okr**u z;n`9yRKK&mz3=fwUizA9NzCjvLMca3R~-~&vp$rFUP-%aE*SPEo#^(OZT4SA1 zi8^@ij(^z{llUz0ef#}3sajO*KB2dIhl+*h?7s&(zYb=c-)L{bEg_xuC##DC{$zO! z?17LjQt9V17*Q71(9bi>&&=1kgX3Jb9@2BzZ?1w}#XLxaS-IwZxVyM|j&>~kSRCNf zzw|vji|lHWQdacgB|Ht(lcFcg2`U=?A4l1MK;nMy-S)B3+Vo324 zDKG3~#hgC@#E){MrPc7kgj5PGlbf~EWdQ81&+RHp_8Muz(Oj7st7Q1BkH28LPb zLtn(q)b%Zifl!-u$ghYVK z!2Nr$nRvk0X#4i`&qWff=S26b44wosCw%7WH4Lm~YlE zuPWvFJ*?x&klimkZ;FweQv%7+wnDk@cD25ZWwr7p%WWR(sCa8VSgyB@A+hawj0ey^ zCd+2W=5!3%ixj=f&{XuZ9?x%!usj}VSPJxBycCc>E!^Th5G;emt18lnKum_gU_`~j z_WJ(4Z>VwG4@-j@T)~`ikVwZXT`+ljcLxbp`_8>Zy5ZFe0bm!Nb~6c;VBVb*y3+t(k*HCiXy8JKt#pc-=9?cOOSNY=7Yz*~FTS9QYvGeg9<3a5 zd|q7Mky+sy{!ED$^ErdP=V!=gjVsYlYMZYd%)@5kd6QC7T3j6n?a}C>T%KDhkzjfT59#)`^XiEMi1EY7$h2H(+?FFE?HrH3%o`1J8 z99AK}-CX`$wpgN*Z~b8`@7X|)g@dK=xRKcYPNnkZ4_qZi{g@xkVryCu=kuZfFQ4?& zL{*yq7S6;5R7?+lq*iZ}RgCZCyppmI6BV7wBaRa-pK%y<5>()Q+-CZ2`n^x1?#LcQ z9(8wjFZ{OK+}f~UUfbKUxhlCizeGL5D4zSaqHe{hV)KEq)WT8yefN8v_CLoXJw1}K zxZB&?KQ*?4DmCp=;yU7vcnHbKj}8t{0mRTZPM-|M1~YL|sM)*dyJ%bR!^6VPhN;nR zv&nOEcW+*JTim|$30hoJ$qZA)n?XjM7qoS;e~1TFcELl7J?;E*D9ng~uXKcXT&Y#k z-0il;Cq#*FaX`_-y%JGcHFBX0M~p(a0Sd7IWz+`{<{E}A&rUCnZT8uucW;_hqLWRB zFwpbGE^Alvj_NY~Z9$zni+@iKG*YMg>lmVsppc=9c$Gg3>IOJ6W7aI$I^M(pz+m9m z2Ut99q^0gx4oEj=nO*@VDsneMsYVHyjg=jWBR3?+dHuEeNau8K&xWUthMKyUwKX+xPjDdf*Fefj#wrj;9Q!qrEY!Me*>{osAVyhD z&4CmnzxkF9iWJO#N5;^4_jg)Kjj4{5tvn)uHZuQ%jtRRCpo92>4+rTXh>w>?5_yCR zGnO@;jYh7sitd1AXgP@bxudr*^+v0ZZ2}|#6;Km0zV;z<3 zvo=_dpJw<4TEAG*nKjB@>rYB_NuYkouR{K$4R-zI64lhz>IBPW9_k-lazuizXOF#m z;Q;oq6Wa5S1*pV7f>?O#q-f=;NDaW?9&oXeJdyjp%4!uTqgIa35;9>kZNr^GGS3osbVTkGn^5&*?r@Br>vdJ+J|c4b$Dfn7pguVg zyI{hMdu#Y$)yNw5X54~fdus>#J@7fS058EsNr@NkkF6)_Pfigo3W%A{?0gs9yC;#NfV(CfkUM1K=Hb?#pPrNj4}46S z93K~@p)vfW_6z@DbkqYd5$K;-iL`9G9Q6>2NySdg$)Y(mwk@hvXPiNfn6MZenQ|w$ zcRuZ`&6aY>HFD<6Tzk--FRl^Q&Adb9mlYWZS{NepgecFW%~adn!8(bbCcYZa+xjZ)KpxvOg3kl1*VjhnKQ z*0SWl-wCD7)kMxevkP26AA##G`|zXaPP#VxeKHHWsnK{xW&#h-G4jjqJM+Yj3{n~h zA|TTRB5-OvCO~!%VMjlz0RP{`{Uf|2+?O2K2)L4~N}rnIvYmPhhgL(62!s*$R$cm? zoj+yyAMRZB7HTnjLgUEOFE)ig@ikPPZ$mLjOQx83yqc33Vg;HT(elAem&Mhfq2H%| zZkyh>_);~13yXa6M+$%=<10(48YA)78G3a}*jej)NHETZ)R6z~c-u5X92vKb3Af%f zQ>^K4tJ=>IQr|UP$wRR}9rfbG=;=49(G^Uby-;Rlnx@d3pM=RJT_T3&j8~ZUq=TdD zC|sE9hwmz&wU0C2<#fFoZy?`(h8BI65uZ4|&jB0ZZ(We}Q!~c29S;ns{3Dmx=YXid z4j1xyT|kA2f}L=b9<5Tvg`7stgme3?H_reEG5}AV=yK9cmn#YWm+)nQIRrTHS2^61 zuK6n&J(OMM0rLnGh4u9C(2`gGzi(L3rR`nMG&020JLH|t%3iX$g^&iXbh%#z!NDmU z8Nr(>qeMK_&$Z>k-`+yq`*8nVp4T@t$SWuzAbt-K0iu=|t+la*rg(8geqtpUi_F_G zYhh$Plm$sYM*weI!%!rU-@Ny4efmlt;Ok58B3+WkrZP+wtMV@!g4){Y5FPJqid{p% zdPO37qx{U^t!KmA>k=V@7|<7s!QKf(AQ11o73~Kzoj%H9*Ylha36os43%?zn*Jbmz zxA(^KUDp%)P;O2{mE>&aIr(Y041cOn3A(v}&?B%aLCoQw{P8>WhvCt2!>Tpt=uw$! zj|_d0s8O4lrA^bHXL!VwcF)bfLwLV_DRbLNzXXOp-?~4~kj?c+fpXv5Y#+2KuBnI1 z6Kw%%v*rFPBrNh`&4Sr_L)Uy8aMGKW!X%Ua%AMr!k(=ahKK>DEky@aUdQfV>o##)2 zkUzu%COxao`>TcdoQ`aW7BG<`l>wKQ(MQQe_|T6<#i+-c+Gt@1Y=ENV#U z-bxpYJM9SObo#ooV-NL1Q(sA;`rF90cd(j9-Or24hgUJZYWVc>eJF|HRP6WZV1hYl zMI+_5vGLU-?WwZ0C5f9-V@|FlrZ6n>yD?(=^1e6Z<9E;rn%C<8D1-j=npwziD3MMQ zirJ5@TkUVFWOP!|_+ozAzFAN*DH{AT{*Eh2j&nZ-*#Cl!{4V$d!}nM0zX78N0WIRYsae3f`3xbLLCjQfsOP6DupfiU8Os9|fO8~+z^uA9*& z%kegt$aZeac{_*s@Gw)m;f>=jvi+sm^n zxS?-5`+NWFO-~XY?ozlH{GxvhckbCHiI^t`Mnwu%;CPV}X+<%i4E{2EiLuryxci?i z=x()N(|5BZ#0sKPoo6d+^^WNWf9*TNawl4p>wCArzBiwe?GgxZOQ4ZWBTQw{tGR9W zd;ZPG_i6e5%7`!;W!%$ub8Jq?V^4S|7jz3PJRN^pRq%hDXqEI?^{?Hz{iVKG|HQvO zF~IA*aIPL0xaf5Z-QMbDphZNujUjQb?C1%)I!JlBH{0HyV(5>fS_Kg(Q~LGf0dpej z-@BS^hk4?}W=@DI>Wqus{Q*`P^%n{Ie(jbcCWSZi(~2;2l#X327_ArW%U<>7K*hZs z^o2#a&BOYH6`MnMDbOg;g|^>q9bA7;v(hI=>SPm#+I8lm6*>)7ZMdJ3Wk1*Rb9_Ok?siL zxZQ3G8W9~mEm$XdBgjP0#8m&Im71G&bo&g=<@Tx3aS?3gDCNC#x#b7pZSx>uBGq;* zC)28W;Sv53zm$OWrjpXw&{~+QzXk*?;peZ#{8l3;5< z`-|yR>N_!VevhqdUdQW`<(WG9hUDHKAFb>9tk96p((pBBe;aeOFCa)k|Gh|YU0L#2 zXzq{$2@;Pt%>?G?nfmT{Pjl^Ce|3*7(7#4{t1tfUwut2T@O7xSH@JMY)Xl%V>DOIM zY$ZLl)j3#qx}xF-I-5^t(^6947#aBu*@Q#H1v@1&Z9fo}4zJPcXpkr{u`t=`bbKBg zFf!D{cyDXl6t|3)h(O)5g}7UiPg?lqvu^8n3wyr+pM+E|Z4bMK?nERwq;Wqv@*$fIa6j5|%}P7& zZn}u-3ok*P^oY*av1r=Rj;SPkk__52QP8fu;{+5EBU};d3bm6r?Q+sRq+cz%fBHCA z=KYdA%9Wt5xY4{^LDZs3=jB6m)favt&uRJsbB=g)tKT+n9#JxoC%YE)$ja?aMDa zZ%jvMFnu1_ElefY->QDpE>xHm_!2&QIN4M?njF@zj{7%;l;D z*A#+n9Gh3meqL86Q*6AvCov?o&*xj_pFe+Z9(rlnDI|2dzDllm*gRfpDwU2V^lF)# zv8z_ld?!^{aR{gr=q6ey&K+2NkP2+a)YOU|MukL1;7ecKpfR$(z5c|%6mF!e`^J#w zw;ZmzW~r@B_z+#chURv*ha`Nuv?{Ict49463(u&M!9=sYOrL*auo{-na)qYsk-8eC zz2I;fMs{O2RI}k@{7Rf~1`ZpZOF^BBTRKss;U#?EM=p;=F3PG=?yJt@tAyEYHy+0Y z3s8Bs@nJb0rtP1a_UZQ7^`^<-zOSn~(faYMPmT>Z%bcedW)p1oBJCeNu)A3=fO@7) z&9POvew=K&=qpm9h<3t$r^~X27<#mOs;;Bs*1V=s@WVn^D-u20PR!do$j3)|Gg(7A z)$3%QjFOa?EJ;N}?MKtHgv58cpF|N`Yu|!f;gOELP6vIzx7-|IVW3@KV4PiDu`)A{ z3At36h7LxY-TS$Hl9iDH_vu_=!XzCgS(Pa=iCgDUB^SFe26|fJ@WTy+_{-DtUvfPr zxXGIgflRF`TgYe1avwPr0mR+OlO;nfX}OOdU0X^Gm1x)p-^iyfwFZnIL~Z@hprX=u zb)An?A5bUz8T_`XNyxG0x%Kw%-r3pxE{y1d z!u7?CSkQXe^2woN!_J8iHV)3o=5b1k7+Z;{WXssV`l-6h&ZzQ093364_aeo^#dZGx z-NLbv)Z^sS`O=AzWry9=Ux({gXe%g@$W(&dve~jP%w6db7P{9rShN)>si}C3f7XM| z-m)^&^~9$mAX1N`1g?lC(xzyq!s9Zq$|a7K2=|138<-FnY|P(v}8;+|sn_Ya65=Hn@vGHj7h&~o5K`%Ij)G{c&dWimQ25S?IP zr0P_+=vZRsw)_VjJe4(^BGXHBSd6|ZjFsaI?pVHRWYYIcYAIoAJ8nnh!@5qyVR z>pPE;6sk}(LRaGdk~*?&xA0?V+>n}hH65(7l8*{;2QGQ1l{SwPo8Luo^zRUC##bhW ze`CabOPGZ~Y%s@D!5DAJ%;%Zp-cK81ORAzNmq@T&KC@Gx*J^>7wv(D(R>HZfFqfmC zW*NEPT*#;eIspHcm6&E)yssN9M4?`0mrEg#PQeIOm~yQCi?QtJa*^hIQ8zh=JIu@k z%VSeeh~PjspvhbKHv>8n>%8CMa`E$dh9*g zhi8908%E@MHKS9|m$yt%OUu{=tP8)Zd)6f>j7JV$Xqb&PSnM?~+Pd{ez>jX1A*TNb z;ZN!sW**@&tkt1);%q?I{ZyG>^UO@!VcbSJbf>Yh42Gp?54qVK`qy~w%_XeHL~>5rDb}l=q3%6f zYr*fsoq~r!)g#-(Fj&V&dCt-Ys^-TR67jDy3bY9Q0IZZC@Ff0c^h?N$u<*cNSU|f; zu@6aT5mwlYll2&0|Jii@p;Db@k$V<|ha=ODa_i^9CnA+)Cju=#9>aDjZLL5Q6QZ<; zii{v=M46VofjkkFi{WIHr(v~TOwjWEhEi4)zjXS#P*zDTR`~K8LS5_-vKckIsAwd#7W~fIL zG5cwQ|0=T1{KymXTlq)uN3-mYpMF@~5Wq+Ni$RW%U3D9?9Z{ zs%kAyENX*s3HSHKgUqf4R_o#OW68)zp#Z^`pMkmogaQA?YINDI$4P>U2V3P9t33M> z6Xut}`)?`=0`Lw1FUfncHpp0K<9Un-PQA3mEAz2oiJEw3Mzgs~S^&qXanh@_Sk&*E zeyJ4DzRp3@FLL%crF>M=qqn^aT{xHT>gxa!Q!+2vax|Dx|kfa zonK%K(*yuVnfASQkBOEz%&SLiJfr)s2OX`jJV2pLy^d{?}4t%3Q>6il^&7)*tP9_88QuZr~nCmtCv&YNm2m#aDJe z$>`$bJ#9J9x8Iz=5YM`>UTL!qzj%GFgafV-9lZz}1C3NXOM(t*0WCB?w*#Vle$<92 z*skz+@TedCp{J;DO<+4gahho3pKrtY?gPp>6Hf10L~8@&XyF|o>O|!wW6#|ahM%~j zA!kJ-hpbJg={qq7$TmZ@p#aO0-sMP#S>_I1*X@)xM3{Y7U-d&6S^g3e&uxCdYJ0m! zg9uB&N%u`+s9j5B$}^sEqu;hH*WB^nfW7x-i!K0CL*Ui5ko+};NVzYxzPbG7Wm$}R znh5YJdpSB3*$rQru)KSm7sAZGJjZfet{%ucIWkYC@Y_zYwWPN>ZBSOovKe8oqV!cA=ixo<@Pa0-rqlWr;_|SUQ9>2#9x9ZYj6XryW*I} z+l1`<8~iZc=Y<3X9RC(i#2ntiv44cM3q9nlDG6Yp^0u{{A9jB%Ff|zdHnF+Ti_~3q z?=X}dkn+a-lmy2DJ~+x<)@tnGb;WV;=jBA{i@39v!|aTi!IwH7<8lFmON)YUnInUl z+w#le4P7)L77hz{PuKpScd_UFF}k>BS3;9BY}xBJ%)-65sIJX^I>ILC>Th_ReEZ^3 z$=o-}cS#WP=aWq=Udjl2E)yFW8h`=QS^u)@K+6$&vqxxXJ$9czkEVoo5_n%8N#i>k zNJ^f?dzCUUd*f@extqn_&J~1f+9B2iI!Xj!?Hrpqg@(S1 zQJ8FZd(mhFz8VJSXB?Z8`I7C%Ee=Bm$HA>zSG%@@doB0%+@-LwyoR*_$CfB&gU>h< z@0zdM{lp8O%yw6KU(F#%29?m+^!u5F;={^v_LhJ z3D&V@6`q!ls(~8H48QICC@uyN-DaRxjx#a)i9yyEqLTIFCmlC3!k^Z~wZ}<2YTt{y zbsz-3&Gbr9DHcr0rHL(XvHr~@KW2ch@`d(Y{(Vf+3IsR%dR+jFO)@$eD5N+q_o9b{ zVV}S`b|3P({pzopl2l5ZhZEdu>&XW+$`RGJG5`$R473YBL}mVKAsmD$_!c&GB>N6b z)ulvAE29JC$}2+sh{BxPXw+^-f77OZ;spOG4wG@k0K$0eYTuj+<1{HdIhjJYkn4bT z)qkqry@1%A&{*vQ3xmC>zfqmPTci0dtsBbYKab<3MLj64@BE=Wox_heelmmgS>-;C zZei<~%~CSaWDZ5l=FXn%JByy{u}ytB?-{h9eNh``ka^E0huxPWDL}t zARz@^Tx|d+%)#z3uM7Z^j@X z5@eys#X_)kDyOW4*sv3H8)^PvItPjArgrCV96;|N5%zPHowlR7{*^t5!MdUEp`z{C zEh7v|Af3l0Gz>I4Aovai`=4^5c~Vnvj=aSZq7}ck%S_#Iwg&vxwk;2}$5FjL0O`&q z(V{R-7geP&F$1ovfgnoMwMr_3%6~=8>kojbf``IMyS9vk-ZzX58pjta<9$h5RNx2gQNV zcB8eP`03s6Zb=chc>@-&*)3%u3`Tb*P?_NEA(A`|JXOz$LrGtF;>RW2{QTH;Li;Dt zU36;ez@p#mz%$DJ!^g-$kqT+r3+D^i2O9zgre!>R7?BF)?Zbvz3{!OMwS5{gLdSz7B!R=)OuLiQ@z|7Fux-;E zkb|e{Sfiz88eW~`9;S>Jtx7Mx>{lqv#Q8=n&; zqLXTT(=cjtFv)}w%w&8jQ5H}tIw}Os#ZnmGPe%n-aPW*X^o+at_(flPLVCZ)-+*-+Z0=U?X zG%Mb1>%zA{!%N8HHJN|oMbG-1D^mytO#T%|0}kVDoh`XhUR?VQ@`k%Cel_D(AImCb zaZhT0=3z9QehPq)i>jgeg_umCTt3k*%(x1#7SML|fBCb+p=EV0H*rH+Bc27ltdkwHuuk>PTpti8RA; z6pQUe*e3;f$70L;%tFJ5iT24AEyD&?Oz{-~`+`9>7Yv7}iOo9-O>FSMw^;8jn84T* z)=T5g2aa!pPMDTswmVo$_PRRbZf7XuC;$XDlZYsG22r^oa1#(uni z5yvsq6I=1Ky73AAKEbwM%?t*f{ah)>1*Vlx_^&dE!ZDqS(woziX@l9b6qB*n!Qrv$QK+xKq0bkNz~u)}Zy zfE%vS7Q1VUyz?$GgnDhSKW@{^JRjsgo11MU3Oe&!;-{siXu^x@93IWR_{J4|dC8cg zzlp#qZc=c88|1FM^G|O1XfHs^fS}X*hz1x3H04LlKUm*f&Xz(x)Rd)UyW-8o2F$bY z@(TXmlGx?(^g+MpYW@W?q3NUp1;?y%;fj$v(_D~&0dwslGeh%i| z$Zp`bM^;`41FPW?i;Ud@5>(xuX*IGJx%p<@-%Ahl(t8QJNVw;SZX-;#U|F=9_4K!j zAh`u?yiqS~Cl@F3I$regy_h31aB#6|8L3bync1o8{xzXF&gDk+x87FvBq9GG3iq4j zY1aXauc#|#;rI99l3^yyNY|W!`k01kRvt*O37DYn2)BhhLy10I5p}(DzbWkP0}VoA zO!YHyve5x;j_8cc!icX6#$fQAzR#=1sjOLP#Q9nRhIInS-E5ym(AT0ICx}7W?_w_1 z>{X5QR4(P!h7j56-L(fE6eHd-Rq*BqtM$GQtL{5o@m%b(EU}wZzk~R+9j)UM4@fnJ z8sgH#xQif4a9MbGxE>rCf*y(qKyWO!FW36AbZ6X-w)BVgWov?DNPRA#rgSZ#QdDQ3 zDk&pl%g?0r z;QJt@6FgfkDC1{7&>wen&Q!YUxXk&$i&gJm=V>qXtlC34|4Z`TvQz_}dQ(5_scQT0 zb!+!vVV5US%H!|vn!Z*p7h(a|;}n4Zm z)mbb0o1pbtAy&siH@RXaT{zi58(?nkwDJe6wj^AQevYwLux~-GqbD|o$HAf1Ma0I@ zU;~itmwXPG*=BQxn2Flej}D1!tO2h|--mr4V<|cYKWz%#>&eY|iWc;yHV80|5}aQ= zXM}>Jvok2+T$aQ6uM3Hns(kO}QH9I|8%WQ7K#(dy)eX&Rl(>O`2ZzgNh_4PI5el zc@+JO20I zHB$h_DC#Jvi=p>uGxmeqdk?5XIt#3zw-!Z&>l z`*>w$|5jhlpAy`GHKw48J8d>Vpx_>0uf&Vdq<^cXsVkjf6;99VJjZV`wR>R|w3qQt z-uSs+UALgWz1_P2fq1uG#N{-pPxx}1j(PQEz`g9?u@Q;t`Bx$^s73NE@jU+!#O⪙*sx;2AB}$5$>If z%s+B{++LzI{UG?{3y()5XtWVtcI))&J*QL|$1Dr&kB6s{8~QgV@xJqJ>Y*YWZITL| zv6fSWLA7MS;1kSt6Bto24^X^|+jOaBD0=eD=e=D3z@0$1#*azdw2RB#+WArpB%2KF^54wEP8k z>rw`C8h-B5KET~yg;YBv0Zc4!;Z3xN0rPNpphl$coZMzUptvE7PCaiS zpah}wpCgr0#`(_9V{NUzJAUG$mR5P`OE zQLpw%u6nhg7q(Aw!5dU7pE`rRez^jq4Q+=W)k;!RdE*e4m*ID%85rMg#Ys)jV61f1 zwci}=h=XqlCEd_&bJ=#0d?9DUgTp5)Z!m(j-HI?6Mif8&>j}VvT>9CBTi;&iAr%69 zg1$8)-^$S_5!NX1pKr;c*%r?W>~{fgv*!+BGBA_a54_L15vjz(2@uVePEr;r&gB@XfOp^}R*E_bcF0&}$$6 zs7gW&xb*gKA}(ND(%AL#Kd@yvIX`O^q`H8fI-oT@&rTuY9P8f2A$kF`PP$Jmb>PxM z`1?$(Igj;5bvYGWu*S>ClckhK>u%l^9WZN|rEFmT(@#s;8Gj$GlX9{u02=%2pDExU zGPRsqOM2iBx$N-sHSR40mDy z%LwufaW;?rctr8E4HZB>ohULM>BoRrsY7;_Z`vbMe!R>4lLxu3Dqd;hgntKI1h}p< zQ47}HxC1IrTr!H~gmJtm9qEtVXlzTIb>7iIRxd(}Jm-8FGn$$wlRx|SkMq)n9S__$ z16Xo>3#NbQdu2(fKL_5xU^fV)+l?V3xDP?M#f#K)o| z>s&v^zw(IF_4|%Z`sb*Z&aQsYtsnTSQFf>C@iJpm&i0uapGE}s2{ISjtYKk;*y2&n z#1;DR&`YY-UzU;pJ9^PZ&U~BmM~Cz9X7fsA+5B7C<> zV>7J*v&Z`!JTsW;eD5H-0X1gtDPkst=))H*vo<_3_LrgKd3Oznm_Owj%6R{M--uOj z^l9y(X?0N3c)y86MT$qTrN8L8;U)-grhe~ndSq{Eiqc@|<)o>n<-0R2=Y(}IZQYy2 zW%WDa-wmxN0>b@)=C2Iho|C;Jx*ldm4Xvxaop~Df<_Eosm3lnFIV+o&T+xy&oXTRC z1vt`cQg(-Hp^N5*s0-TSylMIZPdgv!_5CCUp81Jiet8Yn<91Y3N56tJ_)7&nj#mm@ z9TdOx9`CewE&E-^lFc-s)u>gVnDBhD$AfH3vTK)tWy$s~iUCo5~E z7ectl;Y5LArNmeP#WtNK9YIC%r4y|EaTZ>H0&lId+4gp2U#IuL`=NyriwNtuE~F__>y_pJY=ESB*PY4 zXd7jh5V*)B(6N%F5ppI*@&97K^M4zqP697tfSDdDvxrjiTL65>Nh?WJyf+E?KM`H& A2><{9 literal 0 HcmV?d00001 diff --git a/docs/html/images/menu_design/MenuDiagram.png b/docs/html/images/menu_design/MenuDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..543328a5e8030acb7e1322605afcfcfb184d2440 GIT binary patch literal 155648 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

        - Google I/O Developer Conference 2009 -
        -

        Google I/O is a two-day developer event that will take place May 27-28 at Moscone Center, San Francisco. The agenda includes a number of great sessions on Android topics by team engineers and other developers.

        -

        Learn more »

        + Android Developer Challenge 2 +
        +

        The second Android Developer Challenge has begun! In this contest, + real-world users will help review and score applications and the overall winner will + take away $250,000. The deadline for submitting an application to the contest is August 31, 2009.

        +

        Learn more about ADC 2 »

        - +
         
        @@ -79,8 +79,8 @@ home=true

        7Z#chS{j0nOin(+_Yu8 zWm9rSZb`c~nJEpc&Q&WWw(WM>CC|VA-1TQHUsh`KK$~_QvQrvX%Ys$qm9sASJs~*DmS)X2@b4D-<@#AMi)lnVs<3HS20kCoLUQFb^KamXJC2)<8b-w6i8n&J1lu)S#Gy*`ibehr6$l8Jyn zhTN2)RV!ANR|iuwTC^!HPWDERZ-(nEsU;$fgH)>7E4A^WIiqbVbq@^`&O!W~GLMK?twk7aePkZH6P3*B{Vh<6--TRU5YM4rJtZ?%Kht?7D~@2*mol zRkNaW^`2TYBP*|MyJBB_#NDY`wq)hrkSb`?uDE5ESyxLQpI6^ECLalh9EJJ=+Ga3f zu|SgF9o)8MMoili2pCaNiM6hD<<83L0m!+Kzn` z%-_S73EP&5!Ft#t9(m-E#9jE`5ynMYR^bUJ4QtmjD{(gxa#Z&5r0k5rCk^S{sp!{! zCBC%eo`VJ*-@B6`5|8!p`a~jbnUI7eBq0eoiX{=ZOh`f!l8}TX>|8<;l8}TXBq0eq wmym=cBq0e&NW#t~Bq0e&NJ0|wpOgO|08-LVe`e(MhyVZp07*qoM6N<$f@eJ;SpWb4 literal 0 HcmV?d00001 diff --git a/docs/html/images/menu_design/TaskFlowDiagram.png b/docs/html/images/menu_design/TaskFlowDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..0157132b8d71183b3a25bcd86d88f242d3d76f08 GIT binary patch literal 32794 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 literal 0 HcmV?d00001 diff --git a/docs/html/images/menu_design/TextFieldContextMenuDiagram.png b/docs/html/images/menu_design/TextFieldContextMenuDiagram.png new file mode 100644 index 0000000000000000000000000000000000000000..b23a7da48c1cd8b36a642b1774f257160d72a305 GIT binary patch literal 33313 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 literal 0 HcmV?d00001 diff --git a/docs/html/index.jd b/docs/html/index.jd index 07d0abe7f6e46..c39e9a8d994f5 100644 --- a/docs/html/index.jd +++ b/docs/html/index.jd @@ -11,19 +11,19 @@ home=true

        Watch

        - -

        More Android videos »

        + +

        More Android videos »

        + + + + + + + + + + + + + + + + +
        入力応答
        zip(java.lang.String) + /work/device/out/linux-x86-debug/android/app/android_sdk.zip
        zip.endsWith(".zip")(boolean) true
        zip.endsWith(".jar")(boolean) false
        +

        デバッガではなくスクラップブック ページを使用しても、任意のコードを実行できます。Eclipse ドキュメントで「スクラップブック」を検索してください。

        + +

        DDMS の手動による実行

        + +

        ADT プラグインを使用するデバッグをおすすめしますが、手動で DDMS を実行し、ポート 8700 でデバッグするように Eclipse を設定することができます(注: 最初に必ず DDMS を起動してください)。

        + + diff --git a/docs/html/intl/ja/guide/developing/other-ide.jd b/docs/html/intl/ja/guide/developing/other-ide.jd new file mode 100644 index 0000000000000..2983da2752aff --- /dev/null +++ b/docs/html/intl/ja/guide/developing/other-ide.jd @@ -0,0 +1,271 @@ +page.title=その他の統合開発環境 +@jd:body + + + +

        Android アプリケーションの開発では、ADT プラグイン搭載の Eclipse を使用する開発方法が推奨されています。ADT プラグインは、編集、ビルド、デバッグ、.apk パッケージング、署名の機能を統合開発環境に直接統合して提供します。

        + +

        しかし Eclipse の代わりに IntelliJ のような別の総合開発環境や Emacs のような基本的なエディタを使用した開発も可能です。SDK には Android プロジェクトのセットアップ、ビルド、デバッグ、および配布用パッケージ作成に必要なすべてのツールが含まれています。このドキュメントでは、こうしたツールの使用方法について説明します。

        + + +

        主要なツール

        + +

        Eclipse 以外の統合開発環境やエディタで開発する際には、次の Android SDK ツールについて知っておく必要があります:

        + +
        +
        android
        +
        Android プロジェクトの作成/更新、AVD の作成/移動/削除のために使用します。
        +
        Android Emulator
        +
        Android のエミュレーション プラットフォームで Android アプリケーションを実行するために使用します。
        +
        Android Debug Bridge
        +
        エミュレータまたは接続先の端末とのインターフェースとして使用します(アプリケーションのインストール、端末のシェル、コマンドの実行などに使用)。 +
        +
        + +

        上記のツールに加えて、SDK に含まれている次のオープンソースとおよびサードパーティ製のツールを使用します:

        + +
        +
        Ant
        +
        Android プロジェクトをコンパイルし、インストール可能な .apk ファイルにビルドするために使用します。
        +
        Keytool
        +
        .apk ファイルに署名するために使用するキーストアと非公開キーを生成します。
        +
        Jarsigner(または同様の署名ツール)
        +
        Keytool で生成した非公開キーを使って .apk ファイルに署名するために使用します。
        +
        + +

        下記のトピックでは、必要な箇所でそれぞれの各ツールを説明しています。さらに高度な操作については、ツールのそれぞれのドキュメントをご覧ください。

        + + +

        Android プロジェクトの作成

        + +

        Android プロジェクトを作成するには、android ツールを使用する必要があります。新しいプロジェクトを android で作成すると、デフォルトのアプリケーション ファイル、スタブ ファイル、構成ファイル、ビルド ファイルを含むプロジェクト ディレクトリが生成されます。

        + + +

        新しいプロジェクトの作成

        + +

        新しいプロジェクトを開始する場合、android create project コマンドを使用すると、必要なファイルとフォルダがすべて生成されます。

        + +

        新しい Android プロジェクトを作成するには、コマンドラインを開き、SDK の tools/ ディレクトリに移動して、次を実行します:

        +
        +android create project \
        +--target <targetID> \
        +--path /path/to/your/project \
        +--activity <your_activity_name> \
        +--package <your_package_namespace>
        +
        + +
          +
        • target は、アプリケーションの「ビルド ターゲット」です。これは、プロジェクトをビルドする Android プラットフォーム ライブラリ(Google API のようなアドオンも含まれます)に対応します。使用可能なターゲットとそれに対応する ID の一覧を表示するには、android list targets を実行します。
        • +
        • path は、プロジェクト ディレクトリのロケーションです。このディレクトリが存在しない場合は、自動的に作成されます。
        • +
        • activity は使用する {@link android.app.Activity} クラスの名前です。このクラス ファイルは <path_to_your_project>/src/<your_package_namespace_path>/ 内に作成されます。
        • +
        • package はプロジェクトのパッケージ名前空間であり、Java プログラミング言語でのパッケージと同じルールに従います。
        • +
        + +

        次に例を示します:

        +
        +android create project \
        +--target 1 \
        +--path ./myProject \
        +--activity MyActivity \
        +--package com.example.myproject
        +
        + +

        このツールは次のファイルとディレクトリを生成します:

        + +
          +
        • AndroidManifest.xml - アプリケーションのマニフェスト ファイル。指定したプロジェクトの Activity クラスと同期されます。
        • +
        • build.xml - Ant 用のビルド ファイルです。
        • +
        • default.properties - ビルド システム用のプロパティです。このファイルを変更しないでください。
        • +
        • build.properties - ビルド システム用のカスタマイズ可能なプロパティです。このファイルを編集して、Ant が使用するデフォルトのビルド設定をオーバーライドできます。
        • +
        • src/your/package/namespace/ActivityName.java - プロジェクトの作成時に指定した Activity クラスです。
        • +
        • bin/ - ビルド スクリプト用の出力ディレクトリです。
        • +
        • gen/ - Ant が生成するファイル(R.java など)が含まれます。
        • +
        • libs/ - プライベート ライブラリが含まれます。
        • +
        • res/ - プロジェクト リソースが含まれます。
        • +
        • src/ - ソース コードが含まれます。
        • +
        • tests/ - テスト用に、上記のすべての複製が含まれます。
        • +
        + +

        プロジェクトを作成すると、開発を始める準備ができます。開発のために、プロジェクト フォルダをどこにでも移動できますが、アプリケーションをエミュレータに送信するために(方法については後述します)、SDK の tools/ ディレクトリにある Android Debug Bridge(adb)を使用する必要があります。そのためにプロジェクト ソリューションと tools/ フォルダ間でアクセスする必要があります。

        + +

        注: SDK ディレクトリは移動させないでください。移動するとビルド スクリプトが機能しなくなります(ビルド スクリプトをもう一度機能させるには、手動でスクリプトを更新して、SDK の新しいロケーションを反映させる必要があります)。

        + + +

        プロジェクトの更新

        + +

        Android SDK の古いバージョンからプロジェクトをアップグレードする場合や、既存のコードから新しいプロジェクトを作成する場合は、android update project コマンドを使って新しい開発環境に合わせてプロジェクトを更新します。このコマンドを使って(--target オプションにより)、既存のプロジェクトのビルド ターゲットを修正することもできます。android ツールは、指定された Android プロジェクトの必要に応じて、欠落している、または更新を必要としているファイルやフォルダの生成を行います。生成物は前セクションに記述されたリストどおりです。

        + +

        既存の Android プロジェクトを更新するには、コマンドラインを開き、SDK の tools/ ディレクトリに移動します。ここで次を実行します:

        +
        +android update project --target <targetID> --path path/to/your/project/
        +
        + +
          +
        • target は、アプリケーションの「ビルド ターゲット」です。これは、プロジェクトをビルドする Android プラットフォーム ライブラリ(Google API のようなアドオンも含まれます)に対応します。使用可能なターゲットとそれに対応する ID の一覧を表示するには、android list targets を実行します。
        • +
        • path は、プロジェクト ディレクトリのロケーションです。
        • +
        + +

        次に例を示します:

        +
        +android update project --target 2 --path ./myProject
        +
        + + +

        アプリケーションへの署名の準備

        + +

        Android アプリケーションの開発を始めると、Android アプリケーションをエミュレータや端末上のシステムにインストールする前に、どの Android アプリケーションにもデジタル署名が必要であることがわかります。解決策としては「デバッグ キー」を使用する方法(エミュレータや開発用端末上ですぐにテストする場合)と、非公開キーを使用する方法(アプリケーションを配布する場合)の 2 つがあります。

        + +

        Android のビルド ツールを使用すると、ビルド時にデバッグキーを使用して .apk ファイルに自動的に署名できるので、スムーズな開発が可能です。つまり、独自の非公開キーを生成しなくても、アプリケーションをコンパイルして、エミュレータにインストールすることができます。ただし、アプリケーションを公開する場合は、SDK ツールが生成したデバッグ キーではなく、独自の非公開キーを使用してアプリケーションに署名する必要があります

        + +

        アプリケーションへの署名をご覧ください。Android でのアプリケーションへの署名と、Android アプリケーション デベロッパーにとっての署名の意味について説明しています。

        + + + +

        アプリケーションのビルド

        + +

        アプリケーションのビルドには、アプリケーションをテスト/デバッグするための「デバッグ モード」と、リリース用の最終パッケージをビルドするための「リリース モード」の 2 つがあります。前のセクションで説明したように、アプリケーションをエミュレータや端末にインストールする前に、アプリケーションに署名する必要があります。

        + +

        デバッグ モードとリリース モードのどちらでビルドしているかに関係なく、プロジェクトをコンパイルし、ビルドするには Ant ツールが必要です。これにより、エミュレータや端末にインストールする .apk ファイルが作成されます。デバッグ モードでビルドすると、.apk ファイルは SDK ツールによりデバッグ キーを使用して自動的に署名されるので、インストールの準備がすぐに整います(ただし、エミュレータまたは接続された開発用端末上にのみインストールできます)。リリース モードでビルドされた .apk ファイルは署名されないので、Keytool と Jarsigner を使って、独自の非公開キーで手動で署名する必要があります。

        + +

        アプリケーションへの署名の内容をよく理解する必要があります。また、アプリケーションをリリースしてエンドユーザーと共有することを計画している場合は非常に重要です。「アプリケーションへの署名」では、非公開キーを生成し、それを使用して .apk ファイルに署名する手順について説明しています。ただし、開発を始めたばかりであれば、デバッグ モードでビルドすることにより、エミュレータまたは独自の開発用端末でアプリケーションをすぐに実行できます。

        + +

        Ant をお持ちでない場合は、Apache Ant ホームページから入手してください。Ant をインストールして、必ず実行可能パスに置きます。Ant を実行する前に、「JAVA_HOME」環境変数を宣言して JDK のインストールパスを指定する必要があります。

        + +

        注: Windows 上に JDK をインストールすると、デフォルトでは「Program Files」ディレクトリにインストールされます。このパス名にはスペースが含まれるために、ant は実行されません。この問題は、JAVA_HOME 変数を次のように指定することで解決できます: set JAVA_HOME=c:\Prora~1\Java\ ただし最も簡単な解決策は、JDK をスペースを含まないディレクトリ(例: c:\java\jdk1.6.0_02)にインストールすることです。

        + + +

        デバッグ モードでのビルド

        + +

        アプリケーションのテストとデバッグをすぐに行いたい場合は、デバッグ モードでアプリケーションをビルドし、すぐにエミュレータにインストールすることができます。デバッグ モードでは、ビルド ツールはデバッグ キーを使用してアプリケーションに自動的に署名します。ただしアプリケーションはリリース モードでテストすることも可能であり、リリース モードでのテストは推奨されています。デバッグ モードは、手動でアプリケーションに署名しなくても、アプリケーションを実行できるようにします。

        + +

        デバッグ モードでビルドするには:

        + +
          +
        1. コマンドラインを開き、プロジェクトのルート ディレクトリに移動します。
        2. +
        3. Ant を使用してプロジェクトをデバッグ モードでコンパイルします: +
          ant debug
          +

          Android アプリケーションの .apk ファイルがプロジェクトの bin/ ディレクトリに、<your_DefaultActivity_name>-debug.apk という名前で作成されます。このファイルはデバッグ キーで署名済みです。

          +
        4. +
        + +

        ソース ファイルまたはリソースを変更するたびに、アプリケーションの最新バージョンをパッケージングするために、Ant を再度実行する必要があります。

        + +

        アプリケーションをエミュレータにインストールして実行する方法については、下記のアプリケーションの実行セクションをご覧ください。

        + + +

        リリース モードでのビルド

        + +

        アプリケーションをエンドユーザーにリリースして配布する準備ができたら、アプリケーションをリリース モードでビルドする必要があります。リリース モードでビルドした後、最終的な .apk ファイルを使用して追加のテストとデバッグをすることをおすすめします。

        + +

        リリース モードでビルドするには:

        + +
          +
        1. コマンドラインを開き、プロジェクトのルート ディレクトリに移動します。
        2. +
        3. Ant を使用してプロジェクトをリリース モードでコンパイルします: +
          ant release
          +

          これにより Android アプリケーションの .apk ファイルがプロジェクトの bin/ ディレクトリに、<your_DefaultActivity_name>.apk という名前で作成されます。

          +

          注: .apk ファイルはこの時点では署名されていません。つまり非公開キーで署名するまで、エミュレータや端末にインストールすることはできません。

          +
        4. +
        + +

        リリース モードではアプリケーションを署名せずにビルドを行います。このため、アプリケーションをエンドユーザーに配布するためには、次に非公開キーを使用して署名を行う必要があります。この手順を行う方法については、Signing Your Applicationをご覧ください。

        + +

        非公開キーを使用してアプリケーションに署名すると、アプリケーションをエミュレータや端末にインストールできるようになります。これについては次のアプリケーションの実行のセクションで説明します。次の方法でウェブ サーバーから端末にインストールすることもできます。署名した APK をウェブサイトにアップロードし、Android ウェブブラウザでその .apk の URL を読み込んでアプリケーションをダウンロードし、インストールを開始します(端末上では、[設定] > [アプリケーション] を選択し、[提供元不明のアプリ] をオンにする必要があります)。

        + + +

        アプリケーションの実行

        + +

        端末のハードウェア以外でアプリケーションを実行する場合は、アプリケーションのインストール先となるエミュレータを起動する必要があります。Android エミュレータのインスタンスは、特有の端末構成に合わせて設定された、特定の Android プラットフォームを実行しています。このプラットフォームと構成は、Android 仮想デバイス(AVD)で定義されます。そのためエミュレータを起動する前に、AVD を定義しなくてはいけません。

        + +

        端末ハードウェアでアプリケーションを実行する場合は、代わりに、端末のでの開発 をご覧ください。

        + +
          +
        1. AVD の作成 +
            +
          1. コマンドラインを開き、SDK パッケージの tools/ ディレクトリに移動します。
          2. +
          3. 最初に、「配備ターゲット」を選択する必要があります。選択可能なターゲットを表示するには、次のコマンドを実行します: +
            android list targets
            +

            次のように選択可能な Android ターゲットのリストが表示されます:

            +
            +id:1
            +    Name: Android 1.1
            +    Type: platform
            +    API level: 2
            +    Skins: HVGA (default), HVGA-L, HVGA-P, QVGA-L, QVGA-P
            +id:2
            +    Name: Android 1.5
            +    Type: platform
            +    API level: 3
            +    Skins: HVGA (default), HVGA-L, HVGA-P, QVGA-L, QVGA-P
            +
            +

            アプリケーションを実行する Android プラットフォームに一致するターゲットを探します。id の番号を書き留めておき、次のステップで使用します。

            +
          4. +
          5. 選択した配備ターゲットを使用して、新しい AVD を作成します: +
            android create avd --name <your_avd_name> --target <targetID>
            +
          6. カスタム ハードウェア プロファイルを作成するかどうかの問い合わせがあります。「yes」と答えると、携帯端末ハードウェアのさまざまな面を定義するための一連の問い合わせがあります(入力を空白のままにすると、かっこ内に表示されたデフォルト値が使用されます)。または、Enter キーを押すと、すべてデフォルト値が使用されます(「no」がデフォルトです)。
          7. + +
          +
        2. + +
        3. エミュレータの起動
        4. +

          SDK の tools/ ディレクトリから、上記で作成した既存の AVD を使用してエミュレータを起動します: +

          emulator -avd <your_avd_name>
          +

          エミュレータのインスタンスが起動し、AVD で定義されたターゲットと構成が実行されます。

          + + +
        5. アプリケーションのインストール +

          SDK の tools/ ディレクトリから .apk をエミュレータにインストールします: +

          adb install /path/to/your/application.apk
          +

          複数のエミュレータが実行中の場合、-s オプションでシリアル番号を指定して、アプリケーションをインストールするエミュレーションを指定する必要があります。次に例を示します:

          +
          adb -s emulator-5554 install /my/project/path/myapp.apk
          +
        6. +
        7. アプリケーションを開く +

          エミュレータで、使用可能なアプリケーションのリストを開き、実行するアプリケーションを探して開きます。

          +
        8. +
        + +

        実行するアプリケーションがエミュレータ上にない場合、同じ AVD を指定してエミュレータを再起動してください。Activity を初めてインストールすると、アプリケーション ランチャに表示されず、他のアプリケーションからアクセスできないことがあります。パッケージ マネージャは通常、エミュレータの起動時にしかマニフェストを完全には調べないためです。

        + +

        ヒント: 実行中のエミュレータが 1 つしかない場合、1 つの簡単なステップで、アプリケーションをビルドし、エミュレータにインストールすることができます。プロジェクトのルート ディレクトリに移動し、Ant を使用してインストール モードでプロジェクトをコンパイルしますant install)。これにより、アプリケーションがビルドされ、デバッグ キーにより署名され、現在実行中のエミュレータにインストールされます。現在実行中のエミュレータが複数あると、install コマンドは失敗します。複数のエミュレータからの選択を行うことはできません。

        + +

        上記で使用したツールについて詳しくは、次のドキュメントをご覧ください:

        + + + +

        アプリケーションへのデバッガの接続

        + +

        このセクションでは、画面上でのデバッグ情報(CPU の使用率など)の表示方法や、総合開発環境に接続してエミュレータ上で実行するアプリケーションをデバッグする方法について説明します。

        + +

        Eclipse プラグインを使用すると、デバッガへの接続は自動化されます。しかし他の総合開発環境でも、デバッグ ポートをリッスンしてデバッグ情報を受信するように設定することができます:

        +
          +
        1. 総合開発環境とエミュレータ間のポート転送サービスとして機能する Dalvik Debug Monitor Server(DDMS)ツールを起動します。
        2. +
        3. エミュレータでオプションのデバッグ構成を設定します。設定には、デバッガ接続まで Activity のアプリケーション起動をブロックするオプションなどが含まれます。エミュレータでの CPU 使用率や画面の更新率の表示のように、これらのデバッグ用オプションの多くは DDMS がなくても使用できます。
        4. +
        5. 総合開発環境を設定して、デバッグ用にポート 8700 に接続します。総合開発環境を設定してデバッグ ポートに接続する をご覧ください。
        6. +
        diff --git a/docs/html/intl/ja/guide/index.jd b/docs/html/intl/ja/guide/index.jd new file mode 100644 index 0000000000000..73ca18a4a8a76 --- /dev/null +++ b/docs/html/intl/ja/guide/index.jd @@ -0,0 +1,52 @@ +page.title=デベロッパー ガイド +@jd:body + +

        +Android デベロッパー ガイドへようこそ。デベロッパー ガイドは、Android 向けアプリケーション開発における実用的な入門資料です。この資料では、Android の背後にある概念、アプリケーション構築用のフレームワーク、およびAndroid プラットフォーム向けソフトウェアを開発、テスト、公開するためのツールについて説明します。 +

        + +

        +デベロッパー ガイドには Android プラットフォームに関するほとんどのドキュメントが含まれていますが、フレームワーク API に関する参考資料は含まれていません。API の仕様については、上部にある [リファレンス] タブをご覧ください。 +

        + +

        +左側のパネルに表示されているように、デベロッパー ガイドは複数のセクションに分かれています。各セクションは次のとおりです: +

        + +

        +
        Android の基本
        +
        Android とは何か、基本機能、アプリケーションとの関係など、Android の基本事項について紹介します。
        + +
        フレームワーク トピック
        +
        Android のフレームワークと API の各部分について説明します。フレームワークの概要については、アプリケーションの基礎を最初にご覧ください。次に、ユーザー インターフェースの設計やリソースの設定、データの保存、権限の利用など、それぞれのトピックを必要に応じて参照してください。
        + +
        開発
        +
        Android の開発とデバッグ用ツールの使用方法、結果のテスト方法について説明します。
        + +
        公開
        +
        アプリケーション配布の準備をする方法と、準備ができたら公開する方法について説明します。
        + +
        ベスト プラクティス
        +
        効率よく機能し、ユーザーにとって役立つアプリケーションを作成するための推奨テクニックについて説明します。
        + +
        チュートリアルとサンプル
        +
        Android アプリケーションを構築する方法を例示する段階的なチュートリアルとサンプル コードです。
        + +
        付録
        +
        関連情報、仕様、よくある質問、用語解説などの情報です。
        +
        + +

        +Android 向けプログラム開発の最初のステップは、SDK(ソフトウェア開発キット)をダウンロードすることです。このキットのダウンロード方法と説明については、上部にある [SDK] タブをご覧ください。 +

        + +

        +SDK のダウンロード後は、まずはじめにデベロッパー ガイドを参照してください。コードを実際に見てみることから始めたい場合は、簡単な Hello World チュートリアルを参照してください。Android プラットフォーム向けに作成された標準的な「Hello, World」アプリケーションについて説明しています。アプリケーションの基礎ドキュメントは、アプリケーション フレームワークを理解したいユーザーに最適な出発点となります。 +

        + + +

        +不明点などがある場合は、Android ディスカッション グループへの参加をおすすめします。詳しくは上部にある [コミュニティ] タブをご覧ください。 +

        + +

        デベロッパー ガイドの別のページに移動してから、このページに戻るには、[デベロッパー ガイド] タブをクリックします。

        \ No newline at end of file diff --git a/docs/html/intl/ja/guide/publishing/app-signing.jd b/docs/html/intl/ja/guide/publishing/app-signing.jd new file mode 100644 index 0000000000000..23d8cf764e91d --- /dev/null +++ b/docs/html/intl/ja/guide/publishing/app-signing.jd @@ -0,0 +1,336 @@ +page.title=アプリケーションへの署名 +@jd:body + +
        +
        + +

        署名の概略

        + +
          +
        • Android アプリケーションはすべて署名する必要がある
        • +
        • 自己署名キーで署名可能
        • +
        • アプリケーションの署名方法は重要です。このドキュメントをよくお読みください
        • +
        • 開発プロセスの初期段階で署名戦略を決定します
        • +
        + +

        このドキュメントの内容

        + +
          +
        1. 概要
        2. +
        3. 署名戦略
        4. +
        5. 署名の基本設定
        6. +
        7. デバッグ モードでの署名
        8. +
        9. 公開リリースへの署名 +
            +
          1. リリース向けのコンパイル
          2. +
          3. 適切な秘密鍵の取得
          4. +
          5. アプリケーションの署名
          6. +
          7. Eclipse ADT によるコンパイルと署名
          8. +
          +
        10. +
        11. 秘密鍵のセキュリティ設定
        12. + +
        + +

        関連項目

        + +
          +
        1. アプリケーションのバージョニング
        2. +
        3. 公開の準備
        4. +
        + +
        +
        + +

        このドキュメントでは、Android アプリケーションを携帯端末ユーザーに公開する前に署名する方法について説明します。

        + +

        概要

        + +

        Android システムでは、インストールするすべてのアプリケーションに対してデジタル署名されて証明書を必要とします。この証明書の秘密鍵は、アプリケーションのデベロッパーが所持するものです。Android システムは証明書をアプリケーションの作成者の識別手段、およびアプリケーション間の信頼関係の確立手段として使用します。証明書は、ユーザーがどのアプリケーションをインストールできるかを制御するものではありません。証明書は認証機関によって署名される必要はありません。通常の Android アプリケーションは自己署名証明書を使用して正常に機能します。

        + +

        Android アプリケーションの署名について、次の点を理解することが重要です:

        + +
          +
        • すべてのアプリケーションは署名される必要があります。署名されていないアプリケーションはシステムにインストールされません。
        • +
        • アプリケーションの署名に、自己署名証明書を使用できます。認証機関は不要です。
        • +
        • アプリケーションをエンド ユーザーにリリースする準備ができたら、適切な秘密鍵を使用してアプリケーションに署名する必要があります。SDK ツールで生成されたデバッグ キーで署名されたアプリケーションは、公開できません。 +
        • +
        • システムが署名証明書の有効期限を確認するのは、インストール時のみです。アプリケーションのインストール後に署名者証明書が期限切れになった場合、アプリケーションは正常な動作を継続します。
        • +
        • 標準ツールである Keytool と Jarsigner を使用してキーを生成し、アプリケーションの .apk ファイルに署名できます。
        • +
        + +

        Android システムは、適切に署名されていないアプリケーションをインストールせず、実行もしません。この規則は、実際のデバイスでもエミュレータでも、Android システムが実行されるすべての状況で適用されます。このため、エミュレータまたはデバイス上で実行またはデバッグする前に、アプリケーションの署名を設定する必要があります。

        + +

        Android SDK ツールは、デバッグ時のアプリケーション署名を支援します。「ADT Plugin for Eclipse」と「Ant ビルド ツール」では両方とも、デバッグ モードリリース モードの 2 種類の署名モードを利用できます。 + +

          +
        • 開発およびテスト中は、デバッグ モードでコンパイルできます。デバッグ モードでは、ビルド ツールは JDK に付属の Keytool ユーティリティを使用して、キーストアとキーを既知のエイリアスとパスワードで作成します。コンパイルのたびに、ツールはデバッグ キーを使用してアプリケーションの .apk ファイルに署名します。パスワードは既知のものなので、コンパイルのたびにツールにキーストア/キー パスワードを入力する必要はありません。
        • + +
        • アプリケーションをリリースする準備ができたら、リリース モードでコンパイルして、.apk に秘密鍵で署名する必要があります。次の 2 通りの方法があります: +
            +
          • Keytool と Jarsigner をコマンド ラインで使用する方法。このアプローチでは、まずアプリケーションを署名されていない .apk にコンパイルします。次に、Jarsigner(または類似のツール)を使用して秘密鍵で .apk に手動で署名します。適切な秘密鍵を所持していない場合は、Keytool を手動で実行して独自のキーストア/キーを生成し、Jarsigner でアプリケーションに署名できます。
          • +
          • ADT Export Wizard を使用する方法。ADT プラグイン搭載の Eclipse を使用して開発している場合、Export Wizard を使用してアプリケーションをコンパイルし、秘密鍵を生成して(必要な場合)、.apk に署名できます。この作業をすべて Export Wizard を使用して 1 つのプロセスで実行できます。 +
          • +
          +
        • +
        + +

        署名戦略

        + +

        アプリケーションの署名は、開発アプローチに一部影響します。特に、複数のアプリケーションをリリースする予定の場合、高い影響を与えます。

        + +

        一般に、すべてのデベロッパーに推奨される戦略は、アプリケーションの予期される使用期間を通じて同じ証明書ですべてのアプリケーションに署名することです。このようにするには、複数の理由があります:

        + +
          +
        • アプリケーションのアップグレード - アプリケーションのアップグレードをリリースするとき、ユーザーが新バージョンにシームレスにアップグレードできるように、アップグレードされたアプリケーションにも同じ証明書で署名します。システムがアプリケーションのアップデートをインストールする際は、新バージョンの証明書のいずれかが旧バージョンの証明書と一致する場合、システムがアップデートを許可します。一致する証明書を使用せずに署名する場合は、アプリケーションに別のパッケージ名を割り当てる必要があります。この場合、新しいバージョンがまったく新しいアプリケーションとしてインストールされます。
        • + +
        • アプリケーションのモジュール性 - Android システムでは、アプリケーションが要求する場合、同じ証明書で署名されたアプリケーションを同じプロセスで実行できます。これにより、システムはこれらを単一のアプリケーションとして取り扱います。このようにすればアプリケーションをモジュールとして配備でき、ユーザーは必要に応じて各モジュールを個別に更新できます。
        • + +
        • 許可によるコード/データ共有 - Android システムでは、署名ベースの権限付与を実施しているため、アプリケーションは指定された証明書で署名されている別のアプリケーションに機能を提供できます。同じ証明書で複数のアプリケーションに署名し、署名に基づいた権限のチェックを行うことで、アプリケーションはコードとデータを安全な方法で共有できます。
        • + +
        + +

        署名戦略を決定する際のもう 1 つの重要な検討事項として、アプリケーションの署名に使用するキーの有効期間の設定方法があります。

        + +
          +
        • アプリケーションのアップグレードをサポートするには、キーの有効期間は、アプリケーションの予定される試用期間以上である必要があります。有効期間は、25年以上であることが推奨されます。キーの有効期間が切れた場合、ユーザーはアプリケーションの新バージョンにシームレスにアップグレードできなくなります。
        • + +
        • 同じキーで複数の異なるアプリケーションに署名する場合、キーの有効期間が、今後のアプリケーション スイートに追加される依存アプリケーションを含め、すべてのアプリケーションのすべてのバージョンの予定される使用期間を超えることを確認してください。
        • + +
        • アプリケーションを Android マーケットに公開する予定の場合、アプリケーションの署名に使用するキーの有効期間を、2033 年 10 月 22 日以降の期限に設定する必要があります。マーケット サーバーは、新バージョンが公開されたときにユーザーがマーケット アプリケーションをシームレスにアップグレードできるよう、この要件を義務付けています。
        • +
        + +

        アプリケーションの設計時にこれらの点を考慮し、アプリケーションの署名に適切な証明書を使用してください。

        + +

        署名の基本設定

        + +

        キーストアとデバッグ キーの生成をサポートするため、SDK ビルド ツールで Keytool を使用できることを初めに確認してください。たいていの場合、「JAVA_HOME」環境変数を設定して適切な JDK を参照させることで、SDK ビルド ツールで Keytool を認識できます。または、JDK バージョンの Keytool を PATH 変数に追加しても認識できます。

        + +

        Linux バージョンに付属されている GNU Java コンパイラで開発している場合は、gcj バージョンではなく、JDK バージョンの Keytool を使用していることを確認してください。Keytool が既に PATH に指定されている場合は、/usr/bin/keytool の symlink を指していることがあります。この場合は、symlink ターゲットが JDK の Keytool を指していることを確認してください。

        + +

        アプリケーションを公開する場合は、Jarsigner ツールをコンピュータで使用できるようにする必要があります。Jarsigner と Keytool の両方が JDK によって提供されます。

        + +

        デバッグ モードでの署名

        + +

        Android ビルド ツールにはデバッグ署名モードがあり、アプリケーションの開発とデバッグがスムーズに行えます。また、.apk をエミュレータまたはデバイスにインストールする際の、署名に対する Android システム要件を満たします。デバッグモードでは、SDK ツールは Keytool を呼び出してデバッグ キーストアとキーを作成します。

        + +

        SDK ツールは事前に指定された名前とパスワードを使用してデバッグ キーストア/キーを作成します。

        +
          +
        • キーストア名 – 「debug.keystore」
        • +
        • キーストアのパスワード – 「android」
        • +
        • キーのエイリアス – 「androiddebugkey」
        • +
        • キーのパスワード – 「android」
        • +
        • CN – 「CN=Android Debug,O=Android,C=US」
        • +

        + +

        必要に応じて、デバッグ キーストア/キーの場所および名前を変更できます。また、自分で作成したデバッグ キーストア/キーを指定することもできます。Eclipse/ADT で、[[]ウィンドウ(Windows)] > [[]設定(Prefs)] > [[]Android] > [[]ビルド(Build)] を選択します。ただし、自分で作成したデバッグ キーストア/キーは、デフォルトのデバッグ キー(上述)と同じキーストア/キー名とパスワードを使用する必要があります。

        + +

        注: デバッグ証明書で署名した場合は、アプリケーションを公開できません

        + +

        Eclipse ユーザー

        + +

        Eclipse/ADT で開発し、Keytool を上記のように設定してある場合は、デバッグモードにおける署名はデフォルトで有効になっています。アプリケーションを実行またはデバッグするときに、ADT は .apk にデバッグ証明書で署名し、エミュレータにインストールします。ADT が Keytool にアクセスできる場合は、ユーザーは特に操作する必要はありません。

        + +

        Ant ユーザー

        + +

        Ant を使用して .apk ファイルを構築する場合、デバッグ署名モードは debug オプションを使用することで有効になります(android ツールで生成された build.xml ファイルを使用していることが前提となります)。ant debug を実行してアプリケーションをコンパイルする際、ビルド スクリプトはキーストア/キーを生成し、.apk に署名します。ユーザーは操作する必要はありません。詳細は、その他の統合開発環境での開発: デバッグモードにおけるビルド をお読みください。

        + + +

        デバッグ証明書の有効期限

        + +

        デバッグ モード(Eclipse/ADT と Ant ビルドのデフォルト)でのアプリケーション署名に使用した自己署名証明書には、作成日から 365 日の有効期限が設定されます。

        + +

        証明書の期限が切れると、ビルド エラーが発生します。Ant ビルドでは、エラーは次のようになります:

        + +
        debug:
        +[echo] Packaging bin/samples-debug.apk, and signing it with a debug key...
        +[exec] Debug Certificate expired on 8/4/08 3:43 PM
        + +

        Eclipse/ADT では、Android コンソールに同様のエラーが表示されます。

        + +

        この問題を解決するには、debug.keystore ファイルを削除します。AVD のデフォルトの格納場所は、OS X と Linux の場合は ~/.android/avd、Windows XP の場合は C:\Documents and Settings\\.android\、Windows Vista の場合は C:\Users\\.android\ です。

        + + +

        次にビルドを行うと、ビルド ツールは新しいキーストアとデバッグ キーを再度生成します。

        + +

        開発コンピュータがグレゴリオ暦以外のロケールを使用している場合、ビルド ツールが誤って期限切れのデバッグ証明書を生成することがあります。このため、アプリケーションをコンパイルしようとするとエラーが発生します。解決策については、トラブルシューティング トピックの ビルド ツールが期限切れのデバッグ証明書を生成するため、アプリケーションがコンパイルできない をご覧ください。

        + + +

        公開リリースへの署名

        + +

        アプリケーションを他のユーザーに公開する準備ができたら、次のことを行う必要があります:

        +
          +
        1. アプリケーションをリリース モードでコンパイルする
        2. +
        3. 適切な秘密鍵を取得する
        4. +
        5. アプリケーションに秘密鍵で署名する
        6. +
        + +

        以下のセクションでは、これらの手順を実行する方法について説明します。

        + +

        ADT プラグイン搭載の Eclipse を使用している場合、これらの手順を実行する代わりに Export Wizard を使用して .apk をコンパイルして秘密鍵で署名できます。Export Wizard では、処理過程で新しいキーストアと秘密鍵の生成も可能です。Eclipse ADT によるコンパイルと署名を参考にコンパイルを行ってください。

        + + +

        リリース向けのコンパイル

        + +

        アプリケーションのリリースを準備するには、リリース モードでコンパイルする必要があります。リリース モードでは、Android ビルド ツールはアプリケーションを通常どおりにコンパイルしますが、デバッグ キーで署名しません。

        + +

        注: 署名されていないアプリケーション、またはデバッグ キーで署名されたアプリケーションはリリースできません。

        + +

        Eclipse ユーザー

        + +

        署名されていない .apk ファイルを Eclipse からエクスポートするには、パッケージ エクスプローラー(Package Explorer)でプロジェクトを右クリックして、[[]Android ツール(Android Tools)] > [[]署名されていないアプリケーション パッケージのエクスポート(Export Unsigned Application Package)] を選択します。次に、署名されていない .apk ファイルの場所を指定します(または、AndroidManifest.xml ファイルを Eclipse で開き、[[]概要(Overview)] タブを開いて [[]署名されていない .apk のエクスポート(Export an unsigned .apk)] をクリックします)。

        + +

        Export Wizard では、コンパイルと署名の手順を一緒に処理できます。Eclipse ADT によるコンパイルと署名をご覧ください。

        + +

        Ant ユーザー

        + +

        Ant を使用している場合は、必要な作業は Ant コマンドでビルド ターゲットとして「release」を指定するだけです。たとえば、Ant を build.xml ファイルがあるディレクトリから実行している場合、コマンドは次のようになります:

        + +
        $ ant release
        + +

        ビルド スクリプトは、アプリケーション .apk を署名せずにコンパイルします。

        + + +

        適切な秘密鍵の取得

        + +

        アプリケーションの署名を準備するには、まず署名に使用する適切な秘密鍵があることを確認することが必要です。適切な秘密鍵とは、次の条件を満たすものです:

        + +
          +
        • 自分が所有している。
        • +
        • アプリケーションで識別される、個人、法人、または組織の実体を表す。
        • +
        • アプリケーションまたはアプリケーション スイートの予期される使用期間を超える有効期間を持っている。有効期間として、25 年以上を推奨します。 +

          アプリケーションを Android マーケットに公開する予定の場合、2033 年 10 月 22 日までの有効期間が必要です。有効期間がこの日付以前に期限切れになるキーで署名されたアプリケーションは、アップロードできません。 +

        • +
        • Android SDK ツールで生成されたデバッグ キーではない。
        • +
        + +

        自己署名されたキーを使用できます。適切なキーがない場合、Keytool を使用して生成する必要があります。基本設定で説明した手順に従って、Keytool を使用できるようにしてください。

        + +

        Keytool で自己署名キーを生成するには、keytool コマンドを使用して以下に示すオプション(および、必要に応じてその他のオプション)を渡します。

        + +

        注: Keytool を実行する前に、秘密鍵のセキュリティ設定を読んで、キーのセキュリティを確保する方法と、自分とユーザーにとってセキュリティ確保が重要な理由を理解してください。特に、自分のキーを生成する場合、キーストアとキーの両方に強力なパスワードを選択する必要があります。

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        Keytool のオプション説明
        -genkeyキー ペアを生成します(公開キーと秘密鍵)。
        -v詳しいメッセージを出力する。
        -keystore <keystore-name>.keystore秘密鍵を含むキーストアの名前。
        -storepass <password>

        キーストアのパスワード。

        セキュリティ上の注意として、安全なコンピュータで作業している場合を除き、このオプションをコマンド ラインに指定しないでください。指定しなかった場合、Keytool からパスワードの入力が求められます。このため、パスワードはシェルの履歴に記録されません。

        -alias <alias_name>キーのエイリアス。
        -keyalg <alg>キーの生成時に使用する暗号化アルゴリズム。DSA と RSA の 2 つをサポートしています。
        -dname <name>

        キーの作成者を識別する、識別名。値は、自己署名証明書の発行者およびサブジェクト フィールドとして使用されます。

        このオプションはコマンド ラインで指定する必要はありません。指定しなかった場合、Jarsigner からそれぞれの識別名フィールド(CN、OU など)の入力が求められます。

        -validity <valdays>

        キーの有効期間(日数)。

        注: 10000 以上の値を推奨します。

        -keypass <password>

        キーのパスワード。

        +

        セキュリティ上の注意として、安全なコンピュータで作業している場合を除き、このオプションをコマンド ラインに指定しないでください。指定しなかった場合、Keytool からパスワードの入力が求められます。このため、パスワードはシェルの履歴に記録されません。

        + + +

        秘密鍵を生成する Keytool コマンドの例を示します。

        + +
        $ keytool -genkey -v -keystore my-release-key.keystore 
        +-alias alias_name -keyalg RSA -validity 10000
        + +

        上記のコマンド例を実行すると、Keytool からキーストアとキーのパスワードと、キーの識別名フィールドの指定が求められます。キーストアが my-release-key.keystore というファイルとして生成されます。キーストアとキーは、入力したパスワードで保護されます。キーストアには 1 つのキーが含まれ、10000 日間有効です。エイリアスは、後で使用する名前で、アプリケーションに署名するときにこのキーストアを参照する名前です。

        + +

        Keytool の詳細は http://java.sun.com/j2se/1.5.0/docs/tooldocs/#security のドキュメント(英語のみ)をご覧ください。

        + + +

        アプリケーションの署名

        + +

        リリースする .apk に実際に署名する準備ができたら、Jarsigner ツールを使用して署名できます。基本設定で説明したように、Jarsigner をコンピュータで使用できることを確認してください。また、秘密鍵を含むキーストアがあることも確認してください。

        + +

        アプリケーションに署名するには、Jarsigner を実行して、アプリケーションの .apk と、.apk の署名に使用する秘密鍵を含むキーストアの両方を参照します。以下の表では、使用できるオプションを示します。

        + + + + + + + + + + + + + + + + + + +
        Jarsigner のオプション説明
        -keystore <keystore-name>.keystore秘密鍵を含むキーストアの名前。
        -verbose詳しいメッセージを出力する。
        -storepass <password>

        キーストアのパスワード。

        セキュリティ上の注意として、安全なコンピュータで作業している場合を除き、このオプションをコマンド ラインに指定しないでください。指定しなかった場合、Jarsigner からパスワードの入力が求められます。このため、パスワードはシェルの履歴に記録されません。

        -keypass <password>

        秘密鍵のパスワード。

        セキュリティ上の注意として、安全なコンピュータで作業している場合を除き、このオプションをコマンド ラインに指定しないでください。指定しなかった場合、Jarsigner からパスワードの入力が求められます。このため、パスワードはシェルの履歴に記録されません。

        + +

        Jarsigner を使用して my_application.apk というアプリケーション パッケージに署名する例を、上記で作成したキーストアを使用して示します。 +

        + +
        $ jarsigner -verbose -keystore my-release-key.keystore 
        +my_application.apk alias_name
        + +

        上記のコマンドを実行すると、Jarsigner からキーストアとキーのパスワードの入力が求められます。.apk がその場で変更され、.apk は署名されます。.apk に別のキーで複数回署名できます。

        + +

        .apk が署名されたことを確認するには、次のようなコマンドを使用できます:

        + +
        $ jarsigner -verify my_signed.apk
        + +

        .apk が適切に署名されると、Jarsigner から「jar verified」と出力されます。詳細情報が必要な場合は、次のコマンドを使用できます。

        + +
        $ jarsigner -verify -verbose my_application.apk
        + +

        または、次のコマンドを使用します。

        + +
        $ jarsigner -verify -verbose -certs my_application.apk
        + +

        上記の -certs オプションが付加されたコマンドでは、「CN=」行が出力され、キーの作成者が示されます。

        + +

        注: 「CN=Android Debug」と出力される場合、.apk が Android SDK によって生成されたデバッグ キーで署名されたことを示しています。アプリケーションをリリースする予定の場合は、デバッグ キーではなく秘密鍵で署名する必要があります。

        + +

        Jarsigner の詳細は http://java.sun.com/j2se/1.5.0/docs/tooldocs/#security のドキュメント(英語のみ)をご覧ください。

        + + +

        Eclipse ADT によるコンパイルと署名

        + +

        ADT 搭載 Eclipse を使用している場合、Export Wizard を使用して署名済み .apk をエクスポートできます(必要に応じて、新しいキーストアを作成することもできます)。Export Wizard は、Keytool と Jarsigner のすべての処理を、コマンド ラインを使用せず、グラフィカル ユーザー インターフェースで署名を実行できます。Export Wizard は Keytool と Jarsigner の両方を使用するため、上記の署名の基本設定の条件を満たすコンピュータで使用できます。

        + +

        署名された .apk を作成するには、パッケージ エクスプローラー(Package Explorer)でプロジェクトを右クリックして、[[]Android ツール(Android Tools)] > [[]署名済みアプリケーション パッケージのエクスポート(Export Signed Application Package)] を選択します(または、AndroidManifest.xml ファイルを Eclipse で開き、[[]概要(Overview)] タブを開いて [[]Export Wizard を使用する(Use the Export Wizard)] をクリックします)。表示されたウィンドウには、アプリケーションのエクスポート中に見つかったエラーが表示されます。エラーが見つからなかった場合は Export Wizard で処理を続行します。.apk に署名する秘密鍵の選択や、新しいキーストアと秘密鍵の作成など、アプリケーション署名のプロセスを手順を追って実行できます。

        + +

        Export Wizard が完了すると、配布可能な署名済み .apk が作成されています。

        + + +

        秘密鍵のセキュリティ設定

        + +

        秘密鍵のセキュリティ設定は、作成者とユーザーの両者にとって重要です。他人にキーを使用させたり、第三者が見つけて使用できるような安全ではない場所にキーストアとキーを放置したりすると、作成者とユーザー間の信頼が損なわれます。

        + +

        他者が許可を得ずにキーを取得した場合、その人物はアプリケーションに署名して配布し、本物のアプリケーションを故意に置き換えたり破損させたりすることができます。このような人物は、身元を詐称してアプリケーションに署名して配布し、その他のアプリケーションまたはシステム自体を攻撃したり、ユーザー データを破損させたり盗み出したりすることもあります。

        + +

        キーの有効期限が切れるまで、秘密鍵のセキュリティを常に適切に維持できるかは、デベロッパーとしての評価を左右します。キーを安全に保つためのヒントをいくつか紹介します。

        + +
          +
        • キーストアとキーに強力なパスワードを選択します。
        • +
        • Keytool でキーを生成するとき、コマンド ラインで -storepass および -keypass オプションを指定しないようにします。指定すると、パスワードがシェル履歴に記録され、コンピュータのすべてのユーザーがアクセスできるようになります。
        • +
        • 同様に、Jarsigner でアプリケーションに署名するとき、コマンド ラインで -storepass-keypass オプションを指定しないようにします。
        • +
        • 秘密鍵を誰にも与えたり貸したりせず、不正なユーザーにキーストアとキーのパスワードを知られないようにします。
        • +
        + +

        一般的には、キーの生成、使用、保管に関して常識的な注意を払っていれば、セキュリティを確保することができます。

        \ No newline at end of file diff --git a/docs/html/intl/ja/guide/publishing/preparing.jd b/docs/html/intl/ja/guide/publishing/preparing.jd new file mode 100644 index 0000000000000..f1e7b45fbedba --- /dev/null +++ b/docs/html/intl/ja/guide/publishing/preparing.jd @@ -0,0 +1,154 @@ +page.title=公開の準備 +@jd:body + + + +

        アプリケーションの公開とは、アプリケーションをテストして適切にパッケージし、Android 搭載の携帯端末のユーザーが利用できる状態にすることです。

        + +

        アプリケーションを公開して Android 搭載デバイスにインストールするには、いくつかの作業を行ってアプリケーションの準備を整える必要があります。このドキュメントでは、アプリケーションのリリースを成功させるための準備における、重要なチェックポイントを説明しています。 +

        + +

        アプリケーションを Android マーケットに公開する場合は、アプリケーションの具体的な準備要件について Android マーケットでの公開 もご覧ください。

        + +

        アプリケーションを公開する方法の一般的な情報については、Publishing Your Applications のドキュメントをご覧ください。

        + +
        + +

        アプリケーションのリリースを準備する前の作業:

        + +
          +
        1. アプリケーションを実際のデバイスで徹底的にテストする
        2. +
        3. アプリケーションへのエンド ユーザー ライセンス契約の追加を検討する
        4. +
        5. アプリケーションのマニフェストにアイコンとラベルを指定する
        6. +
        7. ロギングとデバッグを無効にして、データとファイルをクリーンアップする
        8. +
        + +

        アプリケーションの最終コンパイルを実行する前の作業:

        + +
          +
        1. アプリケーションでバージョン管理を行う
        2. +
        3. 適切な暗号化キーを取得する
        4. +
        5. アプリケーションが MapView 要素を使用している場合は、Maps API キーに登録する
        6. +
        + +

        アプリケーションのコンパイル

        +

        アプリケーションをコンパイルした後の作業:

        +
          +
        1. アプリケーションに署名する
        2. +
        3. コンパイルしたアプリケーションをテストする
        4. +
        +
        + +

        アプリケーションのリリースを準備する前の作業

        + +

        1. アプリケーションを実際のデバイスで徹底的にテストする

        + +

        アプリケーションをできる限り広範に徹底的にテストすることが重要です。この作業を支援するため、Android では多数のテスト用クラスとツールを用意しています。{@link android.app.Instrumentation Instrumentation} を使用して JUnit およびその他のテスト ケースを実行できます。また、UI/Application Exerciser Monkey などのテスティング ツールを使用できます。

        + +
          +
        • ユーザーがアプリケーションを正常に実行できるようにするため、アプリケーションが実行されると予想されるタイプの携帯端末の実機を入手してください。実際のデバイスで、実際のネットワーク条件の下でアプリケーションをテストします。アプリケーションを実際のデバイスでテストすることは非常に重要です。これによって、作成したユーザー インターフェース要素のサイズが正しく(特にタッチスクリーン UI の場合)、アプリケーションのパフォーマンスと電池効率が適正であることを確認できるからです。
        • + +
        • アプリケーションの対象とするタイプの携帯端末が手に入らない場合は、-dpi-device-scale-netspeed-netdelay-cpu-delay などのエミュレータ オプションを使用して、エミュレータの画面、ネットワーク パフォーマンス、その他の属性をモデル化して可能な限り対象デバイスに適応させることができます。このようにして、アプリケーションの UI とパフォーマンスをテストできます。ただし、公開する前にアプリケーションを実際の対象デバイスでテストすることを強く推奨します。
        • + +
        • アプリケーションが T-Mobile G1 デバイスを対象としている場合、UI が画面の向き変更に対応しているか確認してください。
        • +
        + +

        2. アプリケーションへのエンドユーザー ライセンス契約の追加を検討する

        + +

        個人、組織、知的財産を保護するため、アプリケーションのエンドユーザー ライセンス契約(EULA)を付加することを推奨します。 + +

        3. アプリケーションのマニフェストにアイコンとラベルを指定する

        + +

        アプリケーションのマニフェストに指定するアイコンとラベルは、アプリケーションのアイコンと名前としてユーザーに表示されるため、重要な要素です。アイコンとラベルは、デバイスの [[]ホーム] 画面や、[[]アプリケーションの管理]、[[]マイダウンロード] などに表示されます。また、公開サービスによってアイコンとラベルがユーザーに表示される可能性もあります。

        + +

        アイコンとラベルを指定するには、android:iconandroid:label 属性をマニフェストの <application> 要素に定義します。

        + +

        アイコンのデザインについては、組み込みの Android アプリケーションのスタイルとできるだけ統一感を持たせてください。

        + +

        4. ロギングとデバッグを無効にして、データとファイルをクリーンアップする

        + +

        リリース時にはデバッグ機能を無効にし、デバッグおよびその他の不要なデータ/ファイルをアプリケーション プロジェクトから削除してください。

        +
          +
        • android:debuggable="true" 属性をマニフェストの <application> 要素から削除します。
        • +
        • ログ ファイル、バックアップ ファイル、およびその他の不要なファイルをアプリケーション プロジェクトから削除します。
        • +
        • 個人的または自分専用のデータがないか確認し、必要に応じて削除します。
        • +
        • ソース コード内に {@link android.util.Log} メソッドへの呼び出しがある場合は、無効にします。
        • +
        + +

        アプリケーションの最終コンパイルを実行する前の作業

        + +

        5. アプリケーションでバージョン管理を行う

        + +

        アプリケーションをコンパイルする前に、アプリケーションにバージョン番号を定義しておく必要があります。定義するには、アプリケーションのマニフェスト ファイルの <manifest> 要素の android:versionCodeandroid:versionName 属性の両方に適切な値を指定します。バージョン番号の設定は、全体的なアプリケーションアップグレードの計画を考慮して、慎重に検討してください。

        + +

        これまでにリリースしたバージョンがある場合、最新のアプリケーションのバージョン番号を旧バージョンから増加させる必要があります。アプリケーションのマニフェスト ファイルの <manifest> 要素の android:versionCodeandroid:versionName 属性の両方を適切な値を使用して増加する必要があります。

        + +

        アプリケーションのバージョン情報を定義する方法は、Versioning Your Applicationsをご覧ください。

        + +

        6. 適切な暗号化キーを取得する

        + +

        ここまで準備作業をすべて読んで実行していれば、アプリケーションはコンパイルされ、署名の準備ができています。.apk の内部では、アプリケーションは適切にバージョン管理されており、上記のように余分なファイルや非公開データは削除されています。

        + +

        アプリケーションに署名する前に、適切な非公開キーがあることを確認する必要があります。非公開キーを取得(または生成)する方法については、適切な非公開キーの取得をご覧ください。

        + +

        適切な非公開キーを取得(または生成)したら、キーを使用して次の手順を実行します:

        + +
          +
        • アプリケーションが MapView 要素を使用している場合は、Maps API キー(以下をご覧ください)に登録します。
        • +
        • 以降の準備プロセスで、リリースするアプリケーションに署名します。
        • +
        + +

        7. アプリケーションが MapView 要素を使用している場合は、Maps API キーに登録する

        + + + +

        アプリケーションが Mapview 要素を使用する場合、アプリケーションを Google Maps サービスで登録し、Maps API キーを取得する必要があります。その後、MapView で Google Maps からデータを取得できるようになります。この処理を行うため、Maps サービスに署名証明書の MD5 フィンガープリントを提出します。

        + +

        開発中は、SDK ツールが生成したデバッグ キーを登録して一時的な Maps API キーを取得できます。ただし、アプリケーションを公開する前には、非公開キーに基づく新しい Maps API キーで登録する必要があります。

        + +

        アプリケーションが MapView 要素を使用する場合、次の点を理解することが重要です:

        + +
          +
        1. アプリケーションをリリース用にコンパイルする前に、Maps API キーを取得する必要があります。このキーを、アプリケーションのレイアウト ファイルにある各 MapView 要素の、android:apiKey という特殊な属性に追加する必要があるからです。MapView オブジェクトをコードから直接インスタンス化している場合は、Maps API キーをコンストラクタのパラメータとして渡す必要があります。 +
        2. +
        3. アプリケーションの MapView 要素が参照する Maps API キーは Google Maps 内で登録され、アプリケーションの署名に使用される証明書に登録される必要があります。これはアプリケーションを公開する際に特に重要です。MapView 要素は、アプリケーションの署名に使用されるリリース証明書に登録されるキーを参照する必要があります。
        4. +
        5. SDK ツールが生成したデバッグ証明書を登録して一時的な Maps API キーを取得している場合、リリース証明書を登録して新しい Maps API キーを取得する必要があります。また、MapView 要素を変更して、デバッグ証明書と関連付けられたキーではなく、新しいキーを参照させることも忘れないでください。このようにしないと、MapView 要素には Maps データをダウンロードする許可が与えられません。
        6. +
        7. アプリケーションの署名に使用する非公開キーを変更するには、Google Maps サービスから新しい Maps API キーを取得する必要があります。新しい Maps API キーを取得してすべての MapView 要素に適用してください。以前のキーを参照する MapView 要素には、Maps データをダウンロードする許可が与えられません。
        8. +
        + +

        署名と非公開キーについては、アプリケーションへの署名をご覧ください。

        + + +

        アプリケーションのコンパイル

        + +

        前述のセクションで説明したアプリケーションの準備ができたら、アプリケーションをリリース用にコンパイルできます。

        + +

        アプリケーションをコンパイルした後の作業

        + +

        8. アプリケーションに署名する

        + +

        非公開キーを使用してアプリケーションに署名します。アプリケーションに正しく署名することは、非常に重要です。詳細は、アプリケーションへの署名をご覧ください。

        + +

        9. コンパイルして署名したアプリケーションのテスト

        + +

        コンパイルしたアプリケーションをリリースする前に、対象とする携帯端末(および可能ならば対象ネットワーク)上で徹底的にテストする必要があります。特に、UI 部分の MapView 要素がマップ データを正常に受信していることを確認してください。正常に受信していない場合、Maps API キーに登録するに戻って問題を解決してください。アプリケーションがサーバー側サービスを正しく利用できること、指定データまたは使用データを正しく処理できること、そして認証要件を正常に処理できることも確認してください。

        + +

        これらのテストが完了したら、アプリケーションを携帯端末ユーザーに公開する準備が整ったと言えるでしょう。

        + + diff --git a/docs/html/intl/ja/guide/publishing/versioning.jd b/docs/html/intl/ja/guide/publishing/versioning.jd new file mode 100644 index 0000000000000..bf86016f74280 --- /dev/null +++ b/docs/html/intl/ja/guide/publishing/versioning.jd @@ -0,0 +1,100 @@ +page.title=アプリケーションのバージョニング +@jd:body + +
        +
        + +

        バージョン管理の概略

        + +
          +
        • アプリケーションにはバージョンを設定する必要がある
        • +
        • バージョンは、アプリケーションのマニフェスト ファイルで設定する
        • +
        • アプリケーションのバージョン管理方法は、ユーザーのアップグレード方法に影響
        • +
        • 開発プロセスの初期段階で、今後のリリースの検討事項を含めて、バージョン管理戦略を決定します
        • +
        + +

        このドキュメントの内容

        + +
          +
        1. アプリケーションのバージョンの設定
        2. +
        3. 最小システム API バージョンの指定 +
        + + +

        関連項目

        + +
          +
        1. 公開の準備
        2. +
        3. Android マーケットでの公開
        4. +
        5. The AndroidManifest.xml File
        6. +
        + +
        +
        + +

        バージョン管理のコンポーネントは、アプリケーションのアップグレード及びメンテナンスの計画を立てるのに重要です。

        + +
          +
        • ユーザーは、デバイスにインストールされたアプリケーション バージョンと、インストールが可能なアップグレード バージョンについて、特定の情報が必要です。
        • +
        • スイートとして公開されたその他のアプリケーションなどでは、アプリケーションのバージョンをシステムに問い合わせて、互換性と依存関係を確認する必要があります。
        • +
        • アプリケーションを公開するサービスでは、アプリケーションにバージョンを問い合わせて、バージョンをユーザーに表示できるようにする必要があります。公開サービスでは、互換性を確認してアップグレードとダウングレードの関係を確立するために、アプリケーション バージョンを確認する必要があります。
        • +
        + +

        Android システム自体は、アップグレードや互換性の制約の実施などのために、アプリケーション バージョン情報をアプリケーションに対して確認することはありません。代わりに、アプリケーションにおけるバージョン制約はユーザーまたはアプリケーション自体によって完全に実施されます。

        + +

        Android システムが確認を行うのは、アプリケーションによってマニフェストの minSdkVersion 属性に指定されたシステム バージョン互換性です。この属性によりアプリケーションは互換性を持つ最小システム API を指定できます。詳細は、最小システム API バージョンの指定をご覧ください。 + +

        アプリケーションのバージョンの設定

        +

        アプリケーションのバージョン情報を定義するには、アプリケーションのマニフェスト ファイルで属性を設定します。2 つの属性を使用でき、常にこの両方に値を定義することが推奨されています:

        + +
          +
        • android:versionCode - アプリケーション コードのバージョンを他のバージョンと相対的に示す整数値。 + +

          この値は整数なので、その他のアプリケーションはプログラムでバージョンの値を評価して関係を確認できます(たとえば、このバージョンがアップグレードかダウングレードなのか、など)。任意の整数値を設定できますが、アプリケーションの後続のリリースでは、現在より大きな値を使用するようにしてください。システムではこのバージョン管理の基準を強制しませんが、後継リリースの値を増加させることは標準的です。

          + +

          通常、アプリケーションの最初のバージョンの versionCode を 1 に設定してリリースし、その後は各リリースについて、リリースがメジャー リリースであってもマイナー リリースであっても、値を単調増加させます。これは、android:versionCode の値は、ユーザーに表示されるアプリケーション リリース バージョンと類似している必要性はないことを意味します。以下の android:versionName をご覧ください。アプリケーションと公開サービスでは、このバージョンの値はユーザーには表示されません。

          +
        • +
        • android:versionName - アプリケーション コードのリリース バージョンを表す文字列値で、ユーザーに表示される値です。 +

          値は文字列なので、アプリケーション バージョンを「<major>.<minor>.<point>」といった文字列や、その他のタイプの絶対的または相対的バージョン ID として記述できます。

          + +

          android:versionCode の場合と同様に、システムではこの値をアプリケーションでユーザーに表示する以外の目的で内部的に利用することはありません。公開サービスでは、ユーザーに表示するために android:versionName 値を取り出す可能性もあります。

          +
        • +
        + +

        これらのバージョン属性の両方をマニフェスト ファイルの <manifest> 要素で定義します。

        + +

        ここに、<manifest> 要素の android:versionCodeandroid:versionName 属性を示すマニフェストの例を示します。

        + +
        +<?xml version="1.0" encoding="utf-8"?>
        +<manifest xmlns:android="http://schemas.android.com/apk/res/android"
        +      package="com.example.package.name"
        +      android:versionCode="2"
        +      android:versionName="1.1">
        +    <application android:icon="@drawable/icon" android:label="@string/app_name">
        +        ...
        +    </application>
        +</manifest>
        +
        + +

        この例では、android:versionCode 値は現在の .apk がこのアプリケーション コードの 2 番目のリリースを含んでいることを表し、これは android:codeName 文字列が示すようにマイナー後継リリースであることを示します。

        + +

        Android フレームワークには、アプリケーションがシステムに別のアプリケーションのバージョン情報を問い合わせる API が用意されています。バージョン情報を取得するため、アプリケーションは {@link android.content.pm.PackageManager#getPackageInfo(java.lang.String, int)} +method of {@link android.content.pm.PackageManager PackageManager}.

        を使用します。 + +

        最小システム API バージョンの指定

        + +

        アプリケーションが最低でも Android プラットフォームの特定のバージョンを必要とする場合、このバージョンを API レベルの ID としてアプリケーションのマニフェスト ファイルに指定できます。このようにすると、互換性のあるバージョンの Android システムを実行しているデバイスにのみアプリケーションをインストールできるようになります。

        + +

        最小システム バージョンをマニフェストに指定するには、次の属性を使用します:

        + +
          +
        • android:minSdkVersion - Android プラットフォームのコード バージョンに対応する整数値。 +

          アプリケーションのインストールを準備する際に、システムはこの属性の値を確認して、システム バージョンと比較します。android:minSdkVersion 値がシステム バージョンよりも大きい場合、システムはアプリケーションのインストールを中止します。

          + +

          この属性をマニフェストに指定しない場合、システムではアプリケーションがすべてのプラットフォーム バージョンと互換性があると仮定します。

        • +
        + +

        アプリケーションに最小プラットフォーム バージョンを指定するには、<uses-sdk> 要素を <manifest> の子として追加し、android:minSdkVersion を属性として定義します。

        + +

        詳細は、Android System Image 1.1 Version Notes もご覧ください。

        diff --git a/docs/html/intl/ja/guide/topics/fundamentals.jd b/docs/html/intl/ja/guide/topics/fundamentals.jd new file mode 100644 index 0000000000000..247d076e45251 --- /dev/null +++ b/docs/html/intl/ja/guide/topics/fundamentals.jd @@ -0,0 +1,922 @@ +page.title=開発の基礎 +@jd:body + + + +

        +Android アプリケーションはすべて Java プログラミング言語で記述します。コンパイル済みの Java コード(およびそのアプリケーションに必要なすべてのデータやリソース ファイル)は、aapt ツールを使用して Android パッケージにバンドルします。Android パッケージは、拡張子が {@code .apk} のアーカイブ ファイルです。ユーザーは、このファイルをデバイスにダウンロードして利用します。つまり、Android パッケージは、アプリケーションをモバイル デバイスに配布およびインストールするための媒体として機能します。1 つの {@code .apk} ファイルに含まれているすべてのコードが、1 つのアプリケーションと見なされます。 +

        + +

        +各 Android アプリケーションは、以下に示すさまざまな方法で他のアプリケーションから隔離されています: +

        + +
          +
        • すべてのアプリケーションは、デフォルトではそのアプリケーション個別の Linux プロセスで実行されます。Android は、アプリケーション コードの実行が必要になったときにプロセスを開始し、その必要がなくなって他のアプリケーションからシステム リソースを要求されたときにプロセスを終了します。
        • + +
        • プロセスごとに専用の Java 仮想マシン(VM)が割り当てられるため、アプリケーション コードは他のアプリケーションから隔離された状態で実行されます。
        • + +
        • デフォルトでは、アプリケーションごとに固有の Linux ユーザー ID が割り当てられます。権限が設定されているため、アプリケーションのファイルはそのユーザーからしか認識できず、そのアプリケーション自体からのみ利用できます。ただし、ファイルを他のアプリケーションにエクスポートすることは可能です。
        • +
        + +

        +2 つのアプリケーションで同じユーザー ID を共有することもできます。その場合は、それぞれのアプリケーションのファイルを相互に認識できます。システム リソースを節約するため、同じ ID のアプリケーションで同じ VM を共有し、同じ Linux プロセスで実行することも可能です。 +

        + + +

        アプリケーションのコンポーネント

        + +

        +Android の大きな特長の 1 つは、許可されていれば、あるアプリケーションから別のアプリケーションの要素を利用できる点です。たとえば、開発中のアプリケーションで画像の一覧をスクロール表示したい場合、他のアプリケーションで開発済みの適切なスクローラがあり、その利用が許可されていれば、独自に開発しなくてもそのスクローラを利用できます。アプリケーションに他のアプリケーションのコードを組み込んだり、リンクを設定したりする必要はありません。必要になった時点で、他のアプリケーションの一部分を開始するだけです。 +

        + +

        +この仕組みが機能するには、アプリケーション プロセスの一部分を必要に応じて開始でき、その部分の Java オブジェクトをインスタンス化できなくてはなりません。そのため、Android アプリケーションには、他のシステムで動作するアプリケーションでよく使用されるような、アプリケーション全体にアクセスするための単一のエントリ ポイント(たとえば {@code main()} 関数)はありません。代わりに、システムが必要に応じてインスタンス化して実行できるコンポーネントで構成されます。コンポーネントには以下の 4 つのタイプがあります: +

        + +
        + +
        アクティビティ
        +
        アクティビティは、ユーザーが 1 つの操作を集中的に行うための視覚的なユーザー インターフェースを表します。たとえば、ユーザーが選択できるメニュー アイテムの一覧を表示するアクティビティや、写真をキャプション付きで表示するアクティビティなどが考えられます。SMS アプリケーションなら、あるアクティビティでメッセージを送信する連絡先の一覧を表示し、別のアクティビティで選択した連絡先へのメッセージを入力し、その他のアクティビティで古いメッセージを参照したり設定を変更したりできます。これらのアクティビティを組み合わせて全体としてのユーザー インターフェースを形成しますが、それぞれのアクティビティは相互に独立しています。各アクティビティは、{@link android.app.Activity} 基本クラスのサブクラスとして実装されます。 + +

        +アプリケーションは、1 つのアクティビティで構成することも、上記のSMS アプリケーションのように複数のアクティビティで構成することもできます。どのようなアクティビティがいくつ必要になるかは、アプリケーションやその設計に応じて異なります。通常は、アクティビティのうちのいずれかを最初のアクティビティとして指定し、ユーザーがアプリケーションを起動したときに表示します。あるアクティビティから別のアクティビティに移動するには、現在のアクティビティから次のアクティビティを開始します。 +

        + +

        +各アクティビティには、それを表示するためのデフォルトのウィンドウが割り当てられます。通常はウィンドウを画面全体に表示しますが、画面より小さいウィンドウを他のウィンドウの前面に表示することもできます。アクティビティに、新たなウィンドウを追加することも可能です。たとえば、アクティビティの途中でユーザーの応答を要求するポップアップ ダイアログを表示したり、ユーザーが画面上の特定のアイテムを選択したときに別ウィンドウで重要な情報を表示したりできます。 +

        + +

        +ウィンドウの視覚的なコンテンツは、ビュー({@link android.view.View} 基本クラスの派生オブジェクト)の階層として提供されます。各ビューは、ウィンドウ内の特定の矩形領域を制御します。親ビューは、その子となるビューで構成され、それらの子ビューのレイアウトを決定します。リーフ ビュー(階層の最下位に位置するビュー)は、そのビューが制御する矩形領域に表示され、その領域でのユーザーのアクションに対して応答します。つまり、ビューはアクティビティとユーザーが対話する場所です。たとえば、ビューに小さな画像を表示し、ユーザーがその画像をタップしたら何らかのアクションを開始することもできます。Android には、ボタン、テキスト フィールド、スクロール バー、メニュー アイテム、チェックボックスなど、さまざまなビューがあらかじめ用意されています。 +

        + +

        +ビューの階層は、{@link android.app.Activity#setContentView Activity.setContentView()} メソッドを使用してアクティビティのウィンドウ内に配置します。コンテンツ ビューは、階層のルートとなる View オブジェクトです(ビューおよびその階層について詳しくはUser Interface のドキュメントをご覧ください)。 +

        + +

        サービス
        +
        サービスは、視覚的なユーザー インターフェースを持たず、バックグラウンドにおいて明確な終了期限がなくで実行されます。たとえば、ユーザーが他の操作をしている間 BGM を再生するサービス、ネットワーク経由でデータをフェッチするサービス、何かを計算してその結果をアクティビティに提供するサービスなどが考えられます。各サービスは、{@link android.app.Service} 基本クラスの拡張です。 + +

        +典型的な例としては、プレイリストの曲を再生するメディア プレーヤーが挙げられます。プレーヤー アプリケーションは、ユーザーが曲を選んで再生するための 1 つ以上のアクティビティで構成することが予想されますが、ユーザーはプレーヤーを離れて別の操作に移った後も曲を聞いていたいと考えられることから、曲の再生自体をアクティビティで処理するわけにはいきません。音楽の再生を続けるには、メディア プレーヤー アクティビティから、バックグラウンドで実行するサービスを開始します。音楽再生サービスは、それを開始したアクティビティが画面上に見えなくなった後もそのまま実行されます。 +

        + +

        +また、実行中のサービスに接続(バインド)することもできます(実行されていない場合はそのサービスを開始することも可能です)。接続中は、サービスが公開しているインターフェースを使ってサービスと対話できます。音楽再生サービスであれは、このインターフェースを使って一時停止、巻き戻し、停止、再生の再開などの操作を実行できるようにします。 +

        + +

        +アクティビティや他のコンポーネントと同様に、サービスもアプリケーション プロセスのメイン スレッドで実行します。したがって、サービスによって他のコンポーネントやユーザー インターフェースの実行を妨げられることはなく、時間がかかるタスク(たとえば曲の再生)については、通常は別のスレッドを生成して処理します。詳しくは、プロセスとスレッドをご覧ください。 +

        + +
        ブロードキャスト レシーバ
        +
        ブロードキャスト レシーバは、ブロードキャストの連絡を受信してそれに対処するだけのコンポーネントです。ブロードキャストの多くが元々はシステム コードで、たとえばタイム ゾーンが変更されたこと、電池の残量が少なくなったこと、写真が撮影されたこと、ユーザーが言語設定を変更したことなどを連絡するために使用します。アプリケーションでも、たとえば何らかのデータがデバイスにダウンロードされて利用できるようになったことを、他のアプリケーションにブロードキャストで知らせることができます。 + +

        +アプリケーションでは、重要と思われるすべての連絡に応答できるよう、ブロードキャスト レシーバをいくつでも設定できます。すべてのレシーバは、{@link android.content.BroadcastReceiver} 基本クラスの拡張です。 +

        + +

        +ブロードキャスト レシーバがユーザー インターフェースを表示することはありません。ただし、受信した情報への応答としてアクティビティを開始したり、{@link android.app.NotificationManager} を使用してユーザーにアラートを送信したりすることはあります。通知の際には、バックライトを点滅させる、バイブレーションを起動する、音を鳴らすなど、さまざまな方法でユーザーの注意を喚起できます。通常は、ステータス バーに永続アイコンを表示し、ユーザーがこれを開いてメッセージを取得できるようにします。 +

        + +
        コンテンツ プロバイダ
        +
        コンテンツ プロバイダは、アプリケーションのデータを他のアプリケーションでも利用できるようにします。データは、ファイル システムや SQLite データベースなど、一般に利用できる方法で格納されていれば使用できます。コンテンツ プロバイダは、{@link android.content.ContentProvider} 基本クラスの拡張です。プロバイダが制御する型のデータを、他のアプリケーションから取得および格納するための標準メソッド セットを実装しています。ただし、これらのメソッドをアプリケーションから直接呼び出すことはできません。代わりに、{@link android.content.ContentResolver} オブジェクトのメソッドを呼び出します。ContentResolver は、すべてのプロバイダと通信でき、プロバイダと連携して関係のあるすべてのプロセス間通信を管理します。 + +

        +コンテンツ プロバイダの使用方法について詳しくは、Content Providersのドキュメントをご覧ください。 +

        + +
        + +

        +Android では、特定のコンポーネントで処理すべきリクエストがあると、そのコンポーネントのアプリケーション プロセスが実行中かどうかを確認(必要に応じてプロセスを開始)し、そのコンポーネントの適切なインスタンスが利用可能かどうかを確認(必要に応じてインスタンスを作成)します。 +

        + + +

        コンポーネントのアクティブ化: インテント

        + +

        +コンテンツ プロバイダは、ContentResolver からのリクエストの対象になるとアクティブ化されます。それ以外の 3 つのコンポーネント(アクティビティ、サービス、ブロードキャスト レシーバ)は、インテントと呼ばれる非同期メッセージによってアクティブ化されます。インテントは、メッセージのコンテンツを保持する {@link android.content.Intent} オブジェクトです。アクティビティやサービスの場合の Intent オブジェクトの主な役割は、リクエストされているアクションを指名し、その対象となるデータの URI を指定することです。たとえば、ユーザーに画像を表示するためのリクエストや、ユーザーにテキストを編集させるリクエストをアクティビティに伝達できます。ブロードキャスト レシーバの場合は、Intent オブジェクトがこれから通知を行うアクションを指名します。たとえば、カメラのボタンが押されたことを、関係のあるブロードキャスト レシーバに通知できます。 +

        + +

        +以下に示すように、コンポーネントのタイプごとに別々のアクティブ化メソッドが用意されています: +

        + +
          + +
        • アクティビティを起動する(または何か新しい処理を実行させる)には、Intent オブジェクトを {@link android.content.Context#startActivity +Context.startActivity()} または {@link +android.app.Activity#startActivityForResult +Activity.startActivityForResult()} に渡します。応答アクティビティで {@link android.app.Activity#getIntent getIntent()} メソッドを呼び出すと、最初にそのアクティビティが起動されたときのインテントの内容を確認できます。Android によってアクティビティの {@link +android.app.Activity#onNewIntent onNewIntent()} メソッドが呼び出され、アクティビティが後続のインテントに渡されます。 + +

          +多くの場合、アクティビティから次のアクティビティを開始します。開始するアクティビティから結果が返される場合は、{@code startActivity()} ではなく {@code startActivityForResult()} を呼び出します。たとえば、ユーザーに写真を選択させるアクティビティを開始する場合は、ユーザーによって選択された写真が返されるかもしれません。結果は、呼び出し側のアクティビティの {@link android.app.Activity#onActivityResult +onActivityResult()} メソッドに渡した Intent オブジェクトで返されます。 +

          +
        • + +
        • サービスを開始する(または実行中のサービスに新しい指示を与える)には、{@link +android.content.Context#startService Context.startService()} に Intent オブジェクトを渡します。Android により、サービスの {@link android.app.Service#onStart +onStart()} メソッドが呼び出されて Intent オブジェクトが渡されます。

          + +

          +同様に、インテントを {@link +android.content.Context#bindService Context.bindService()} に渡すと、呼び出し側のコンポーネントと対象となるサービスの間の継続中の接続を確立できます。サービスは、{@link android.app.Service#onBind onBind()} 呼び出しで Intent オブジェクトを受け取ります(サービスがまだ開始されていない場合は、必要に応じて {@code bindService()} で開始できます)。たとえば、上で例に挙げた音楽再生サービスとの接続を確立するアクティビティを使用して、ユーザーが再生を操作するための手段(ユーザー インターフェース)を提供できます。アクティビティで {@code bindService()} を呼び出して接続を確立してから、サービスに定義されているメソッドを呼び出して再生を操作します。 +

          + +

          +サービスのバインドについては、後ほどリモート プロシージャ コールのセクションで詳しく説明します。 +

          +
        • + +
        • アプリケーションでブロードキャストを開始するには、{@link +android.content.Context#sendBroadcast(Intent) Context.sendBroadcast()}{@link android.content.Context#sendOrderedBroadcast(Intent, String) +Context.sendOrderedBroadcast()}{@link +android.content.Context#sendStickyBroadcast Context.sendStickyBroadcast()} などのメソッドのいずれかのバリエーションに Intent オブジェクトを渡します。Android によって {@link +android.content.BroadcastReceiver#onReceive onReceive()} メソッドが呼び出され、関係のあるすべてのブロードキャスト レシーバにインテントが配信されます。

        • + +
        + +

        +インテント メッセージについて詳しくは、Intents and Intent Filters をご覧ください。 +

        + + +

        コンポーネントの終了

        + +

        +コンテンツ プロバイダは、ContentResolver からのリクエストに応答している間のみアクティブになります。ブロードキャスト レシーバは、ブロードキャスト メッセージに応答している間のみアクティブになります。つまり、これらのコンポーネントを明示的に終了させる必要はありません。 +

        + +

        +一方、アクティビティはユーザー インターフェースを提供します。長い時間をかけてユーザーと会話するためのものであり、待機状態の間も、会話が続いてきる限りはアクティブなままになっている可能性があります。同様に、サービスも長い間実行されたままになる可能性があります。Android には、アクティビティとサービスを以下のような規則的な方法で終了させるためのメソッドが用意されています: +

        + +
          +
        • アクティビティを終了させるには、その {@link android.app.Activity#finish finish()} メソッドを呼び出します。あるアクティビティから {@code startActivityForResult()} で開始した別のアクティビティは、{@link android.app.Activity#finishActivity finishActivity()} を呼び出して終了させることができます。
        • + +
        • サービスは、その {@link android.app.Service#stopSelf stopSelf()} メソッドを呼び出すか、{@link android.content.Context#stopService Context.stopService()} を呼び出すことで停止できます。
        • +
        + +

        +コンポーネントが、既に利用されていない場合や、Android がよりアクティブな他のコンポーネントにメモリを割り当てる必要がある場合は、システムがコンポーネントを終了させることもあります。このような状況およびその影響については、コンポーネントのライフサイクルで詳しく説明します。 +

        + + +

        マニフェスト ファイル

        + +

        +アプリケーション コンポーネントを開始するには、Android がそのコンポーネントの存在を認識している必要があります。アプリケーションのコンポーネントは、マニフェスト ファイルで宣言します。このファイルは、アプリケーションのコード、ファイル、リソースなどとともに Android パッケージ({@code .apk} ファイル)にバンドルされます。 +

        + +

        +マニフェストは構造化された XML ファイルで、どのアプリケーションでも常に AndroidManifest.xml という名前になります。アプリケーション コンポーネントの宣言以外にも、アプリケーションをリンクさせる必要のあるライブラリ(デフォルトの Android ライブラリを除く)の指定や、アプリケーションに付与されるべき権限の指定などにも使用します。 +

        + +

        +しかし、マニフェストの最も重要な役割は、アプリケーションのコンポーネントに関する情報を Android に提供することです。たとえば、アクティビティを次のように宣言できます: +

        + +
        <?xml version="1.0" encoding="utf-8"?>
        +<manifest . . . >
        +    <application . . . >
        +        <activity android:name="com.example.project.FreneticActivity"
        +                  android:icon="@drawable/small_pic.png"
        +                  android:label="@string/freneticLabel" 
        +                  . . .  >
        +        </activity>
        +        . . .
        +    </application>
        +</manifest>
        + +

        +<activity> 要素の {@code name} 属性は、そのアクティビティを実装する {@link android.app.Activity} サブクラスを指名します。{@code icon} および {@code label} 属性には、ユーザーに対して表示するアイコンやラベルが保持されているリソース ファイルを指定します。 +

        + +

        +その他のコンポーネントも、サービスは <service> 要素、ブロードキャスト レシーバは <receiver> 要素、コンテンツ プロバイダは <provider> 要素を使用して同じような方法で宣言します。マニフェストに宣言されていないアクティビティ、サービス、およびコンテンツ プロバイダは、システムから認識できないため実行されることはありません。ただし、ブロードキャスト レシーバの場合は、マニフェストで宣言する方法と、コード内で {@link android.content.BroadcastReceiver} オブジェクトとして動的に作成し、{@link android.content.Context#registerReceiver Context.registerReceiver()} を呼び出してシステムに登録する方法があります。 +

        + +

        +マニフェスト ファイルの作成方法について詳しくは、The AndroidManifest.xml Fileをご覧ください。 +

        + + +

        インテント フィルタ

        + +

        +Intent オブジェクトでは、対象とするコンポーネントを明示的に指名できます。明示的に指名されている場合、Android はマニフェスト ファイル内の宣言に基づいてコンポーネントを特定してアクティブにします。一方、明示的に指名されていない場合は、そのインテントに応答する上で最適なコンポーネントが選択されます。方法としては、Intent オブジェクトを、その対象となりうるコンポーネントのインテント フィルタと照合します。コンポーネントのインテント フィルタは、そのコンポーネントで処理できるインテントの種類を示します。これもコンポーネントに関する重要な情報の 1 つなので、マニフェスト ファイルで宣言します。次に、上に示した例を拡張して 2 つのインテント フィルタを追加したアクティビティを示します: +

        + +
        <?xml version="1.0" encoding="utf-8"?>
        +<manifest . . . >
        +    <application . . . >
        +        <activity android:name="com.example.project.FreneticActivity"
        +                  android:icon="@drawable/small_pic.png"
        +                  android:label="@string/freneticLabel" 
        +                  . . .  >
        +            <intent-filter . . . >
        +                <action android:name="android.intent.action.MAIN" />
        +                <category android:name="android.intent.category.LAUNCHER" />
        +            </intent-filter>
        +            <intent-filter . . . >
        +                <action android:name="com.example.project.BOUNCE" />
        +                <data android:mimeType="image/jpeg" />
        +                <category android:name="android.intent.category.DEFAULT" />
        +            </intent-filter>
        +        </activity>
        +        . . .
        +    </application>
        +</manifest>
        + +

        +この例の 1 つ目のフィルタは、アクション「{@code android.intent.action.MAIN}」とカテゴリ「{@code android.intent.category.LAUNCHER}」を組み合わせた一般的なフィルタです。このフィルタは、アプリケーション ランチャ(ユーザーがデバイス上で起動できるアプリケーションを一覧表示した画面)に、このアクティビティを表示する必要があることを示しています。つまり、このアクティビティはアプリケーションへのエントリ ポイントとして機能し、ユーザーがランチャでそのアプリケーションを選択したときに最初に表示されるということです。 +

        + +

        +2 つ目のフィルタでは、アクティビティが特定のタイプのデータに対して実行できるアクションを宣言しています。 +

        + +

        +コンポーネントにはインテント フィルタをいくつでも指定でき、それぞれのフィルタで別々の機能を宣言できます。フィルタが 1 つも指定されていないコンポーネントは、そのコンポーネントが対象として明示的に指名されているインテントでのみアクティブにできます。 +

        + +

        +コード内で作成して登録したブロードキャスト レシーバの場合、インテント フィルタは {@link android.content.IntentFilter} オブジェクトとして直接インスタンス化されます。それ以外の全てのフィルタは、マニフェストで設定します。 +

        + +

        +インテント フィルタについて詳しくは、Intents and Intent Filters をご覧ください。 +

        + + +

        アクティビティとタスク

        + +

        +既に説明したように、あるアクティビティから別のアクティビティを開始することができます。これには、別のアプリケーションで定義されているアクティビティも含まれます。たとえば、ユーザーに特定の場所の地図を表示するとします。そのためのアクティビティは既に存在しているので、現在のアクティビティで必要な情報を Intent オブジェクトに格納して {@code startActivity()} に渡すだけで、マップ ビューアに地図を表示できます。ユーザーが [戻る] キーを押すと、画面に元のアクティビティが再表示されます。 +

        + +

        +この場合、マップ ビューアは別のアプリケーションで定義されており、そのアプリケーションのプロセスで実行されていますが、ユーザーにとってはマップ ビューアが元のアプリケーションの一部であるかのように感じられます。Android では、両方のアクティビティを同じタスクに組み込むことで、このようなユーザー エクスペリエンスを実現できます。簡単に言えば、ユーザーが 1 つの「アプリケーション」と感じるものがタスクです。関連するアクティビティをスタックにまとめたものがタスクです。スタック内のルート アクティビティは、タスクを開始するアクティビティです。通常であれば、ユーザーがアプリケーション ランチャで選択するアクティビティがこれに相当します。スタックの最上位にあるアクティビティは、ユーザーのアクションの焦点となっている実行中のアクティビティです。あるアクティビティから別のアクティビティを開始すると、そのアクティビティが新たにスタックにプッシュされて実行中のアクティビティになります。1 つ前のアクティビティはスタック内に残されています。ユーザーが [[]戻る] キーを押すと、現在のアクティビティがスタックからポップされ、1 つ前のアクティビティが実行中のアクティビティとして再開されます。 +

        + +

        +スタックはオブジェクトを保持します。したがって、同じ Activity サブクラスのインスタンス(たとえばマップ インスタンス)を複数開くと、それぞれのインスタンスが別々のエントリになります。スタック内のアクティビティは、プッシュまたはポップされるのみで再配置されることはありません。 +

        + +

        +タスクはアクティビティのスタックであり、マニフェスト ファイル内のクラスや要素ではありません。したがって、アクティビティと無関係にタスクの値を設定することはできません。タスクの値は、ルート アクティビティでまとめて設定します。たとえば、次のセクションでは「タスクの親和性」について説明しますが、値はタスクのルート アクティビティの親和性のセットから読み込まれます。 +

        + +

        +タスク内のアクティビティは、1 つのユニットとして一緒に移動します。タスク全体(アクティビティ スタック全体)をフォアグラウンドに移動したり、バックグラウンドに移動したりできます。たとえば、現在のタスクは 4 つのアクティビティからなるスタックで、現在のアクティビティの下にアクティビティが 3 つあるとします。ここで、ユーザーが [ホーム] キーを押してアプリケーション ランチャに移動し、新しいアプリケーション(実際には新しいタスク)を選択したとします。すると、現在のタスクはバックグラウンドに移動し、新しいタスクのルート アクティビティが表示されます。しばらくして、ユーザーがホーム画面に戻り 1 つ前のアプリケーション(タスク)を選択すると、そのタスクがスタック内の 4 つのアクティビティとともにフォアグラウンドに移動します。ここでユーザーが [戻る] キーを押しても、中断したばかりのアプリケーション(1 つ前のタスクのルート アクティビティ)は表示されません。代わりに、スタックの最上位のアクティビティがポップされ、同じタスクの 1 つ前のアクティビティが表示されます。 +

        + +

        +アクティビティとタスクの動作としては、ここで説明した動作がデフォルトです。ただし、この動作のほとんどの要素は変更可能です。タスクとアクティビティの関連付けやタスク内でのアクティビティの動作は、アクティビティを開始した Intent オブジェクトのフラグ セットと、マニフェストに指定されているアクティビティの <activity> 要素の属性セットとの相互作用によって決まります。リクエスト側と応答側の両方が動作に影響を及ぼします。 +

        + +

        +この点において、主に使用する Intent フラグは以下のとおりです: + +

        {@code FLAG_ACTIVITY_NEW_TASK}
        {@code FLAG_ACTIVITY_CLEAR_TOP}
        {@code FLAG_ACTIVITY_RESET_TASK_IF_NEEDED}
        {@code FLAG_ACTIVITY_SINGLE_TOP}

        + +

        +また、主に使用する {@code <activity>} 属性は以下のとおりです: + +

        {@code taskAffinity}
        {@code launchMode}
        {@code allowTaskReparenting}
        {@code clearTaskOnLaunch}
        {@code alwaysRetainTaskState}
        {@code finishOnTaskLaunch}

        + +

        +以降のセクションでは、これらのフラグや属性の役割、相互作用の仕組み、使用する際の留意事項などについて説明します。 +

        + + +

        親和性と新しいタスク

        + +

        +デフォルトでは、アプリケーション内のすべてのアクティビティは相互に親和性があり、すべてのアクティビティができる限り同じタスクに属そうとします。ただし、{@code <activity>} 要素の {@code taskAffinity} 属性を使用して、アクティビティごとに個別の親和性を設定することもできます。つまり、別々のアプリケーションで定義されているアクティビティで親和性を共有したり、同じアプリケーションで定義されているアクティビティに別々の親和性を割り当てたりできるということです。親和性が作用する状況は 2 つあります。1 つはアクティビティを起動する Intent オブジェクトに {@code FLAG_ACTIVITY_NEW_TASK} フラグが含まれている場合、もう 1 つはアクティビティの {@code allowTaskReparenting} 属性が "{@code true}" に設定されている場合です。 +

        + +
        +
        {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} フラグ
        +
        既に説明したとおり、新しいアクティビティは、デフォルトでは {@code startActivity()} を呼び出したアクティビティのタスクの一部として起動します。つまり、呼び出し側のアクティビティと同じスタックにプッシュされるということです。しかし、{@code startActivity()} に渡された Intent オブジェクトに {@code FLAG_ACTIVITY_NEW_TASK} フラグが含まれている場合、システムはその新しいアクティビティを別のタスクに収容しようとします。フラグの名前からも判断できますが、ほとんどの場合は新しいタスクが開始されます。ただし常にそうなるとは限りません。既存のタスクに新しいアクティビティと同じ親和性が割り当てられている場合、そのアクティビティはそのタスクの一部として起動します。そうでない場合には、新しいタスクが開始されます。
        + +
        allowTaskReparenting 属性
        +
        {@code allowTaskReparenting} 属性が "{@code true}" に設定されているアクティビティは、そのアクティビティと親和性のあるタスクがフォアグラウンドに移ったときに、アクティビティを開始したタスクから親和性のあるタスクに移動できます。たとえば、旅行アプリケーションの一部として、選択された都市の天気予報を表示するアクティビティが定義されているとします。このアクティビティには、同じアプリケーション内の他のアクティビティと同じ親和性(デフォルトの親和性)が割り当てられていますが、その親の割り当てを変更することも可能です。あるアクティビティが天気予報アクティビティを開始すると、その時点では開始側のアクティビティと同じタスクに属した状態になります。しかし、次に旅行アプリケーションがフォアグラウンドに移ると、天気予報アクティビティの割り当てが変更され、旅行アプリケーションのタスクの一部として表示されます。
        +
        + +

        +ユーザーから見て複数の「アプリケーション」が 1 つの {@code .apk} ファイルに含まれている場合は、それぞれのアプリケーションに関連付けられているアクティビティに別々の親和性を割り当てることをおすすめします。 +

        + + +

        起動モード

        + +

        +launchMode 属性の {@code <activity>} 要素には、以下の 4 種類の起動モードを割り当てることができます: +

        + +

        "{@code standard}"(デフォルト モード)
        "{@code singleTop}"
        "{@code singleTask}"
        "{@code singleInstance}"

        + +

        +これらのモードは、それぞれが以下の 4 つの点で異なります: +

        + +
          + +
        • インテントに応答するアクティビティをどのタスクに保持するか。"{@code standard}" および "{@code singleTop}" モードの場合は、そのインテントを開始した(つまり {@link android.content.Context#startActivity startActivity()} を呼び出した)タスクに保持されます。ただし、Intent オブジェクトに {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} フラグが含まれている場合は、前のセクション親和性と新しいタスクで説明したとおり、別のタスクが選択されます。 + +

          +一方、"{@code singleTask}" および "{@code singleInstance}" モードの場合は、アクティビティが常にタスクのルート アクティビティになります。タスクは定義されており、他のタスクの一部として起動されることはありません。 +

          + +
        • アクティビティのインスタンスを複数生成できるか。"{@code standard}" または "{@code singleTop}" アクティビティは複数回インスタンス化できます。それらのインスタンスを複数のタスクに割り当てることも、特定のタスクに同じアクティビティの複数のインスタンスを割り当てることも可能です。 +

          + +

          +一方、"{@code singleTask}" および "{@code singleInstance}" アクティビティのインスタンスは 1 つに制限されます。これらのアクティビティはタスクのルートに当たります。したがって、これらのタスクの複数のインスタンスがデバイス上に同時に存在することはないということになります。 +

          + +
        • インスタンスのタスクに他のアクティビティを含めることができるか。"{@code singleInstance}" アクティビティは、そのタスク内の唯一のアクティビティとして単独で動作します。ここから別のアクティビティを開始した場合、そのアクティビティは起動モードに関係なく、あたかもインテントに {@code FLAG_ACTIVITY_NEW_TASK} フラグが含まれているかのように別のタスクで起動します。"{@code singleInstance}" モードと "{@code singleTask}" モードは、これ以外の点ではまったく同じです。

          + +

          +他の 3 つのモードでは、タスクに複数のアクティビティを割り当てることができます。"{@code singleTask}" アクティビティは、常にタスクのルート アクティビティになりますが、同じタスクに割り当てることになる別のアクティビティを開始することができます。"{@code standard}" および "{@code singleTop}" アクティビティのインスタンスは、スタック内のどの位置にでも配置できます。 +

        • + +
        • クラスの新しいインスタンスを起動して新しいインテントを処理するかどうか。デフォルトの "{@code standard}" モードの場合は、新しいインテントに応答するときには必ず新しいインスタンスが作成されます。それぞれのインスタンスで処理するインテントは 1 つのみです。"{@code singleTop}" モードの場合は、クラスの既存のインスタンスが対象タスクのアクティビティ スタックの最上位にあれば、それを再利用して新しいインテントを処理します。スタックの最上位にない場合は再利用されません。代わりに、新しいインスタンスが作成されてスタックにプッシュされ、新しいインテントの処理に使用されます。 + +

          +たとえば、タスクのアクティビティ スタックに、ルート アクティビティ A とアクティビティ B、C、D が含まれているとします。スタック内のアクティビティの順序は A-B-C-D で D が最上位です。ここに、アクティビティのタイプが D のインテントが届きます。D の起動モードがデフォルトの "{@code standard}" である場合は、そのクラスの新しいインスタンスが起動し、スタックは A-B-C-D-D となります。しかし、D の起動モードが "{@code singleTop}" であれば、スタックの最上位は D なので、新しいインテントは既存のインスタンスによって処理されるはずです。したがって、スタックは A-B-C-D のままとなります。 +

          + +

          +一方、届いたインテントのアクティビティ タイプが B だった場合は、B のモードが "{@code standard}" であっても "{@code singleTop}"であっても B の新しいインスタンスが起動します。これは B がスタックの最上位ではないためで、結果としてスタックは A-B-C-D-B となります。 +

          + +

          +"{@code singleTask}" または "{@code singleInstance}" アクティビティの場合は、既に説明したとおり同時に複数のインスタンスが存在することはないため、インスタンスは常に新しいインテントを処理することになります。"{@code singleInstance}" アクティビティはスタック内の唯一のアクティビティであるため、常にスタックの最上位、つまりインテントを処理する位置にあります。一方、"{@code singleTask}" アクティビティは、スタック内の上位に他のアクティビティがある場合とない場合があります。上位にアクティビティがある場合、インテントを処理する位置にはないため、そのインテントはドロップされます(インテントがドロップされたとしても、そのインテントが届いたことによって、タスクがフォアグラウンドに移ったままの状態になります)。 +

          +
        • + +
        + +

        +既存のアクティビティで新しいインテントを処理することになった場合は、{@link android.app.Activity#onNewIntent onNewIntent()} の呼び出しによって Intent オブジェクトがアクティビティに渡されます(最初にアクティビティを開始したインテント オブジェクトは {@link android.app.Activity#getIntent getIntent()} を呼び出して取得できます)。 +

        + +

        +なお、新しいインテントを処理するためにアクティビティの新しいインスタンスが作成された場合、ユーザーは [[]戻る] キーを押して 1 つ前の状態(1 つ前のアクティビティ)に戻ることができます。しかし、アクティビティの既存のインスタンスで新しいインテントを処理する場合は、[[]戻る] キーを押しても、新しいインテントが届く前にそのインスタンスで処理していた作業に戻ることはできません。 +

        + +

        +起動モードについて詳しくは、<activity> 要素の説明をご覧ください。 +

        + + +

        スタックのクリア

        + +

        +ユーザーがタスクを長時間放置すると、タスクのルート アクティビティを除くすべてのアクティビティがクリアされます。ユーザーがタスクに戻ると、タスクは以前のように表示されますが、残っているのは最初のアクティビティだけです。つまり、一定の時間が経過していればユーザーは以前の作業を放棄していて、新しい作業をするためにそのタスクに戻ってきたと考えるわけです。 +

        + +

        +これがデフォルトです。この動作を変更したい場合は、以下のアクティビティ属性を使用します: +

        + +
        +
        alwaysRetainTaskState 属性
        +
        タスクのルート アクティビティでこの属性を "{@code true}" に設定すると、上で説明したデフォルトの動作は発生しません。長時間経過しても、タスク内のすべてのアクティビティはそのまま残されます。
        + +
        clearTaskOnLaunch 属性
        +
        タスクのルート アクティビティでこの属性を "{@code true}" に設定した場合、ユーザーがいったんタスクを離れると、戻ったときにはルートを含むすべてのアクティビティがクリアされています。つまり、{@code alwaysRetainTaskState} の正反対の動作になります。ユーザーが一瞬でもタスクを離れると、最初の状態からやり直すことになります。
        + +
        finishOnTaskLaunch 属性
        +
        この属性は {@code clearTaskOnLaunch} に似ていますが、タスク全体ではなく単一のアクティビティに作用します。また、ルート アクティビティを含むどのアクティビティもクリアの対象となりえます。この属性が "{@code true}" に設定されたアクティビティは、現在のセッションの間のみタスクの一部を形成します。ユーザーがいったんそのタスクから離れてから、再度タスクに戻ると、このアクティビティはクリアされています
        +
        + +

        +アクティビティをスタックから削除する方法は他にもあります。Intent オブジェクトに {@link +android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP FLAG_ACTIVITY_CLEAR_TOP} フラグが含まれており、そのインテントを処理すべきタイプのアクティビティのインスタンスが対象タスクのスタック内に存在する場合は、そのインスタンスがスタックの最上位になってインテントに応答できるよう、それより上位のアクティビティはすべてクリアされます。指定されたアクティビティの起動モードが "{@code standard}" である場合は、そのアクティビティもスタックから削除され、新しいインスタンスが起動してインテントを処理します。起動モード "{@code standard}" では、新しいインテントを処理する際、常に新しいインスタンスが作成されるためです。 +

        + +

        +{@code FLAG_ACTIVITY_CLEAR_TOP} は、ほとんどの場合 {@code FLAG_ACTIVITY_NEW_TASK} と組み合わせて使用します。これらのフラグを組み合わせると、別のタスクに既に存在しているアクティビティを探し、それをインテントに応答できる位置に配置できます。 +

        + + +

        タスクの開始

        + +

        +アクティビティをタスクのエントリ ポイントとして設定するには、アクションとして "{@code android.intent.action.MAIN}"、カテゴリとして "{@code android.intent.category.LAUNCHER}" を指定したインテント フィルタをアクティビティに追加します(このタイプのフィルタの例については、インテント フィルタをご覧ください)。このタイプのフィルタを追加すると、アクティビティのアイコンとラベルがアプリケーション ランチャに表示されます。これにより、ユーザーがタスクを起動するための手段を提供できるだけでなく、起動後はいつでもそのタスクに戻れるようにすることができます。 +

        + +

        +この 2 番目の機能、つまりユーザーがいったんタスクを離れても後で戻ることができるようにする点が重要です。この理由から、アクティビティに {@code MAIN} と {@code LAUNCHER} フィルタが指定されている場合は、必ずタスクが開始される起動モード("{@code singleTask}" または "{@code singleInstance}")を使用する必要があります。たとえば、このフィルタを指定しなかった場合を考えてみましょう。インテントが "{@code singleTask}" アクティビティを起動し、新しいタスクが開始され、ユーザーがしばらくの間このタスクで作業を行います。その後、ユーザーが [ホーム] キーを押したとします。ホーム画面が表示され、先ほどのタスクはバックグラウンドに移動します。しかし、このタスクはアプリケーション ランチャには表示されていないため、ユーザーがタスクに戻るための手段がありません。 +

        + +

        +{@code FLAG_ACTIVITY_NEW_TASK} フラグにも、これと同じような難しさがあります。このフラグを指定したアクティビティでは、新しいタスクを開始した後にユーザーが [ホーム] キーを押してそのタスクを離れた場合に備え、タスクに戻るための手段を用意しておく必要があります。一部のエンティティ(たとえば通知マネージャ)は、アクティビティを常に外部タスクとして開始します。エンティティの一部として開始することはないため、{@code startActivity()} に渡すインテントには必ず {@code FLAG_ACTIVITY_NEW_TASK} を指定します。外部エンティティから呼び出すことのできるアクティビティでこのフラグが使用されている可能性がある場合は、開始されたタスクにユーザーが戻るための手段を別途提供するようにしてください。 +

        + +

        +ユーザーがアクティビティに戻ることができるようにしない場合は、{@code <activity>} 要素の {@code finishOnTaskLaunch} を "{@code true}" に設定します。詳しくは、スタックのクリアをご覧ください。 +

        + + +

        プロセスとスレッド

        + +

        +Android では、最初のアプリケーション コンポーネントを実行する必要が生じると、そのための Linux プロセスを単一の実行スレッドで開始します。デフォルトでは、アプリケーションのすべてのコンポーネントがそのプロセスとスレッドで実行されます。 +

        + +

        +ただし、コンポーネントが他のプロセスで実行されるようにしたり、特定のプロセスに使用する追加スレッドを生成したりすることも可能です。 +

        + + +

        プロセス

        + +

        +コンポーネントを実行するプロセスは、マニフェスト ファイルで管理します。コンポーネントの各要素({@code <activity>}、{@code <service>}、{@code <receiver>}、および {@code <provider>})には {@code process} 属性があり、そのコンポーネントをどのプロセスで実行すべきかを指定できるようになっています。これらの属性の設定によって、それぞれのコンポーネントを専用のプロセスで実行したり、一部のコンポーネントだけでプロセスを共有したりできます。また、別々のアプリケーションのコンポーネントが、同じプロセスで実行されるように設定することもできます。この場合は、それらのアプリケーションが同じ Linux ユーザー ID を共有し、同じ認証機関によって署名されている必要があります。{@code <application>} 要素にも {@code process} 属性があり、すべてのコンポーネントに適用されるデフォルト値を設定できます。 +

        + +

        +すべてのコンポーネントは指定されたプロセスのメイン スレッドでインスタンス化され、コンポーネントに対するシステム コールはそのスレッドからディスパッチされます。1 つのインスタンスに対して、複数のスレッドが作成されることはありません。したがって、システム コールに応答するメソッド(たとえば、後ほどコンポーネント ライフサイクルで説明するライフサイクル通知や、ユーザーのアクションを報告する {@link android.view.View#onKeyDown View.onKeyDown()} のようなメソッド)は、常にそのプロセスのメイン スレッドで実行されます。つまり、コンポーネントがシステムから呼び出されたときに、プロセス内の他のコンポーネントの実行を妨げないよう、実行に時間がかかる処理や他の妨げになることの多い処理(ネットワーク処理、ループ計算など)をできる限り避ける必要があるということです。時間がかかる処理には別のスレッドを生成できます。詳しくは、次のスレッド セクションをご覧ください。 +

        + +

        +状況によっては、Android がプロセスを終了させるべきと判断する場合があります。たとえば、メモリが不足してきた場合や、他のプロセスでユーザーにすばやく応答する必要がある場合です。プロセスが終了すると、そのプロセス内で実行されているアプリケーション コンポーネントは破棄されます。それらのコンポーネントで処理する作業がもう一度発生すると、そのためのプロセスが再び開始されます。 +

        + +

        +Android では、どのプロセスを終了させるかを判断するため、ユーザーにとっての相対的な重要度を重み付けして管理します。たとえば、アクティビティがまだ画面に表示されているプロセスを終了させるよりも、アクティビティが画面に表示されていないプロセスを終了させる方が合理的です。したがって、プロセスを終了させるかどうかは、そのプロセスで実行されているコンポーネントの状態に応じて判断されるということです。コンポーネントの状態については、後ほどコンポーネントのライフサイクルで詳しく説明します。 +

        + + +

        スレッド

        + +

        +アプリケーションを単一のプロセスに限定したとしても、バックグラウンドでの処理にスレッドが必要になることはよくあります。ユーザー インターフェースはユーザーのアクションに対して常にすばやく応答できなければならないため、アクティビティをホストするスレッドで、ネットワーク ダウンロードのような時間のかかる処理を一緒にホストしないようにする必要があります。すぐに完了しない可能性のあるすべての処理は、別のスレッドに割り当てるようにしてください。 +

        + +

        +スレッドは、標準の Java {@link java.lang.Thread} オブジェクトを使用してコード内で作成します。Android には、スレッドを管理するための便利なクラスが数多く用意されています。たとえば、スレッド内でメッセージ ループを実行するための {@link android.os.Looper}、メッセージを処理するための {@link android.os.Handler}、メッセージ ループでスレッドを設定するための {@link android.os.HandlerThread} などがあります。 +

        + + +

        リモート プロシージャ コール

        + +

        +Androidは軽量な仕組みのリモート・プロシージャ・コール (RPC) を採用しています。RPC とは、メソッドをローカルで呼び出しますが、実行はリモート(別のプロセス)で行い、その結果を呼び出し側に返します。そのためには、メソッド呼び出しとそれに付随するデータをオペレーティングシステムが解釈できるレベルまで分解してから、それらをローカルのプロセスとアドレス空間からリモートのプロセスとアドレス空間に転送し、リモートで呼び出しを再構築する必要があります。戻り値は、反対方向に転送しなければなりません。Android にはこの処理を行うためのコードがすべて用意されているため、RPC インターフェースを定義して実装するだけで RPC を利用できます。 +

        + +

        +RPC インターフェースに含めることができるのはメソッドのみです。すべてのメソッドは、戻り値がない場合でも同期的に実行されます(つまり、リモート メソッドが完了するまでローカル メソッドがブロックされます)。 +

        + +

        +このメカニズムを簡単に説明すると次のようになります。まず、シンプルなインターフェース定義言語(IDL)を使用して、実装したい RPC インターフェースを宣言します。aidl ツールにより、RPC インターフェースの宣言から Java インターフェース定義が生成されます。この定義は、ローカルとリモートの両方のプロセスで使用する必要があります。定義には、次の図に示すように 2 つの内部クラスが含まれています: +

        + +

        +RPC のメカニズム +

        + +

        +これらの内部クラスには、IDL で宣言したインターフェースのリモート プロシージャ コールを管理するために必要なコードがすべて含まれています。どちらの内部クラスも {@link android.os.IBinder} インターフェースを実装します。一方の内部クラスは、ローカルのシステムで内部的に使用しますが、記述するコードでは無視しても構いません。もう一方の内部クラスはスタブと呼ばれ、{@link android.os.Binder} クラスを拡張します。スタブには、IPC(プロセス間通信)呼び出しを発生させるための内部コードに加え、IDL で宣言した RPC インターフェース内のメソッドの宣言が含まれます。これらのメソッドを実装するには、図に示すようにスタブをサブクラス化します。2つの内部クラスのうちの一方は、システムがローカルかつ内部的に使用するので、開発者が記述するコードでは無視してかまいません。... リモート側では、図のようにスタブをサブクラス化して、これらのメソッドを実装する必要があります。 +

        + +

        + 通常、リモート プロセスはサービスで管理します。サービスなら、プロセスや他のプロセスへの接続に関する情報をシステムに伝えることができるからです。サービスには、{@code aidl} ツールで生成されたインターフェース ファイルと、RPC メソッドを実装するスタブ サブクラスの両方を持たせることになります。サービスのクライアントには、{@code aidl} ツールで生成されたインターフェース ファイルのみを持たせます。 +

        + +

        +以下に、サービスとそのクライアントの間の接続がどのように設定されるかを示します: +

        + +
          +
        • サービスのクライアント(ローカル側)には {@link android.content.ServiceConnection#onServiceConnected +onServiceConnected()} および{@link android.content.ServiceConnection#onServiceDisconnected +onServiceDisconnected()} メソッドが実装されているため、リモート サービスとの接続が確立されたときや切断されたときには通知を受けることができます。通知があり次第、{@link android.content.Context#bindService bindService()} を呼び出して接続を設定します。 +
        • + +
        • +サービスの {@link android.app.Service#onBind onBind()} メソッドは、受け取ったインテント({@code bindService()} に渡されたインテント)に応じて、接続を承認または拒否するために実装します。接続が承認されると、接続を承認するのであれば、スタブ サブクラスのインスタンスを返します。 +
        • + +
        • サービスが接続を承認すると、Android がクライアントの {@code onServiceConnected()} メソッドを呼び出し、IBinder オブジェクト(サービスが管理するスタブ サブクラスのプロキシ)を渡します。クライアントは、このプロキシを介してリモートサービスを呼び出すことができます。 +
        • +
        + +

        +ここでは、説明を簡単にするため、RPC メカニズムの細かい点は省略しています。詳しくは、Designing a Remote Interface Using AIDL、および {@link android.os.IBinder IBinder} クラスの説明をご覧ください。 +

        + + +

        スレッドセーフなメソッド

        + +

        +状況によっては実装したメソッドが複数のスレッドから呼び出されることもあるため、スレッドセーフな記述を心掛ける必要があります。 +

        + +

        +前のセクションで説明した RPC のようにメソッドをリモートで呼び出すことができる場合は、このような状況が特に発生しやすくなります。IBinder オブジェクトに実装されているメソッドを IBinder と同じプロセスから呼び出すと、そのメソッドは呼び出し側のスレッドで実行されます。一方、別のプロセスからメソッドを呼び出した場合は、プロセスのメイン スレッドではなく、IBinder と同じプロセス内に保持されているスレッドのプールから選択されたスレッドで実行されます。たとえば、サービスの {@code onBind()} メソッドはそのサービスのプロセスのメイン スレッドから呼び出されるのに対し、{@code onBind()} から返されたオブジェクトに実装されているメソッド(たとえば RPC メソッドを実装するスタブ サブクラス)はプール内のスレッドから呼び出されます。サービスには複数のクライアントを割り当てることができるため、複数のプール スレッドを同じ IBinder に同時に割り当てることも可能です。したがって、IBinder メソッドはスレッドセーフになるように実装する必要があります。 +

        + +

        +同様に、コンテンツ プロバイダも別のプロセスからのデータ リクエストを受け取ることができます。ContentResolver および ContentProvider クラスはプロセス間通信の管理の詳細を隠蔽しますが、それらのリクエストに応答する ContentProvider メソッド({@link android.content.ContentProvider#query query()}{@link android.content.ContentProvider#insert insert()}{@link android.content.ContentProvider#delete delete()}{@link android.content.ContentProvider#update update()}、および {@link android.content.ContentProvider#getType getType()} メソッド)は、プロセスのメイン スレッドではなく、コンテンツ プロバイダのプロセス内のスレッドのプールから呼び出されます。これらのメソッドを同時に呼び出すことのできるメソッドの数に制限はありません。したがって、これらのメソッドもスレッドセーフになるように実装する必要があります。 +

        + + +

        コンポーネントのライフサイクル

        + +

        +アプリケーション コンポーネントにはライフサイクルがあります。ライフサイクルは、インテントへ応答することでのインスタンス化で始まり、そのインスタンスの破棄で終わります。この間、コンポーネントがアクティブなときとアクティブでないときがあり、アクティビティであればユーザーから見えるときと見えないときがあります。このセクションでは、アクティビティ、サービス、およびブロードキャスト レシーバのライフサイクルについて説明します。具体的には、それぞれがライフタイムの間に取ることのできる状態、状態の遷移を通知する方法、およびそれらの状態が、コンポーネントを実行しているプロセスが終了させられたり、インスタンスが破棄されたりする可能性への影響などについて説明します。 +

        + + +

        アクティビティのライフサイクル

        + +

        アクティビティは、基本的に以下の 3 つの状態を取ります:

        + +
          +
        • 状態がアクティブまたは実行中のアクティビティは、画面のフォアグラウンドに表示されている(つまり現在のタスクのアクティビティ スタックの最上位にある)アクティビティです。これが、ユーザーのアクションの焦点となっているアクティビティです。
        • + +
        • 状態が一時停止のアクティビティは、ユーザーのアクションの焦点から外れていますが、まだユーザーから見ることのできるアクティビティです。つまり、それよりも前面に他のアクティビティが表示されていますが、そのアクティビティが透明か全画面表示でないかのどちらかで、一時停止しているアクティビティの一部が見えている状態です。一時停止しているアクティビティは、完全に動作しています(すべての状態やメンバー情報は保持されており、ウィンドウ マネージャにアタッチされたままになっています)。ただし、メモリが極端に不足した場合は、システムによって強制終了させられる可能性があります。

        • + +
        • 状態が停止のアクティビティは、別のアクティビティに隠されて完全に見えなくなったアクティビティです。すべての状態とメンバー情報はまだ保持しています。しかし、もうユーザーに対して表示されていないため、他でメモリが必要な場合は強制終了させられる可能性が高いアクティビティです。

        • +
        + +

        +システムが一時停止または停止しているアクティビティをメモリから削除する場合は、アクティビティの {@link android.app.Activity#finish finish()} メソッドを呼び出して終了を要求するか、単純のそのプロセスを強制終了します。そのアクティビティをもう一度ユーザーに表示する際は、完全に再起動して以前の状態に復元する必要があります。 +

        + +

        +アクティビティがある状態から別の状態に遷移すると、以下の protected メソッドに対する呼び出しによって変更が通知されます: +

        + +

        {@code void onCreate(Bundle savedInstanceState)}
        {@code void onStart()}
        {@code void onRestart()}
        {@code void onResume()}
        {@code void onPause()}
        {@code void onStop()}
        {@code void onDestroy()}

        + +

        +これらのメソッドはすべて、状態が変化したときに適切な処理を行うためにオーバーライドできるフックです。オブジェクトが初めてインスタンス化されたときに初期設定を行うため、すべてのアクティビティには {@link android.app.Activity#onCreate onCreate()} を実装する必要があります。多くのアクティビティには、データの変更をコミットするための {@link android.app.Activity#onPause onPause()} も実装します。これを実装しない場合は、何らかの方法でユーザーとの対話を停止できるようにしておく必要があります。 +

        + + + + +

        +これら 7 つのメソッドを使用すると、アクティビティのライフサイクル全体を定義できます。これらを実装することで、ネストされた 3 つのループからなるアクティビティのライフサイクルを監視できます: +

        + +
          +
        • アクティビティのライフタイム全体は、{@link android.app.Activity#onCreate onCreate()} が初めて呼び出されたときに始まり、最後に {@link android.app.Activity#onDestroy} が呼び出されたときに終了します。アクティビティは、{@code onCreate()} で「全体的」な状態のすべての初期設定を行い、{@code onDestroy()} 残っていたリソースをすべて解放します。たとえば、ネットワークからのデータのダウンロードをバックグラウンドで実行するスレッドは、{@code onCreate()} で作成され、{@code onDestroy()} で停止します。
        • + +
        • アクティビティの可視ライフタイムは、{@link android.app.Activity#onStart onStart()} の呼び出しで始まり、対応する {@link android.app.Activity#onStop onStop()} の呼び出しで終了します。このライフタイムの間は、ユーザーが画面上でそのアクティビティを見ることができます。ただし、アクティビティがフォアグラウンドにない場合や、ユーザーと対話していない場合もあります。これらの 2 つのメソッドの間は、ユーザーに対してアクティビティを表示するために必要なリソースを確保できます。たとえば、{@code onStart()} で {@link android.content.BroadcastReceiver} を登録して UI に影響する変化を監視し、表示しているアクティビティがユーザーから見えなくなったら {@code onStop()} で登録を解除できます。{@code onStart()} および {@code onStop()} メソッドは、アクティビティがユーザーから見え隠れするたびに繰り返し呼び出すことができます。

        • + +
        • アクティビティのフォアグラウンド ライフタイムは、{@link android.app.Activity#onResume onResume()} の呼び出しで始まり、対応する {@link android.app.Activity#onPause onPause()} の呼び出しで終了します。フォアグラウンド ランタイムの間は、このアクティビティが他のどのアクティビティよりも前面に表示され、ユーザーと対話しています。アクティビティは、一時停止状態と再開状態の間を頻繁に遷移します。たとえば、デバイスがスリープ状態になるときや新しいアクティビティを開始するときには {@code onPause()} が呼び出され、アクティビティの結果や新しいインテントが届いたときには {@code onResume()} が呼び出されます。したがって、これらのメソッドを記述する際は、できるだけ軽量化しておく必要があります。

        • +
        + +

        +次の図に、これらのループとアクティビティの遷移経路を示します。色の付いた楕円は、アクティビティが取ることのできる主な状態です。長方形は、アクティビティが状態間を遷移するときに処理を実行するために実装できるコールバック メソッドを表します。 +

        + +

        + +

        +次の表では、各メソッドについて詳しく説明し、ライフサイクル全体における位置付けを示します: +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        メソッド 説明 強制終了
        {@link android.app.Activity#onCreate onCreate()}アクティビティが初めて作成されるときに呼び出されます。通常の静的な設定(ビューの作成、リストへのデータのバインドなど)は、すべてのこのメソッドで行う必要があります。このアクティビティの 以前の状態が保存されていた場合、このメソッドにはその状態を保持している Bundle オブジェクトが引数として(詳しくは、後述のアクティビティの状態の保存をご覧ください)。 +

        この後には、必ず {@code onStart()} が呼び出されます。

        不可{@code onStart()}
            {@link android.app.Activity#onRestart +onRestart()}アクティビティが停止した後、それをもう一度開始する直前に呼び出されます。 +

        この後には、必ず {@code onStart()} が呼び出されます。

        不可{@code onStart()}
        {@link android.app.Activity#onStart onStart()}アクティビティがユーザーから見えるようになる直前に呼び出されます。 +

        その後、アクティビティがフォアグラウンドに表示された場合は {@code onResume()} が、他のアクティビティの後ろに隠れた場合は {@code onStop()} が呼び出されます。

        不可{@code onResume()}
        または
        {@code onStop()}
            {@link android.app.Activity#onResume onResume()}アクティビティがユーザーとの対話を開始する直前に呼び出されます。この時点で、アクティビティはアクティビティ スタックの最上位にあり、ユーザーからの入力はこのアクティビティに対して行われます。 +

        この後には、必ず {@code onPause()} が呼び出されます。

        不可{@code onPause()}
        {@link android.app.Activity#onPause onPause()}システムが別のアクティビティを開始しようとしているときに呼び出されます。このメソッドは、保存されていない変更を永続データにコミットする場合や、アニメーションのように CPU を大量に消費する処理を停止する場合に使用するのが一般的です。このメソッドが終了するまでは次のアクティビティが開始されたないため、できる限り短時間で実行できるようにしておく必要があります。 +

        その後、アクティビティがフォアグラウンドに戻った場合は {@code onResume()} が、ユーザーから見えなくなった場合は {@code onStop()} が呼び出されます。

        可能{@code onResume()}
        または
        {@code onStop()}
        {@link android.app.Activity#onStop onStop()}アクティビティがユーザーから見えなくなったときに呼び出されます。見えなくなる状況としては、アクティビティが破棄された場合や、再開された別のアクティビティ(既存か新規かを問わず)によって隠された場合が考えられます。 +

        その後、アクティビティがユーザーとの対話に戻った場合は {@code onRestart()} が、アクティビティが完全に終了する場合は {@code onDestroy()} が呼び出されます。

        可能{@code onRestart()}
        または
        {@code onDestroy()}
        {@link android.app.Activity#onDestroy +onDestroy()}アクティビティが破棄される前に呼び出されます。これが、アクティビティが受け取る最後の呼び出しとなります。このメソッドが呼び出される状況としては、アクティビティが完了する場合({@link android.app.Activity#finish + finish()} が呼び出されたとき)や、システムが領域を確保するために一時的にそのアクティビティのインスタンスを破棄する場合が考えられます。これらの 2 つの状況は、{@link + android.app.Activity#isFinishing isFinishing()} メソッドを使用して識別できます。可能なし
        + +

        +表の強制終了列に注目してください。この列は、メソッドが終了した後であれば、システムがアクティビティのコードの別の行を実行することなくいつでもアクティビティを実行しているプロセスを強制終了できるかどうかを示しています。{@code onPause()}、{@code onStop()}、および {@code onDestroy()} メソッドの 3 つは「可能」となっています。1 番目に挙げた {@code onPause()} だけは、プロセスが強制終了する前に必ず呼び出されます。{@code onStop()} と {@code onDestroy()} は、必ず呼び出されるとは限りません。したがって、永続データ(たとえばユーザーによる編集)をストレージに書き込む際は {@code onPause()} を使用する必要があります。 +

        + +

        +強制終了列が「不可」になっているメソッドは、それらが呼び出された瞬間から、アクティビティを実行しているプロセスを保護して強制終了されないようにします。したがって、アクティビティが強制終了可能な状態にあるのは、たとえば {@code onPause()} が返されてから {@code onResume()} が呼び出されるまでの間ということです。その後は、もう一度 {@code onPause()} が返されるまで、強制終了できる状態には戻りません。 +

        + +

        +後述のプロセスとライフサイクルのセクションで詳しく説明しますが、ここでの定義で技術的には「強制終了可能」でないアクティビティでも、システムによって強制終了させられる可能性はありますが、他に利用できるリソースがないなど、極端に急を要する場合に限られます。 +

        + + +

        アクティビティの状態の保存

        + +

        +メモリ不足を補うためにユーザーではなくシステムがアクティビティを終了させた場合には,ユーザがそのアクティビティに戻ったときに、以前の状態のままであることを期待するでしょう。 +

        + +

        +アクティビティが強制終了させられる前の状態を保存しておきたい場合は、アクティビティに {@link android.app.Activity#onSaveInstanceState +onSaveInstanceState()} メソッドを実装します。このメソッドは、アクティビティが破棄されやすい状態になる前(つまり {@code onPause()} が呼び出される前)に呼び出されます。その際、アクティビティの動的な状態を名前/値ペアとして記録できる {@link android.os.Bundle} オブジェクトが渡されます。アクティビティがもう一度開始されると、Bundle は {@code onCreate()} だけでなく、{@code onStart()} の後に呼び出される {@link +android.app.Activity#onRestoreInstanceState onRestoreInstanceState()} メソッドにも渡され、保存されている状態をそのどちらかまたは両方で復元できます。 +

        + +

        +{@code onSaveInstanceState()} および {@code onRestoreInstanceState()} メソッドは、これまでに説明した {@code onPause()} などとは異なり、ライフサイクル メソッドではありません。これらのメソッドは、常に呼び出されるわけではありません。たとえば、{@code onSaveInstanceState()} は、システムによってアクティビティが破棄しやすい状態にされる前には呼び出されますが、ユーザーのアクション(たとえば [[]戻る] キー)によってインスタンスが実際に破棄されるときには呼び出されません。そのような場合は、ユーザーがそのアクティビティに戻ることを想定する必要はないため、状態を保存する理由がないのです。 +

        + +

        +{@code onSaveInstanceState()} は常に呼び出されるとは限らないため、アクティビティの一時的な状態を記録する目的のみに使用し、永続データの格納には使用しないようにしてください。この目的には {@code onPause()} を使用します。 +

        + + +

        アクティビティの協調

        + +

        +あるアクティビティが別のアクティビティを開始すると、両方のアクティビティのライフサイクル状態が遷移します。一方が一時停止または停止し、もう一方が開始されます。場合によっては、これらの協調させる必要があります。 +

        + +

        +ライフサイクルのコールバックの順序は明確に定義されており、特に 2 つのアクティビティが同じプロセス内に存在する場合は次のようになります: +

        + +
          +
        1. 現在のアクティビティの {@code onPause()} メソッドが呼び出されます。
        2. + +
        3. 続いて、開始されるアクティビティの {@code onCreate()}、{@code onStart()}、および {@code onResume()} メソッドが順番に呼び出されます。
        4. + +
        5. その後、開始されたアクティビティが画面上で見えなくなると、その {@code onStop()} メソッドが呼び出されます。
        6. +
        + + +

        サービスのライフサイクル

        + +

        +サービスは、以下の 2 つの方法で使用できます: +

        + +
          +
        • いったん開始したら、停止させられる(または自ら停止する)まで実行し続けることができます。このモードでは、{@link android.content.Context#startService Context.startService()} が呼び出されて開始し、{@link android.content.Context#stopService Context.stopService()} 呼び出されて停止します。サービス自体が {@link android.app.Service#stopSelf() Service.stopSelf()} または {@link android.app.Service#stopSelfResult Service.stopSelfResult()} を呼び出して停止することもできます。サービスの開始時に {@code startService()} が何度呼び出されたとしても、{@code stopService()} を一度呼び出せばサービスは停止します。
        • + +
        • サービスで定義されているインターフェースをエクスポートし、これを介してプログラム的に操作できます。クライアントから Service オブジェクトへの接続を確立し、その接続を使用してサービスにアクセスします。接続は、{@link android.content.Context#bindService Context.bindService()} を呼び出して確立し、{@link android.content.Context#unbindService Context.unbindService()} でサービスを開始します。複数のクライアントが同じサービスにバインドすることも可能です。サービスがまだ開始されていなかった場合は,必要に応じて {@code bindService()} で開始できます。 +

        • +
        + +

        +これら 2 つのモードは、完全に分離されているわけではありません。{@code startService()} で開始されたサービスにバインドすることも可能です。たとえば、再生する曲を指定した Intent オブジェクトで {@code startService()} を呼び出して音楽再生サービスを開始したとします。その後、たとえばユーザーがプレーヤーを操作したい場合や再生中の曲に関する情報を入手したい場合には、アクティビティから {@code bindService()} を呼び出してサービスとの接続を確立できます。このような場合、最後のバインドが閉じられるまでは、{@code stopService()} を呼び出してもサービスは停止しません。 +

        + +

        +アクティビティと同様、サービスにもライフサイクル メソッドがあり、これらを実装することでサービスの状態の変化を監視できます。ただし、protected ではなく public で、以下の 3 つしかありません: +

        + +

        {@code void onCreate()}
        {@code void onStart(Intent intent)}
        {@code void onDestroy()}

        + +

        +これらのメソッドを実装することで、ネストされた 2 つのループからなるサービスのライフサイクルを監視できます: +

        + +
          +
        • サービスのライフタイム全体は、{@link android.app.Service#onCreate onCreate()} が呼び出されたときに始まり、{@link android.app.Service#onDestroy} 終了したときに終わります。アクティビティと同じく、サービスも {@code onCreate()} で初期設定を行い、{@code onDestroy()} で残っていたリソースをすべて解放します。たとえば、音楽再生サービスであれば、{@code onCreate()} で音楽を再生するスレッドを作成し、{@code onDestroy()} でそのスレッドを停止できます。
        • + +
        • サービスのアクティブ ライフタイムは、{@link android.app.Service#onStart onStart()} を呼び出したときに始まります。このメソッドには、{@code startService()} に渡された Intent オブジェクトが渡されます。音楽再生サービスは、この Intent オブジェクトをみて曲を見つけ、その再生を開始します。

          + +

          +サービスの停止に相当するコールバック、つまり {@code onStop()} メソッドはありません。 +

        • +
        + +

        +{@code onCreate()} および {@code onDestroy()} メソッドは、サービスを {@link android.content.Context#startService Context.startService()} または {@link android.content.Context#bindService Context.bindService()} のどちらで開始したかに関係なく、すべてのサービスで呼び出されます。一方、{@code onStart()} は、サービスを {@code startService()} で開始した場合のみ呼び出されます。 +

        + +

        +サービスが他からのバインドを許可している場合は、以下のコールバック メソッドを追加で実装できます: +

        + +

        {@code IBinder onBind(Intent intent)}
        {@code boolean onUnbind(Intent intent)}
        {@code void onRebind(Intent intent)}

        + +

        +{@link android.app.Service#onBind onBind()} コールバックには {@code bindService()} に渡された Intent オブジェクトが渡され、{@link android.app.Service#onUnbind onUnbind()} には {@code unbindService()} 渡された Intent オブジェクトが渡されます。サービスがバインドを許可している場合は、クライアントがサービスと対話する通信チャネルを {@code onBind()} で返します。{@code onUnbind()} メソッドは、サービスに新しいクライアントが接続した場合に {@link android.app.Service#onRebind onRebind()} の呼び出しを要求できます。 +

        + +

        +次の図に、サービスのコールバック メソッドを示します。なお、{@code startService()} で作成されたサービスと、{@code bindService()} で作成されたサービスを分けて記述していますが、作成された方法に関係なく,すべてのサービスはクライアントからのバインドを許可できます。したがって、どのサービスも {@code onBind()} および{@code onUnbind()} メソッドの呼び出しを受け取る可能性はあります。 +

        + +

        + + +

        ブロードキャスト レシーバのライフサイクル

        + +

        +ブロードキャスト レシーバのコールバック メソッドは次の 1 つのみです: +

        + +

        {@code void onReceive(Context curContext, Intent broadcastMsg)}

        + +

        +レシーバにブロードキャスト メッセージが届くと、{@link android.content.BroadcastReceiver#onReceive onReceive()} メソッドが呼び出され、メッセージを保持する Intent オブジェクトが渡されます。ブロードキャスト レシーバは、このメソッドの実行中のみアクティブと見なされます。{@code onReceive()} 終了すると、ブロードキャスト レシーバはアクティブでなくなります。 +

        + +

        +ブロードキャスト レシーバがアクティブになっているプロセスは、強制終了しないよう保護されます。一方、アクティブでないコンポーネントのみからなるプロセスは、それが消費しているメモリが他のプロセスで必要になった場合は、いつでも強制終了される可能性があります。 +

        + +

        +この点は、ブロードキャスト メッセージへの応答に時間がかかるため、ユーザー インターフェースの他のコンポーネントを実行しているメイン スレッドとは別のスレッドで何らかの処理を行う必要がある場合に問題になります。{@code onReceive()} が新しいスレッドを生成して終了した場合、プロセス内に他にアクティブなアプリケーション コンポーネントがなければ、そのスレッドを含めたプロセス全体がアクティブでないと判断されて強制終了させられるおそれがあります。この問題を回避するには、{@code onReceive()} でサービスを開始し、そのサービスにジョブを実行させます。これにより、プロセス内にまだアクティブなコンポーネントがあると見なされます。 +

        + +

        +次のセクションでは、プロセスが強制終了される可能性が高くなる状況についてさらに詳しく説明します。 +

        + + +

        プロセスとライフサイクル

        + +

        Android は、プロセスをできるだけ長い間維持しようとします。しかし、最終的にメモリが不足したときには、古いプロセスを削除しなければならなくなります。Android では、どのプロセスを維持し、どのプロセスを強制終了させるかを判断するため、プロセス内で実行されているコンポーネントと各コンポーネントの状態に基づいて、各プロセスを「重要度の階層」の位置づけます。まず最も重要度の低いプロセスが削除され、次は 2 番目に重要度の低いプロセス、その次に 3 番目、というように判断されます。階層は 5 つのレベルで構成されます。以下では、重要度の高いものから順に説明します: +

        + +
          + +
        1. フォアグラウンド プロセスは、ユーザーがその時点で行っている作業に必要なプロセスです。以下のいずれかの条件を満たしているプロセスは、フォアグラウンド プロセスと見なされます: + +
            +
          • ユーザーと対話中のアクティビティを実行している(Activity オブジェクトの {@link android.app.Activity#onResume +onResume()} メソッドが呼び出されている)。
          • + +
          • ユーザーと対話中のアクティビティにバインドされているサービスを実行している。

          • + +
          • いずれかのライフサイクル コールバック({@link android.app.Service#onCreate +onCreate()}{@link android.app.Service#onStart onStart()}、または {@link android.app.Service#onDestroy onDestroy()})を実行している {@link android.app.Service} オブジェクトを保持している。

          • + +
          • {@link android.content.BroadcastReceiver#onReceive +onReceive()} メソッドを実行している {@link android.content.BroadcastReceiver} オブジェクトを保持している。

          • +
          + +

          +同時に存在するフォアグラウンド プロセスは少数に限られています。フォアグラウンド プロセスは、メモリが極端に不足し、すべてのフォアグラウンド プロセスの実行を継続できない場合の最終手段として強制終了させられます。通常、その時点でデバイスはメモリ ページングの状態に達しており、ユーザー インターフェースを応答可能な状態に維持するためには、フォアグラウンド プロセスの一部を強制終了させなければならない状況に陥っています。 +

        2. + +
        3. 可視プロセスは、フォアグラウンド コンポーネントではないものの、ユーザーが見ている画面に影響を及ぼすことのできるプロセスです。以下のいずれかの条件を満たしているプロセスは、可視プロセスと見なされます:

          + +
            +
          • フォアグラウンドではないがユーザーから見ることができるアクティビティを実行している(その {@link android.app.Activity#onPause onPause()} メソッドが呼び出されている)。これは、たとえばフォアグラウンド アクティビティがダイアログで、その背後に直前のアクティビティが見えるような状況です。
          • + +
          • ユーザーから見ることのできるアクティビティにバインドされているサービスを実行している。

          • +
          + +

          +可視プロセスは、非常に重要なプロセスと見なされ、すべてのフォアグラウンド プロセスの実行を維持するために必要でない限り、強制終了させられることはありません。 +

        4. + +
        5. サービス プロセスは、{@link android.content.Context#startService startService()} メソッドで開始されたサービスを実行しているプロセスのうち、より重要度の高い 2 つのレベルのどちらにも該当しないプロセスです。サービス プロセスは、ユーザーに見えるものとの直接的な関係はありませんが、たとえばバックグラウンドでの MP3 の再生、ネットワークからのデータのダウンロードなど、ユーザーが気にかけている処理であることが一般的です。したがって、すべてのフォアグラウンド プロセスと可視プロセスに加え、これらのサービス プロセスの実行を維持するだけのメモリが確保できる限り、強制終了させられることはありません。 +

        6. + +
        7. バックグラウンド プロセスは、その時点でユーザーから見えないアクティビティを保持している(Activity オブジェクトの {@link android.app.Activity#onStop onStop()} メソッドが呼び出されている)プロセスです。これらのプロセスは、ユーザー エクスペリエンスに直接的には影響しておらず、フォアグラウンド、可視、サービス プロセスからメモリが要求された場合はいつでも強制終了する可能性があります。通常は数多くのバックグラウンド プロセスが実行されているため、それらを LRU(least recently used)リストに登録し、ユーザーが一番最近見たアクティビティのプロセスが最後に強制終了するような仕組みになっています。アクティビティにライフサイクル メソッドが正しく実装されており、現在の状態が正しく保存されていれば、プロセスを強制終了してもユーザー エクスペリエンスに悪影響が及ぶことはありません。 +

        8. + +
        9. 空のプロセスは、アクティブなアプリケーション コンポーネントを保持していないプロセスです。このようなプロセスを維持しておく唯一の理由は、これをキャッシュとして使用し、次回コンポーネントを実行するときの起動時間を短くするためです。多くの場合、システムはこれらのプロセスを強制終了させて、プロセス キャッシュとその基礎となるカーネル キャッシュの間でシステム リソース全体のバランスを取ります。

        10. + +
        + +

        +各プロセスは、その時点でアクティブなコンポーネントの重要度に基づいて、そのプロセスが取りうる最も高いレベルにランク付けされます。たとえば、あるプロセスがサービスと可視アクティビティをホストしている場合、そのプロセスはサービス プロセスではなく可視プロセスとしてランク付けされます。 +

        + +

        +また、あるプロセスに他のプロセスが依存しているために、そのプロセスのランクが引き上げられる可能性もあります。他のプロセスから依存されているプロセスが、依存しているプロセスよりも低いレベルにランク付けされることはありません。たとえば、プロセス A 内のコンテンツ プロバイダにプロセス B 内のクライアントが依存している場合や、プロセス A 内のサービスがプロセス B 内のコンポーネントにバインドされている場合、プロセス A は常にプロセス B よりは重要度が高いと見なされます。 +

        + +

        +サービスを実行しているプロセスは、バックグラウンド アクティビティを実行しているプロセスよりも高くランク付けされます。したがって、時間のかかる処理を実行する場合、特にその処理がアクティビティよりも長く続くような場合は、単にスレッドを生成するのではなく、その処理用のサービスを開始することをおすすめします。たとえば、バックグラウンドで音楽を再生する場合や、カメラで撮影した写真を Web サイトにアップロードする場合などはこれに当たります。サービスを使用することで、アクティビティがどのような状況にあっても、処理の重要度として「サービス プロセス」レベル以上を維持できます。ブロードキャスト レシーバのライフサイクルのセクションでも説明しましたが、ブロードキャスト レシーバにおいてもこれと同じ理由で、処理に時間がかかる場合はスレッドではなくサービスを使用することをおすすめします。 +

        diff --git a/docs/html/intl/ja/guide/tutorials/hello-world.jd b/docs/html/intl/ja/guide/tutorials/hello-world.jd new file mode 100644 index 0000000000000..31857cee8c1f4 --- /dev/null +++ b/docs/html/intl/ja/guide/tutorials/hello-world.jd @@ -0,0 +1,375 @@ +page.title=Hello, World +@jd:body + + + +

        デベロッパーにとって、開発フレームワークの第一印象は、どれだけ簡単に「Hello, World」を記述できるかで決まります。Android では、非常に簡単に記述できます。総合開発環境として Eclipse を使用している場合には、開発は特に簡単です。プロジェクトの作成と管理に使用できる便利なプラグインが用意されており、開発サイクルを大幅にスピードアップできるためです。

        + +

        Eclipse を使用していない場合でも問題ありません。Developing in Other IDEsに慣れてから、このチュートリアルに戻り、Eclipse に関する部分以外を参考にしてください。

        + +

        開始する前に、最新の SDK がインストールされている必要があります。また、Eclipse を使用する場合には、ADT プラグインもインストールされている必要があります。これらのプログラムがインストールされていない場合は、「Installing the Android SDK」を参考にインストールを実行して、完了後にこのチュートリアルに戻ってください。

        + +

        AVD の作成

        + + + +

        このチュートリアルでは、開発したアプリケーションを Android エミュレータで実行します。エミュレータを起動するには、事前に Android 仮想デバイス(AVD)を作成する必要があります。AVD は、エミュレータが使用するシステム イメージとデバイスの設定を定義するものです。

        + +

        AVD を作成するには、Android SDK に含まれている「android」ツールを使用します。コマンド プロンプトまたはターミナルを開き、SDK パッケージの中の tools/ ディレクトリに移動して、次のコマンドを実行します。 +

        +android create avd --target 2 --name my_avd
        +
        + +

        カスタム ハードウェア プロファイルを作成するかどうかを尋ねられます。ここではひとまず、リターン キーを押してスキップします(デフォルトの回答は「No」となっています)以上で AVD の作成は終了です。この作業により、Android 1.5 プラットフォームを使用する「my_avd」という名前の AVD が構成されました。これで、AVD をエミュレータで使用できる状態になりました。

        + +

        上記のコマンドで使用した --target オプションは、エミュレータを実行する配備ターゲットを指定するもので、必須オプションです。--name オプションは新規 AVD の名前を定義するもので、これも必須オプションです。

        + + +

        新規 Android プロジェクトを作成する

        + +

        AVD を作成したら、次は Eclipse 内で新規 Android プロジェクトを開始します。

        + +
          +
        1. Eclipse で、[[]ファイル(File)] > [[]新規(New)] > [[]プロジェクト(Project)] を選択します。 +

          ADT Plugin for Eclipse が正常にインストールされていれば、表示されるダイアログに、「Android」というラベルの付いたフォルダと、その中の「Android プロジェクト(Android Project)」が表示されます(1 つまたは複数の Android プロジェクトを作成した後は、「Android XML File」というエントリも表示されるようになります)。

          +
        2. + +
        3. 「Android プロジェクト(Android Project)」を選択して、[[]次へ(Next)] をクリックします。
          +
        4. + +
        5. プロジェクトの詳細項目に以下の値を入力します。 +
            +
          • プロジェクト名(Project name): HelloAndroid
          • +
          • アプリケーション名(Application name): Hello, Android
          • +
          • パッケージ名(Package name): com.example.helloandroid(または自分のプライベート ネームスペース)
          • +
          • アクティビティを作成(Create Activity): HelloAndroid
          • +
          • SDK の最小バージョン(Min SDK Version): 2
          • +
          +

          [[]完了(Finish)] をクリックします。

          + + + +

          各フィールドの説明は以下のとおりです。

          + +
          +
          プロジェクト名(Project Name)
          +
          Eclipse のプロジェクト名。プロジェクト ファイルを格納するディレクトリの名前です。
          +
          アプリケーション名(Application Name)
          +
          アプリケーション名はユーザーにわかりやすいアプリケーションのタイトルにします。この名前が Android 携帯端末に表示されます。
          +
          パッケージ名(Package Name)
          +
          作成したすべてのソース コードを格納するパッケージ ネームスペースです(Java プログラミング言語で作成するパッケージと同じルールに従います)。また、これにより、スタブ Activity が生成されるパッケージの名前も設定されます。 +

          パッケージ名は Android システムにインストールされたすべてのパッケージに共通して固有のものでなければなりません。このため、作成するアプリケーションに標準的なドメイン スタイルのパッケージを使用することが非常に重要です。上記の例では、「com.example」というネームスペースを使用しています。これはサンプル ドキュメント用のネームスペースです。実際にアプリケーションを作成する際には、所属する組織または法人に適切なネームスペースを使用します。

          +
          アクティビティを作成(Create Activity)
          +
          プラグインによって生成されるクラス スタブの名前です。クラス スタブは Android の {@link android.app.Activity} クラスのサブクラスとなります。アクティビティとは単に、実行して何らかの処理を行うことができるクラスを意味します。選択に応じて UI を作成することもできます(ただし必須ではありません)。チェックボックスになっていることからわかるように、これは任意選択の項目です。しかし、実際にはほとんどのアプリケーションでは、アクティビティをアプリケーションの基盤として使用しています。
          +
          SDK の最小バージョン(Min SDK Version)
          +
          作成するアプリケーションが必要とする最小 API レベルを指定する値です。ここに入力した API レベルが、選択可能なターゲットのいずれかで提供される API レベルと一致する場合は、ビルド ターゲットが自動的に選択されます(この例では、API レベルに「2」と入力するとターゲット Android 1.1 が選択されます)。Android システム イメージと Android SDK それぞれの新しいバージョンでは、API に追加または変更が加えられている可能性があります。追加または変更が加えられている場合、新しい API レベルがシステム イメージに割り当てられ、どのアプリケーションの実行を許可するかが規制されます。アプリケーションで必要な API レベルがデバイスでサポートされるレベルよりも高い場合、アプリケーションはインストールされません。
          +
          + +

          その他のフィールド: 「デフォルト ロケーションの使用」チェックボックスでは、プロジェクトのファイルが生成され保存されるディスク上の場所を変更することができます。「ビルド ターゲット」は、作成するアプリケーションがコンパイルされるときにターゲットとするプラットフォームです(この項目は [[]SDK の最小バージョン(Min SDK Version)] の入力値に基づいて自動的に選択されます)。

          + +

          ここで、選択した「ビルド ターゲット」で Android 1.1 プラットフォームが使用されることに注目してください。これは、作成するアプリケーションが Android 1.1 プラットフォーム ライブラリをターゲットとしてコンパイルされることを意味します。先ほど作成した AVD は Android 1.5 プラットフォームで実行されます。バージョンの数字が一致しませんが、Android アプリケーションには上方互換性があるため、1.1 プラットフォーム ライブラリをターゲットとして構築されたアプリケーションでも 1.5 プラットフォームで正常に動作します。ただしその逆の場合は正常に動作しません。

          +
        6. +
        + +

        さて、これで Android プロジェクトを使用できる状態になりました。プロジェクトは左側のパッケージ エクスプローラー(Package Explorer)で表示できます。「HelloAndroid」 > 「src」 > 「com.example.helloandroid」 の中にある HelloAndroid.java ファイルを開きます。ファイルの内容は次のようになっています。

        + +
        +package com.example.helloandroid;
        +
        +import android.app.Activity;
        +import android.os.Bundle;
        +
        +public class HelloAndroid extends Activity {
        +    /** Called when the activity is first created. */
        +    @Override
        +    public void onCreate(Bundle savedInstanceState) {
        +        super.onCreate(savedInstanceState);
        +        setContentView(R.layout.main);
        +    }
        +}
        + +

        クラスが {@link android.app.Activity} クラスに基づいていることに注目してください。アクティビティ(Activity)とは、処理を実行するために使用される単体のアプリケーション エンティティです。1 つのアプリケーションにはいくつものアクティビティが含まれる場合がありますが、ユーザーが一度に操作するのは 1 つのアクティビティです。アクティビティが開始すると、Android システムによって {@link android.app.Activity#onCreate(Bundle) onCreate()} メソッドが呼び出されます。このタイミングですべての初期化と UI セットアップを実行します。アクティビティにユーザー インターフェースは必須ではありませんが、通常はユーザー インターフェースを装備します。

        + +

        では、コードを変更してみましょう。

        + + +

        UI を構築する

        + +

        下記の変更済みのコードを参照して、お手元の HelloAndroid クラスに同じ変更を加えてみてください。太字の部分が追加された行です。

        + +
        +package com.android.helloandroid;
        +
        +import android.app.Activity;
        +import android.os.Bundle;
        +import android.widget.TextView;
        +
        +public class HelloAndroid extends Activity {
        +   /** Called when the activity is first created. */
        +   @Override
        +   public void onCreate(Bundle savedInstanceState) {
        +       super.onCreate(savedInstanceState);
        +       TextView tv = new TextView(this);
        +       tv.setText("Hello, Android");
        +       setContentView(tv);
        +   }
        +}
        + +

        ヒント: プロジェクトにインポート パッケージを簡単に追加できる方法として、Ctrl+Shift+O(Mac では コマンド+Shift+O)を押す方法があります。これは、コードの記述に基づいて足りないパッケージを特定して追加する Eclipse のショートカット キーです。

        + +

        Android のユーザー インターフェースは、「ビュー(Views)」と呼ばれるオブジェクトの階層で構成されています。{@link android.view.View} は、UI レイアウト内でボタン、画像、または(このサンプルのように)テキスト ラベルといった要素として使用される、描画可能なオブジェクトです。これらのオブジェクトのそれぞれが View クラスのサブクラスであり、テキストを処理するサブクラスは {@link android.widget.TextView} です。

        + +

        この変更では、クラス コンストラクタを使用して TextView を作成します。このクラス コンストラクタは、パラメータとして Android {@link android.content.Context} インスタンスを受け入れます。Context とは、システムへのハンドルであり、リソースの解決、データベースや設定へのアクセスの取得などのサービスを提供します。Activity クラスは Context を継承します。作成する HelloAndroid クラスは、Activity のサブクラスであるため、Context でもあります。したがって、this を Context 参照として TextView に引き渡すことができます。

        + +

        次に、{@link android.widget.TextView setText(CharSequence) setText()} を使用してテキスト コンテンツを定義します。

        + +

        最後に、そのコンテンツが Activity UI のコンテンツとして表示されるように、TextView を {@link android.app.Activity#setContentView(View) setContentView()} に引き渡します。Activity によってこのメソッドが呼び出されなければ、UI は表示されず、空白の画面が表示されます。

        + +

        これで、Android で「Hello, World」が表示されるようになりました。次の手順はもちろん、アプリケーションの実行です。

        + + +

        アプリケーションを実行する

        + +

        Eclipse プラグインでは、非常に簡単にアプリケーションを実行できます。

        + +
          +
        1. [[]実行] > [[]実行] を選択します。
        2. +
        3. 「Android Application」を選択します。
        4. +
        + + + +

        Eclipse ADT によって自動的にプロジェクトの新規起動構成が作成され、Android エミュレータが自動的に起動します。エミュレータが起動した後、少し経つとアプリケーションが表示されます。次のような画面が表示されます。

        + + + +

        グレーのバーに表示されている「Hello, Android」は、アプリケーションのタイトルです。このタイトルは Eclipse プラグインによって自動的に作成されます(文字列は res/values/strings.xml ファイル内で定義され、AndroidManifest.xml によって参照されます)。タイトルの下のテキストは、先ほど TextView オブジェクトで作成した実際のテキストです。

        + +

        これで「Hello World」についての基本的なチュートリアルは終了ですが、この続きもぜひ読んでください。Android アプリケーションの開発に関するさらに有益な情報を紹介しています。

        + + +

        UI を XML レイアウトにアップグレードする

        + +

        先ほど作成した「Hello, World」のサンプルは、「プログラマティック」と呼ばれる UI レイアウトを使用しています。「プログラマティック」とは、アプリケーションの UI を直接ソース コードで作成および構築することを意味します。UI プログラミングの経験が豊富な方であればおそらく、このようなアプローチが時にいかに脆弱になり得るかをよくご存じでしょう。レイアウトの軽微な変更のたびに、ソース コード全体に関わる大きな問題が発生する可能性があるからです。また、複数のビューを適切に結びつけることも忘れられがちであるため、これによりレイアウトにエラーが発生し、コードのデバッグで時間が無駄になる場合があります。

        + +

        その理由から、Android では、XML ベースのレイアウト ファイルを使用する別の UI 構築モデルを用意しています。この概念を簡単に説明するには、サンプルを紹介するのが一番です。ここに示すのは、上記の「プログラマティック」に構築したサンプルと同じように動作する XML レイアウト ファイルです。

        + +
        <?xml version="1.0" encoding="utf-8"?>
        +<TextView xmlns:android="http://schemas.android.com/apk/res/android"
        +  android:layout_width="fill_parent"
        +  android:layout_height="fill_parent"
        +  android:text="@string/hello"/>
        + +

        Android XML レイアウト ファイルの全般的な構造はシンプルです。XML 要素がツリー構造になっており、含まれた各ノードが View クラスの名前を表しています(このサンプルでは View 要素が 1 つのみですが)。XML レイアウト内の要素として、{@link android.view.View} を拡張する任意のクラスの名前を使用できます。これには作成するコードの中で定義するカスタム View クラスも含まれます。この構造により、プログラマティックなレイアウトよりもシンプルな構造と構文を使用して、迅速な UI 構築を非常に簡単に行うことができます。このモデルは、アプリケーションの表示(つまり UI)を、データの取得と入力に使用されるアプリケーション ロジックから切り離すことができる Web 開発モデルからヒントを得て考案されました。

        + +

        上記の XML サンプルには、TextView という View 要素 1 つのみが含まれています。この要素は 4 つの XML 属性を持っています。下表に、これらの 4 つの属性の説明をまとめました。

        + + + + + + + + + + + + + + + + + + + + + + + + +
        + 属性 + + 説明 +
        + xmlns:android + + Android ネームスペースで定義された共通の属性を参照することを Android ツールに伝える XML ネームスペース宣言です。すべての Android レイアウト ファイル内の最初と最後のタグはこの属性を持つ必要があります。
        +
        + android:layout_width + + 該当の View が画面の利用可能な幅のうちどれくらいを占めるかを定義します。このサンプルでは、この View しかないため、「fill_parent」という値を使用して画面全体を占めることにします。
        +
        + android:layout_height + + android:layout_width とよく似た属性で、幅ではなく高さを表します。 +
        + android:text + + TextView が表示するテキストを設定します。このサンプルでは、ハードコード記述された文字列値ではなく文字列リソースを使用します。文字列「hello」は res/values/strings.xml ファイル内で定義されます。アプリケーションに文字列を挿入する場合にはこの方法が推奨されます。レイアウト ファイルのハードコードを直接変更する必要がないため、アプリケーションの他の言語へのローカライズがスムーズに進むからです。詳しくは、「リソースと国際化」を参照してください。 +
        + + +

        これらの XML レイアウト ファイルは、作成するプロジェクトの res/layout/ ディレクトリ内に置かれます。「res」は「resources」の略で、アプリケーションに必要なコード以外のすべてのアセットがこのディレクトリに格納されます。リソースには、レイアウト ファイルの他に、画像、音声、ローカライズされた文字列などのアセットがあります。

        + + + +

        Eclipse プラグインでは、このようなレイアウト ファイルの 1 つである「main.xml」が自動的に作成されます。先ほど「Hello World」アプリケーションを作成した際には、このファイルは無視してプログラマティックにレイアウトを作成しました。この作成方法は Android フレームワークについてより深く理解していただくことを意図したもので、実際にはほとんどの場合レイアウトはコードではなく XML ファイルで定義します。以下の手順では、既存のアプリケーションを変更して XML レイアウトが使用されるようにする方法を説明します。

        + +
          +
        1. Eclipse のパッケージ エクスプローラー(Package Explorer)で、/res/layout/ フォルダを展開し、main.xml を開きます(開いた後、場合によっては XML ソースを見るのにウィンドウ下部にある「main.xml」タブをクリックする必要があります)。ファイルの内容を以下の XML に置き換えます。 + +
          <?xml version="1.0" encoding="utf-8"?>
          +<TextView xmlns:android="http://schemas.android.com/apk/res/android"
          +  android:layout_width="fill_parent"
          +  android:layout_height="fill_parent"
          +  android:text="@string/hello"/>
          +

          ファイルを保存します。

          +
        2. + +
        3. res/values/ フォルダ内の strings.xml を開きます。このファイルは、作成するユーザー インターフェースのためのすべてのデフォルトのテキスト文字列を保存するものです。Eclipse を使用している場合、ADT によってあらかじめ helloapp_name という 2 つの文字列が用意された状態になります。hello を何か別の文字列に書き換えてみましょう。たとえば「Hello, Android! I am a string resource!」としてみましょう。変更後のファイルの全体は次のようになります。 +
          +<?xml version="1.0" encoding="utf-8"?>
          +<resources>
          +    <string name="hello">Hello, Android! I am a string resource!</string>
          +    <string name="app_name">Hello, Android</string>
          +</resources>
          +
          +
        4. + +
        5. 次に、HelloAndroid クラスを開いて、XML レイアウトを使用して変更します。ファイルを編集して次のような内容にします。 +
          +package com.example.helloandroid;
          +
          +import android.app.Activity;
          +import android.os.Bundle;
          +
          +public class HelloAndroid extends Activity {
          +    /** Called when the activity is first created. */
          +    @Override
          +    public void onCreate(Bundle savedInstanceState) {
          +        super.onCreate(savedInstanceState);
          +        setContentView(R.layout.main);
          +    }
          +}
          + +

          この変更を行う際に、コードを手入力してコード補完機能を試してみましょう。「R.layout.main」と入力しようとすると、プラグインによって入力候補が表示されます。この機能の便利さは、開発中に何回も実感すると思います。

          + +

          View オブジェクトに setContentView() を引き渡す代わりに、レイアウト リソースへの参照を付与します。リソースは R.layout.main として識別されます。これは、/res/layout/main.xml で定義されたレイアウトを、コンパイルされたオブジェクトで表したものです。Eclipse プラグインでは、この参照がプロジェクトの R.java クラス内に自動的に作成されます。Eclipse を使用していない場合、Ant を実行してアプリケーションのビルドを行う際に R.java クラスが生成されます(R クラスについて詳しくは後ほど説明します)。

          +
        6. +
        + +

        ここで、アプリケーションを再実行します。起動構成は作成済みであるため、ここでは緑色の矢印アイコンをクリックして実行するか、または [[]実行(Run)] > [[]ヒストリーの実行(Run History)] > [[]Android Activity] を選択するだけです。TextView 文字列に加えた変更を除けば、アプリケーションは同じに見えます。ここでポイントとなるのは、2 つの異なるレイアウト編集方法を使用して同じ結果が得られるということです。

        + +

        ヒント: ショートカット キーCtrl+F11(Mac では コマンド+Shift+F11)を使用して、現在表示されているアプリケーションを実行することができます。

        + +

        ここからは、デバッグの基礎知識と、他の総合開発環境に関する補足情報について説明します。さらに詳しく学習したい場合は、「アプリケーションの基礎」を参照してください。Android アプリケーションが動作するためのすべての要素について説明しています。また、「デベロッパー ガイド」の導入ページを参照して、デベロッパー ガイド ドキュメントの概要を確認してください。

        + + +
        +

        R クラス

        +

        Eclipse で、R.java という名前のファイル(gen/(「生成された Java ファイル(Generated Java Files)」フォルダ内)を開きます。ファイルの内容は次のようになっています。

        + +
        +package com.example.helloandroid;
        +
        +public final class R {
        +    public static final class attr {
        +    }
        +    public static final class drawable {
        +        public static final int icon=0x7f020000;
        +    }
        +    public static final class layout {
        +        public static final int main=0x7f030000;
        +    }
        +    public static final class string {
        +        public static final int app_name=0x7f040001;
        +        public static final int hello=0x7f040000;
        +    }
        +}
        +
        + +

        プロジェクトの R.java ファイルは、ファイル内で定義されたすべてのリソースへのインデックスです。ソース コード内では、プロジェクトに含めたすべてのリソースを参照するための簡略形式としてこのクラスを使用します。これは、Eclipse などの総合開発環境のコード補完機能とともに使用すると特に便利です。探している特定の参照をすばやくインタラクティブに見つけることができるからです。

        + +

        お手元のファイルはこれとは若干異なる可能性があります(おそらく 16 進値が異なるためです)。ここでは、「layout」という名前の内部クラスと、そのメンバーであるフィールド「main」に注目します。Eclipse プラグインにより main.xml という名前の XML レイアウト ファイルが認識され、ここにそのためのクラスが生成されたものです。プロジェクトに他のリソース(res/values/string.xml ファイル内の文字列や res/drawable/ ディレクトリ内の描画可能オブジェクトなど)を追加すると、R.java に最新の変更が反映されます。

        +

        Eclipse を使用していない場合は、(Ant ツールを使用した)ビルド時にこのクラス ファイルが生成されます。

        +

        くれぐれもこのファイルを手動で編集しないようにしてください。

        +
        + +

        プロジェクトをデバッグする

        + +

        Android Plugin for Eclipse は、Eclipse のデバッガと優れた連動性を発揮します。このメリットを確認するため、作成したコードにバグを埋め込んでみましょう。作成した HelloAndroid ソース コードを次のように変更します。

        + +
        +package com.android.helloandroid;
        +
        +import android.app.Activity;
        +import android.os.Bundle;
        +
        +public class HelloAndroid extends Activity {
        +    /** Called when the activity is first created. */
        +    @Override
        +    public void onCreate(Bundle savedInstanceState) {
        +        super.onCreate(savedInstanceState);
        +        Object o = null;
        +        o.toString();
        +        setContentView(R.layout.main);
        +    }
        +}
        + +

        この変更は、単にコードに NullPointerException を発生させるものです。アプリケーションを再度実行すると、最終的に次のような画面が表示されます。

        + + + +

        「強制終了」を押してアプリケーションを終了し、エミュレータ ウィンドウを閉じます。

        + +

        エラーの詳細を確認するには、ソース コード内の Object o = null; 行にブレークポイントを設定します(該当するソース コード行の横にあるマーカー バーをダブルクリックします)。次に、メニューから [[]実行(Run)] > [[]デバッグ ヒストリー(Debug History)] > [[]Hello, Android] を選択して、デバッグ モードに入ります。エミュレータでアプリケーションが再起動されますが、今度は、先ほど設定したブレークポイントに到達した時点で中断されます。その後 Eclipse のデバッグ パースペクティブ(Debug Perspective)で、他のアプリケーションで通常行うように、コードの内容を確認できます。

        + + + + +

        Eclipse を使用せずにプロジェクトを作成する

        + +

        Eclipse を使用していない場合(普段から使用している総合開発環境がある場合や、シンプルにテキスト エディタやコマンド ライン ツールを使用している場合など)は、Eclipse プラグインを利用することはできません。しかし心配は無用です。Eclipse を使用していないからといって何らかの機能が失われることはありません。

        + +

        Android Plugin for Eclipse は、単に Android SDK に含まれるツール セットをまとめたものに過ぎません(エミュレータ、aapt、adb、ddms などの個別のツールについては、こちらで別途説明しています)。このため、これらのツールを別のツール、たとえば「Ant」のビルド ファイルなどでまとめることも可能です。

        + +

        Android SDK には、「android」という名前のツールが含まれています。このツールを使用すると、作成するプロジェクトのソース コードとディレクトリ スタブすべて、および Ant と互換性のある build.xml ファイルを作成することができます。これにより、プロジェクトをコマンド ラインで作成したり、普段使用している総合開発環境と統合したりすることができます。

        + +

        たとえば、Eclipse で作成されるものと同様の HelloAndroid プロジェクトを作成するには、次のコマンドを使用します。

        + +
        +android create project \
        +    --package com.android.helloandroid \
        +    --activity HelloAndroid \ 
        +    --target 2 \
        +    --path <path-to-your-project>/HelloAndroid 
        +
        + +

        これにより、path で定義された場所に、プロジェクトに必要なフォルダとファイルが作成されます。

        + +

        SDK ツールを使用してプロジェクトを作成および構築する方法について詳しくは、「Developing in Other IDEs」を参照してください。

        diff --git a/docs/html/intl/ja/index.jd b/docs/html/intl/ja/index.jd new file mode 100644 index 0000000000000..a5378c964d3db --- /dev/null +++ b/docs/html/intl/ja/index.jd @@ -0,0 +1,159 @@ +home=true +@jd:body + + +
        +
        +
        +
        +
        +

        デベロッパーへのお知らせ

        +
        +
        + + Android Developer Challenge 2 +
        +

        第2Android Developer Challengeが、遂に登場しました!このアプリケーション開発コンテストでは、Androidのユーザなら誰でも簡単に参加でき、一等の賞金は$250,000 です。登録の締切日は8月31日になります。

        +

        Android Developer Challengeについて詳しくはこちら »

        +
        +
        +
        +
        +
        +
        +
        +
        + +
        +
        + +
        +
        + +
        +
        +
        +
        + +
         
        +
        + +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        +

        ダウンロード

        +

        Android SDK には、優れたアプリケーションの作成に必要となるツール、サンプル コード、ドキュメントが含まれています。

        +

        詳細 »

        +
         
        +

        公開

        +

        Android マーケットは、アプリケーションを携帯端末に配信するためのオープン サービスです。

        +

        詳細 »

        +
         
        +

        貢献

        +

        Android オープンソース プロジェクトでは、プラットフォーム全体のソースコードを公開しています。

        +

        詳細 »

        +
         
        +

        再生

        + +

        その他の Android 動画 »

        +
        +
        +
        + + + + + + diff --git a/docs/html/intl/ja/sdk/1.5_r2/installing.jd b/docs/html/intl/ja/sdk/1.5_r2/installing.jd new file mode 100644 index 0000000000000..bcb1ffba6355a --- /dev/null +++ b/docs/html/intl/ja/sdk/1.5_r2/installing.jd @@ -0,0 +1,212 @@ +page.title=Android SDK のインストール +@jd:body + + +

        このページでは、Android SDK をインストールして、開発環境を設定する方法について説明します。SDK をまだダウンロードしていない場合は、[ダウンロード] ページからダウンロードしてください。SDK をダウンロードした後に、このページの手順を行ってください。

        + +

        インストール中に問題が発生した場合は、このページの下部にあるインストールに関する注意事項を参照してください。

        + +

        アップグレードする場合

        +

        SDK の以前のバージョンを使用してアプリケーションを既に開発している場合は、このページの代わりに、SDK のアップグレード をご覧ください。 +

        + + +

        インストールの準備

        + +

        インストールを始める前に、開発用マシンがシステム要件を満たしていることを確認してください。 +

        + +

        Eclipse 環境に Android Development Tools(ADT)プラグインを組み込んだ開発環境は、Android 向け開発の初心者に最適です。プラグインを利用する場合は、コンピュータに Eclipse の適切なバージョン(3.3 以降)がインストールされていることを確認してください。Eclipse のインストールが必要な場合は、次の場所からダウンロードできます:

        + +

        http://www.eclipse.org/downloads/

        + +

        Eclipse の Java バージョンまたは RCP バージョンをおすすめします。

        + +

        SDK のインストール

        + +

        SDK のダウンロード後、お使いのマシンの適切な場所に .zip アーカイブを展開します。デフォルトでは、SDK ファイルは android_sdk_<platform>_<release> ディレクトリに展開されます。このディレクトリには、ドキュメントのローカル コピー(ブラウザで documentation.html を開くと参照できます)と、tools/add-ons/platforms/ などのサブディレクトリが含まれます。platforms/ のサブディレクトリ内には、プラットフォームの各バージョンに固有のコードのサンプルが含まれる samples/ があります。

        + +

        システム上に展開した SDK ディレクトリの名前とパスをメモしておきましょう。Android プラグインの設定時や、SDK ツールの使用時にこの SDK ディレクトリを参照する必要があります。

        + +

        SDK のプライマリディレクトリである tools のパスを、システム PATH に追加することをおすすめします。tools/ プライマリディレクトリは、SDK フォルダのルートにあります。tools をパスに追加すると、Android Debug Bridge(adb)やその他のコマンド ライン ツールを、ツールの格納されたディレクトの完全なパスを指定せずに実行できるようになります。

        +
          +
        • Linux 上では ~/.bash_profile ファイルまたは ~/.bashrc ファイルを編集します。PATH 環境変数を設定している行を探し、その行に tools/ ディレクトリへの完全なパスを追加します。PATH を設定する行が無い場合は、次の行を追加します:
        • + +
            export PATH=${PATH}:<your_sdk_dir>/tools
          + +
        • Mac 上では .bash_profile のホーム ディレクトリの内から同じファイルを検索し、Linux と同じように設定します。マシン上にまだ .bash_profile が無い場合は、ファイルを作成することができます。
        • + +
        • Windows 上では、[マイ コンピュータ] を右クリックし、[プロパティ] を選択します。[詳細設定] タブで [環境変数] ボタンをクリックし、表示されたダイアログで [システム環境変数] の [Path] をダブルクリックします。その Path に tools/ ディレクトリへの完全なパスを追加します。
        • +
        + +

        今後 SDK をアップグレードする際は、PATH の設定を更新することを忘れないでください。別のディレクトリに SDK を展開する場合は、その新しい場所を PATH に設定する必要があります。

        + +

        Eclipse IDE を開発環境として使用する場合、Android Development Tools プラグインをインストールして Eclipse を設定する方法について、次のセクションの情報を参照してください。Eclipse を使用しない場合は、別の IDE を使用して Android アプリケーションを開発してから、SDK に含まれているツールを使用してコンパイル、デバッグ、配布を行うことができます(この場合は、次のステップに進んでください)。

        + + +

        Eclipse 用 ADT プラグインのインストール

        + +

        Android では、Android Development Tools(ADT)という Eclipse IDE 用のカスタム プラグインを提供しています。このプラグインは、Android アプリケーションの構築を可能にするために設計された、強力な統合環境です。プラグインによって Eclipse の機能が拡張され、新しい Android プロジェクトの設定、アプリケーションの UI の作成、Android Framework API に基づくコンポーネントの追加、Android SDK ツールを使用したアプリケーションのデバッグが可能になります。さらに、アプリケーションを配布するための署名済み(または未署名)の APK のエクスポートも簡単にできるようになります。

        + +

        一般的な Android 開発において、ADT を組み込んだ Eclipse の使用は強く推奨されており、Android 初心者に最も効率的な開発環境を提供します。(Eclipse 以外の IDE で作業する場合は、Eclipse や ADT をインストールする必要はありません。代わりに、SDK ツールを直接使用してアプリケーションを構築し、デバッグを行います)。

        + +

        インストールの準備で説明した手順に従って Eclipse をインストールした後は、次の手順に従って操作して ADT プラグインをダウンロードし、それぞれの Eclipse 環境にインストールします。

        + + + + + + + +
        Eclipse 3.3(Europa)Eclipse 3.4(Ganymede)
        + +
          +
        1. Eclipse を起動し、[ヘルプ] > [ソフトウェアの更新] > [検索とインストール] を選択します。
        2. +
        3. 表示されるダイアログで [インストールする新規フィーチャーを検索] を選択して [次へ] をクリックします。
        4. +
        5. [新規リモートサイト] をクリックします。
        6. +
        7. 表示されるダイアログ ボックスで、リモート サイトの名前(例: 「Android Plugin」)を入力し、URL を入力します: +
          https://dl-ssl.google.com/android/eclipse/
          +

          プラグインが入手できない場合は、URL の「https」の代わりに「http」を使用してみてください(セキュリティ上の理由からは、https をおすすめします)。

          +

          [OK] をクリックします。

        8. +
        9. 検索リストに新しいサイトが追加されており、チェックボックスがオンの状態で表示されるはずです。[終了] をクリックします。
        10. +
        11. 次の [検索結果] ダイアログボックスで、「Android Plugin」のチェックボックスをオンにします。これにより、そこに含まれているツール「Android DDMS」と「Android Development Tools」も自動的にオンになります。[次へ] をクリックします。
        12. +
        13. 使用許諾契約を読み、同意して、[次へ] をクリックします。
        14. +
        15. 次のインストール ウィンドウで [終了] をクリックします。
        16. +
        17. ADT プラグインはデジタル署名されていません。[すべてインストール] をクリックしてインストールを許可します。
        18. +
        19. Eclipse を再起動します。
        20. +
        + +
        + + +
          +
        1. Eclipse を起動し、[ヘルプ] > [ソフトウェアの更新] を選択します。
        2. +
        3. 表示されるダイアログで [使用可能なソフトウェア] タブをクリックします。
        4. +
        5. [サイトの追加] をクリックします。
        6. +
        7. 次の場所を入力します: +
          https://dl-ssl.google.com/android/eclipse/
          +

          プラグインが入手できない場合は、場所の URL の「https」の代わりに「http」を使用してみてください(セキュリティ上の理由からは、https をおすすめします)。

          +

          [OK] をクリックします。

        8. +
        9. [使用可能なソフトウェア] のタブに戻ると、上記の URL によるプラグインとその中に含まれる「Developer Tools」が表示されているはずです。「Developer Tools」の横のチェックボックスをオンにし、[インストール] をクリックします。
        10. +
        11. 次のインストール ウィンドウで、「Android DDMS」と「Android Development Tools」の両方のチェックボックスがオンになっていることを確認します。[次へ] をクリックします。
        12. +
        13. 使用許諾契約を読み、同意して、[終了] をクリックします。
        14. +
        15. Eclipse を再起動します。
        16. +
        + +
        + +

        次に、Eclipse の設定を変更して、Android SDK ディレクトリを指すように変更します:

        +
          +
        1. [ウィンドウ] > [設定] を選択して、[設定] パネルを開きます(Mac 上では [Eclipse] > [設定])。
        2. +
        3. 左側のパネルで [Android] を選択します。
        4. +
        5. メイン パネルの [SDK Location] で [参照] をクリックし、ダウンロードした SDK ディレクトリを探します。
        6. +
        7. [適用] をクリックして、[OK] をクリックします。
        8. +
        + +

        これで完了です。問題なく完了した場合は、Android アプリケーション開発を始める準備が整っています。開発を始めるヒントについては、次のステップのセクションをご覧ください。

        + + +

        ADT のインストールでのトラブルシューティング

        +

        +上記の手順で、ADT プラグインのダウンロードに問題が生じた場合のヒントは次のとおりです:

        + +
          +
        • Eclipse から ADT プラグインを含むリモート更新サイトが見つからない場合は、リモート サイトとして指定した URL の https を http に変更してみます。つまり、次のリモート サイトの URL を設定します: +
          http://dl-ssl.google.com/android/eclipse/
        • +
        • ファイアウォール(社内のファイアウォールなど)の内部にいる場合、Eclipse でプロキシ情報が正しく設定されていることを確認してください。Eclipse 3.3/3.4 でプロキシ情報を設定するには、Eclipse のメイン メニューから [ウィンドウ](Mac 上では [Eclipse])> [環境設定] > [一般] > [ネットワーク接続] を選択します。
        • +
        +

        +それでも Eclipse を使用して ADT プラグインをリモート更新サイトとしてダウンロードできない場合は、ADT zip ファイルをローカル マシン上にダウンロードして、手動でインストールすることができます: +

        +
          +
        1. ADT zip ファイルをダウンロードします(展開はしないでください)。
        2. +
        3. デフォルトのインストール手順(上記)のステップ 1 と 2 のとおりに操作します。
        4. +
        5. Eclipse 3.3 では [新規アーカイブ・サイト] をクリックします。
          Eclipse 3.4 では [サイトの追加] をクリックして、[アーカイブ] をクリックします。
        6. +
        7. ダウンロードした zip ファイルを参照して選択してください。
        8. +
        9. 上記のステップ 5 から残りの手順に従って操作します。
        10. +
        +

        zip ファイルからインストールしたプラグインを後でアップデートする場合は、デフォルトのアップデート手順の代わりに、もう一度この手順どおりに操作する必要があります。

        + +

        その他のインストール エラー

        + +

        オプションの Eclipse コンポーネント(WST など)を必要とする ADT の機能があります。ADT のインストール時にエラーが発生した場合、お使いの Eclipse インストール環境にこうしたコンポーネントが含まれていない可能性があります。必要なコンポーネントを Eclipse インストール環境に簡単に追加する方法について詳しくは、トラブルシューティング トピック ADT インストールエラー: "requires plug-in org.eclipse.wst.sse.ui" をご覧ください。

        + +

        Linux ユーザーの場合

        +

        Eclipse 用 ADT プラグインのインストール時に、次のエラーが発生する場合があります。 +

        +An error occurred during provisioning.
        +Cannot connect to keystore.
        +JKS
        +

        +この場合、お使いの開発用マシンに適切な Java VM が搭載されていません。Sun Java 6 をインストールするとこの問題が解決し、ADT プラグインを再インストールすることができます。

        + + +

        次のステップ

        +

        インストールを完了すると、アプリケーションの開発を始める準備が整います。開発を始める方法をいくつか紹介します:

        + +

        Android の詳細の学習

        + + +

        SDK の探索

        + + +

        サンプル コードの参照

        +
          +
        • Hello World アプリケーションを構築します(特に Eclipse ユーザーにおすすめです)。
        • +
        • Notepad チュートリアルに沿って Android アプリケーションを完全に構築します。
        • +
        • <sdk>/platforms/<platfrom>/samples に収められている他のサンプル アプリケーションのいずれかを新しいプロジェクトとして作成し、自分の開発環境でコンパイルし、実行します。
        • +
        + +

        Android デベロッパー グループへのアクセス

        +
          +
        • [コミュニティ] タブで、Android デベロッパー グループの一覧を参照します。特に Android Developers グループは、Android デベロッパー コミュニティがどういうものかを知るのに参考になります。
        • +
        + + +

        インストールに関する注意事項

        + +

        Ubuntu Linux に関する注意事項

        + +
          +
        • 開発マシン上で Java をインストールして設定する方法については、次のリソースが参考になります: + +
        • +
        • Android SDK と ADT プラグインをインストールする前に、Java と Eclipse をインストールする手順は次のとおりです。 +
            +
          1. 開発マシン上で 64 ビット版を実行している場合は、apt-get: を使用して ia32-libs パッケージをインストールする必要があります: +
            apt-get install ia32-libs
            +
          2. +
          3. 次に Java をインストールします:
            apt-get install sun-java6-bin
          4. +
          5. Ubuntu パッケージ マネージャでは現在、Eclipse 3.3 バージョンのダウンロードを提供していないので、eclipse.org( http://www.eclipse.org/downloads/ )から Eclipse をダウンロードすることをおすすめします。Eclipse の Java バージョンまたは RCP バージョンをおすすめします。
          6. +
          7. 上記のセクションの手順どおりに SDK と ADT プラグインをインストールします。
          8. +
          +
        • +
        + +

        その他の Linux に関する注意事項

        + +
          +
        • 開発用コンピュータに JDK が既にインストールされている場合は、システム要件に記載されているバージョン要件を満たしていることを確認してください。特に、ディストリビューションによっては JDK 1.4 または Gnu Compiler for Java が組み込まれている場合があります。これらは Android の開発ではサポートされていないので、ご注意ください。
        • +
        + + + diff --git a/docs/html/intl/ja/sdk/1.5_r3/installing.jd b/docs/html/intl/ja/sdk/1.5_r3/installing.jd new file mode 100644 index 0000000000000..bcb1ffba6355a --- /dev/null +++ b/docs/html/intl/ja/sdk/1.5_r3/installing.jd @@ -0,0 +1,212 @@ +page.title=Android SDK のインストール +@jd:body + + +

        このページでは、Android SDK をインストールして、開発環境を設定する方法について説明します。SDK をまだダウンロードしていない場合は、[ダウンロード] ページからダウンロードしてください。SDK をダウンロードした後に、このページの手順を行ってください。

        + +

        インストール中に問題が発生した場合は、このページの下部にあるインストールに関する注意事項を参照してください。

        + +

        アップグレードする場合

        +

        SDK の以前のバージョンを使用してアプリケーションを既に開発している場合は、このページの代わりに、SDK のアップグレード をご覧ください。 +

        + + +

        インストールの準備

        + +

        インストールを始める前に、開発用マシンがシステム要件を満たしていることを確認してください。 +

        + +

        Eclipse 環境に Android Development Tools(ADT)プラグインを組み込んだ開発環境は、Android 向け開発の初心者に最適です。プラグインを利用する場合は、コンピュータに Eclipse の適切なバージョン(3.3 以降)がインストールされていることを確認してください。Eclipse のインストールが必要な場合は、次の場所からダウンロードできます:

        + +

        http://www.eclipse.org/downloads/

        + +

        Eclipse の Java バージョンまたは RCP バージョンをおすすめします。

        + +

        SDK のインストール

        + +

        SDK のダウンロード後、お使いのマシンの適切な場所に .zip アーカイブを展開します。デフォルトでは、SDK ファイルは android_sdk_<platform>_<release> ディレクトリに展開されます。このディレクトリには、ドキュメントのローカル コピー(ブラウザで documentation.html を開くと参照できます)と、tools/add-ons/platforms/ などのサブディレクトリが含まれます。platforms/ のサブディレクトリ内には、プラットフォームの各バージョンに固有のコードのサンプルが含まれる samples/ があります。

        + +

        システム上に展開した SDK ディレクトリの名前とパスをメモしておきましょう。Android プラグインの設定時や、SDK ツールの使用時にこの SDK ディレクトリを参照する必要があります。

        + +

        SDK のプライマリディレクトリである tools のパスを、システム PATH に追加することをおすすめします。tools/ プライマリディレクトリは、SDK フォルダのルートにあります。tools をパスに追加すると、Android Debug Bridge(adb)やその他のコマンド ライン ツールを、ツールの格納されたディレクトの完全なパスを指定せずに実行できるようになります。

        +
          +
        • Linux 上では ~/.bash_profile ファイルまたは ~/.bashrc ファイルを編集します。PATH 環境変数を設定している行を探し、その行に tools/ ディレクトリへの完全なパスを追加します。PATH を設定する行が無い場合は、次の行を追加します:
        • + +
            export PATH=${PATH}:<your_sdk_dir>/tools
          + +
        • Mac 上では .bash_profile のホーム ディレクトリの内から同じファイルを検索し、Linux と同じように設定します。マシン上にまだ .bash_profile が無い場合は、ファイルを作成することができます。
        • + +
        • Windows 上では、[マイ コンピュータ] を右クリックし、[プロパティ] を選択します。[詳細設定] タブで [環境変数] ボタンをクリックし、表示されたダイアログで [システム環境変数] の [Path] をダブルクリックします。その Path に tools/ ディレクトリへの完全なパスを追加します。
        • +
        + +

        今後 SDK をアップグレードする際は、PATH の設定を更新することを忘れないでください。別のディレクトリに SDK を展開する場合は、その新しい場所を PATH に設定する必要があります。

        + +

        Eclipse IDE を開発環境として使用する場合、Android Development Tools プラグインをインストールして Eclipse を設定する方法について、次のセクションの情報を参照してください。Eclipse を使用しない場合は、別の IDE を使用して Android アプリケーションを開発してから、SDK に含まれているツールを使用してコンパイル、デバッグ、配布を行うことができます(この場合は、次のステップに進んでください)。

        + + +

        Eclipse 用 ADT プラグインのインストール

        + +

        Android では、Android Development Tools(ADT)という Eclipse IDE 用のカスタム プラグインを提供しています。このプラグインは、Android アプリケーションの構築を可能にするために設計された、強力な統合環境です。プラグインによって Eclipse の機能が拡張され、新しい Android プロジェクトの設定、アプリケーションの UI の作成、Android Framework API に基づくコンポーネントの追加、Android SDK ツールを使用したアプリケーションのデバッグが可能になります。さらに、アプリケーションを配布するための署名済み(または未署名)の APK のエクスポートも簡単にできるようになります。

        + +

        一般的な Android 開発において、ADT を組み込んだ Eclipse の使用は強く推奨されており、Android 初心者に最も効率的な開発環境を提供します。(Eclipse 以外の IDE で作業する場合は、Eclipse や ADT をインストールする必要はありません。代わりに、SDK ツールを直接使用してアプリケーションを構築し、デバッグを行います)。

        + +

        インストールの準備で説明した手順に従って Eclipse をインストールした後は、次の手順に従って操作して ADT プラグインをダウンロードし、それぞれの Eclipse 環境にインストールします。

        + + + + + + + +
        Eclipse 3.3(Europa)Eclipse 3.4(Ganymede)
        + +
          +
        1. Eclipse を起動し、[ヘルプ] > [ソフトウェアの更新] > [検索とインストール] を選択します。
        2. +
        3. 表示されるダイアログで [インストールする新規フィーチャーを検索] を選択して [次へ] をクリックします。
        4. +
        5. [新規リモートサイト] をクリックします。
        6. +
        7. 表示されるダイアログ ボックスで、リモート サイトの名前(例: 「Android Plugin」)を入力し、URL を入力します: +
          https://dl-ssl.google.com/android/eclipse/
          +

          プラグインが入手できない場合は、URL の「https」の代わりに「http」を使用してみてください(セキュリティ上の理由からは、https をおすすめします)。

          +

          [OK] をクリックします。

        8. +
        9. 検索リストに新しいサイトが追加されており、チェックボックスがオンの状態で表示されるはずです。[終了] をクリックします。
        10. +
        11. 次の [検索結果] ダイアログボックスで、「Android Plugin」のチェックボックスをオンにします。これにより、そこに含まれているツール「Android DDMS」と「Android Development Tools」も自動的にオンになります。[次へ] をクリックします。
        12. +
        13. 使用許諾契約を読み、同意して、[次へ] をクリックします。
        14. +
        15. 次のインストール ウィンドウで [終了] をクリックします。
        16. +
        17. ADT プラグインはデジタル署名されていません。[すべてインストール] をクリックしてインストールを許可します。
        18. +
        19. Eclipse を再起動します。
        20. +
        + +
        + + +
          +
        1. Eclipse を起動し、[ヘルプ] > [ソフトウェアの更新] を選択します。
        2. +
        3. 表示されるダイアログで [使用可能なソフトウェア] タブをクリックします。
        4. +
        5. [サイトの追加] をクリックします。
        6. +
        7. 次の場所を入力します: +
          https://dl-ssl.google.com/android/eclipse/
          +

          プラグインが入手できない場合は、場所の URL の「https」の代わりに「http」を使用してみてください(セキュリティ上の理由からは、https をおすすめします)。

          +

          [OK] をクリックします。

        8. +
        9. [使用可能なソフトウェア] のタブに戻ると、上記の URL によるプラグインとその中に含まれる「Developer Tools」が表示されているはずです。「Developer Tools」の横のチェックボックスをオンにし、[インストール] をクリックします。
        10. +
        11. 次のインストール ウィンドウで、「Android DDMS」と「Android Development Tools」の両方のチェックボックスがオンになっていることを確認します。[次へ] をクリックします。
        12. +
        13. 使用許諾契約を読み、同意して、[終了] をクリックします。
        14. +
        15. Eclipse を再起動します。
        16. +
        + +
        + +

        次に、Eclipse の設定を変更して、Android SDK ディレクトリを指すように変更します:

        +
          +
        1. [ウィンドウ] > [設定] を選択して、[設定] パネルを開きます(Mac 上では [Eclipse] > [設定])。
        2. +
        3. 左側のパネルで [Android] を選択します。
        4. +
        5. メイン パネルの [SDK Location] で [参照] をクリックし、ダウンロードした SDK ディレクトリを探します。
        6. +
        7. [適用] をクリックして、[OK] をクリックします。
        8. +
        + +

        これで完了です。問題なく完了した場合は、Android アプリケーション開発を始める準備が整っています。開発を始めるヒントについては、次のステップのセクションをご覧ください。

        + + +

        ADT のインストールでのトラブルシューティング

        +

        +上記の手順で、ADT プラグインのダウンロードに問題が生じた場合のヒントは次のとおりです:

        + +
          +
        • Eclipse から ADT プラグインを含むリモート更新サイトが見つからない場合は、リモート サイトとして指定した URL の https を http に変更してみます。つまり、次のリモート サイトの URL を設定します: +
          http://dl-ssl.google.com/android/eclipse/
        • +
        • ファイアウォール(社内のファイアウォールなど)の内部にいる場合、Eclipse でプロキシ情報が正しく設定されていることを確認してください。Eclipse 3.3/3.4 でプロキシ情報を設定するには、Eclipse のメイン メニューから [ウィンドウ](Mac 上では [Eclipse])> [環境設定] > [一般] > [ネットワーク接続] を選択します。
        • +
        +

        +それでも Eclipse を使用して ADT プラグインをリモート更新サイトとしてダウンロードできない場合は、ADT zip ファイルをローカル マシン上にダウンロードして、手動でインストールすることができます: +

        +
          +
        1. ADT zip ファイルをダウンロードします(展開はしないでください)。
        2. +
        3. デフォルトのインストール手順(上記)のステップ 1 と 2 のとおりに操作します。
        4. +
        5. Eclipse 3.3 では [新規アーカイブ・サイト] をクリックします。
          Eclipse 3.4 では [サイトの追加] をクリックして、[アーカイブ] をクリックします。
        6. +
        7. ダウンロードした zip ファイルを参照して選択してください。
        8. +
        9. 上記のステップ 5 から残りの手順に従って操作します。
        10. +
        +

        zip ファイルからインストールしたプラグインを後でアップデートする場合は、デフォルトのアップデート手順の代わりに、もう一度この手順どおりに操作する必要があります。

        + +

        その他のインストール エラー

        + +

        オプションの Eclipse コンポーネント(WST など)を必要とする ADT の機能があります。ADT のインストール時にエラーが発生した場合、お使いの Eclipse インストール環境にこうしたコンポーネントが含まれていない可能性があります。必要なコンポーネントを Eclipse インストール環境に簡単に追加する方法について詳しくは、トラブルシューティング トピック ADT インストールエラー: "requires plug-in org.eclipse.wst.sse.ui" をご覧ください。

        + +

        Linux ユーザーの場合

        +

        Eclipse 用 ADT プラグインのインストール時に、次のエラーが発生する場合があります。 +

        +An error occurred during provisioning.
        +Cannot connect to keystore.
        +JKS
        +

        +この場合、お使いの開発用マシンに適切な Java VM が搭載されていません。Sun Java 6 をインストールするとこの問題が解決し、ADT プラグインを再インストールすることができます。

        + + +

        次のステップ

        +

        インストールを完了すると、アプリケーションの開発を始める準備が整います。開発を始める方法をいくつか紹介します:

        + +

        Android の詳細の学習

        + + +

        SDK の探索

        + + +

        サンプル コードの参照

        +
          +
        • Hello World アプリケーションを構築します(特に Eclipse ユーザーにおすすめです)。
        • +
        • Notepad チュートリアルに沿って Android アプリケーションを完全に構築します。
        • +
        • <sdk>/platforms/<platfrom>/samples に収められている他のサンプル アプリケーションのいずれかを新しいプロジェクトとして作成し、自分の開発環境でコンパイルし、実行します。
        • +
        + +

        Android デベロッパー グループへのアクセス

        +
          +
        • [コミュニティ] タブで、Android デベロッパー グループの一覧を参照します。特に Android Developers グループは、Android デベロッパー コミュニティがどういうものかを知るのに参考になります。
        • +
        + + +

        インストールに関する注意事項

        + +

        Ubuntu Linux に関する注意事項

        + +
          +
        • 開発マシン上で Java をインストールして設定する方法については、次のリソースが参考になります: + +
        • +
        • Android SDK と ADT プラグインをインストールする前に、Java と Eclipse をインストールする手順は次のとおりです。 +
            +
          1. 開発マシン上で 64 ビット版を実行している場合は、apt-get: を使用して ia32-libs パッケージをインストールする必要があります: +
            apt-get install ia32-libs
            +
          2. +
          3. 次に Java をインストールします:
            apt-get install sun-java6-bin
          4. +
          5. Ubuntu パッケージ マネージャでは現在、Eclipse 3.3 バージョンのダウンロードを提供していないので、eclipse.org( http://www.eclipse.org/downloads/ )から Eclipse をダウンロードすることをおすすめします。Eclipse の Java バージョンまたは RCP バージョンをおすすめします。
          6. +
          7. 上記のセクションの手順どおりに SDK と ADT プラグインをインストールします。
          8. +
          +
        • +
        + +

        その他の Linux に関する注意事項

        + +
          +
        • 開発用コンピュータに JDK が既にインストールされている場合は、システム要件に記載されているバージョン要件を満たしていることを確認してください。特に、ディストリビューションによっては JDK 1.4 または Gnu Compiler for Java が組み込まれている場合があります。これらは Android の開発ではサポートされていないので、ご注意ください。
        • +
        + + + diff --git a/docs/html/sdk/1.5_r2/installing.jd b/docs/html/sdk/1.5_r2/installing.jd index 69b2c1bef5335..1530dc56e1db5 100644 --- a/docs/html/sdk/1.5_r2/installing.jd +++ b/docs/html/sdk/1.5_r2/installing.jd @@ -9,7 +9,7 @@ page.title=Installing the Android SDK

        This page describes how to install the Android SDK and set up your development environment. If you haven't downloaded the SDK, you can do so from the -Download page. Once you've downloaded +Download page. Once you've downloaded the SDK, return here.

        If you encounter any problems during installation, see the @@ -19,7 +19,7 @@ this page.

        Upgrading?

        If you have already developed applications using an earlier version of the SDK, please read -Upgrading the +Upgrading the SDK, instead.

        @@ -27,7 +27,7 @@ SDK, instead.

        Preparing for Installation

        Before you begin, take a moment to confirm that your development machine meets the -System Requirements. +System Requirements.

        If you will be developing on Eclipse with the Android Development @@ -323,7 +323,7 @@ begin developing applications. Here are a few ways you can get started:

        • If JDK is already installed on your development computer, please take a moment to make sure that it meets the version requirements listed - in the System Requirements. + in the System Requirements. In particular, note that some Linux distributions may include JDK 1.4 or Gnu Compiler for Java, both of which are not supported for Android development.
        diff --git a/docs/html/sdk/1.5_r3/index.jd b/docs/html/sdk/1.5_r3/index.jd new file mode 100644 index 0000000000000..3364f932f24f5 --- /dev/null +++ b/docs/html/sdk/1.5_r3/index.jd @@ -0,0 +1,87 @@ +sdk.version=1.5 +sdk.rel.id=3 +sdk.date=July 2009 + +sdk.win_download=android-sdk-windows-1.5_r3.zip +sdk.win_bytes=191477853 +sdk.win_checksum=1725fd6963ce69102ba7192568dfc711 + +sdk.mac_download=android-sdk-mac_x86-1.5_r3.zip +sdk.mac_bytes=183024673 +sdk.mac_checksum=b1bafdaefdcec89a14b604b504e7daec + +sdk.linux_download=android-sdk-linux_x86-1.5_r3.zip +sdk.linux_bytes=178117561 +sdk.linux_checksum=350d0211678ced38da926b8c9ffa4fac + +page.title=Android 1.5 SDK, Release 3 +@jd:body + +

        For more information on this SDK release, read the +Release Notes.

        + +

        SDK Contents

        + +

        Development tools

        + +

        The SDK includes a full set of tools for developing and debugging application code and designing an application UI. You can read about the tools in the +Dev Guide and access them in the <sdk>/tools/ directory. + +

        The tools package in this SDK includes updates from those provided in the previous SDK. The tools also require a different project structure. To use the new tools, you need to migrate your applications to the new development environment. For more information about how to migrate, see Upgrading the SDK. + +

        For more information about the new tools features, see the SDK Release Notes. + +

        Android Platforms

        + +

        This SDK includes multiple Android platform versions that you use to develop applications. For each version, both a fully compliant Android library and system image are provided. The table below lists the platform versions included in this SDK. For more information about a platform version — features, applications included, localizations, API changes, and so on — see its Version Notes.

        + + + + + + + + + + + + + + + + + + +
        PlatformAPI LevelNotesDescription
        Android 1.53Version NotesIncludes a standard Android 1.5 library and system image with a set of development applications. Does not include any external libraries (such as the Maps external library).
        Android 1.12Version NotesIncludes a compliant Android 1.1 library and system image with a set of development applications. Also includes the Maps external library (due to legacy build system issues).
        + +

        SDK Add-Ons

        + +

        An SDK add-on provides a development environment for an Android external library or a customized (but fully compliant) Android system image. This SDK includes the SDK add-on listed below. The Android system API Level required by the add-on is noted.

        + + + + + + + + + + + +
        Add-OnAPI LevelNotesDescription
        Google APIs3 Includes the com.google.android.maps external library, a compliant +system image, a {@link android.location.Geocoder Geocoder} +backend service implementation, documentation, and sample code.
        + +

        Sample Code and Applications

        + +

        You can look at a variety of tutorials and samples in the Dev Guide and access the sample code itself +in the <sdk>/platforms/android-1.5/samples/ directory of the SDK package. Note the new location — the SDK now includes multiple platform versions that you can develop against and each has its own sample code directory.

        + +

        Documentation

        + +

        The SDK package includes a full set of local documentation. To view it, open the <sdk>/documentation.html file in a web browser. If you are developing in an IDE such as Eclipse, you can also view the reference documentation directly in the IDE.

        + +

        The most current documentation is always available on the Android Developers site:

        + +

        http://developer.android.com/

        + diff --git a/docs/html/sdk/1.5_r3/installing.jd b/docs/html/sdk/1.5_r3/installing.jd new file mode 100644 index 0000000000000..8c3e8ee841864 --- /dev/null +++ b/docs/html/sdk/1.5_r3/installing.jd @@ -0,0 +1,332 @@ +sdk.version=1.5 +sdk.rel.id=3 +sdk.date=April 2009 + +page.title=Installing the Android SDK +@jd:body + + +

        This page describes how to install the Android SDK and set up your +development environment. If you haven't downloaded the SDK, you can +do so from the +Download page. Once you've downloaded +the SDK, return here.

        + +

        If you encounter any problems during installation, see the +Installation Notes at the bottom of +this page.

        + +

        Upgrading?

        +

        If you have already developed applications using an earlier version +of the SDK, please read +Upgrading the +SDK, instead. +

        + + +

        Preparing for Installation

        + +

        Before you begin, take a moment to confirm that your development machine meets the +System Requirements. +

        + +

        If you will be developing on Eclipse with the Android Development +Tools (ADT) Plugin — the recommended path if you are new to +Android — make sure that you have a suitable version of Eclipse +installed on your computer (3.3 or newer). If you need to install Eclipse, you can +download it from this location:

        + +

        http://www.eclipse.org/downloads/

        + +

        A Java or RCP version of Eclipse is recommended.

        + +

        Installing the SDK

        + +

        After downloading the SDK, unpack the .zip archive to a suitable location on your machine. +By default, the SDK files are unpacked into a directory named +android_sdk_<platform>_<release>. +The directory contains a local copy of the documentation (accessible by opening +documentation.html in your browser) and the subdirectories +tools/, add-ons/, platforms/, and others. Inside +each subdirectory of platforms/ you'll find samples/, which includes +code samples that are specific to each version of the platform.

        + +

        Make a note of the name and location of the unpacked SDK directory on your system — you +will need to refer to the SDK directory later, when setting up the Android plugin or when +using the SDK tools.

        + +

        Optionally, you may want to add the location of the SDK's primary tools directory +to your system PATH. The primary tools/ directory is located at the root of the +SDK folder. Adding tools to your path lets you run Android Debug Bridge (adb) and +the other command line tools without +needing to supply the full path to the tools directory.

        +
          +
        • On Linux, edit your ~/.bash_profile or ~/.bashrc file. Look + for a line that sets the PATH environment variable and add the + full path to the tools/ directory to it. If you don't + see a line setting the path, you can add one:
        • + +
            export PATH=${PATH}:<your_sdk_dir>/tools
          + +
        • On a Mac, look in your home directory for .bash_profile and + proceed as for Linux. You can create the .bash_profile if + you haven't already set one up on your machine.
        • + +
        • On Windows, right-click on My Computer, and select Properties. + Under the Advanced tab, hit the Environment Variables button, and in the + dialog that comes up, double-click on Path (under System Variables). Add the full path to the + tools/ directory to the path.
        • +
        + +

        Note that, if you update your SDK in the future, you +should remember to update your PATH settings to point to the new location, if different.

        + +

        If you will be using the Eclipse IDE as your development environment, +the next section describes how to install the Android Development Tools plugin and set up Eclipse. +If you choose not to use Eclipse, you can +develop Android applications in an IDE of your choice and then compile, debug and deploy using +the tools included in the SDK (skip to Next Steps).

        + + +

        Installing the ADT Plugin for Eclipse

        + +

        Android offers a custom plugin for the Eclipse IDE, called Android +Development Tools (ADT), that is designed to give you a powerful, +integrated environment in which to build Android applications. It +extends the capabilites of Eclipse to let you quickly set up new Android +projects, create an application UI, add components based on the Android +Framework API, debug your applications using the Android SDK tools, and even export +signed (or unsigned) APKs in order to distribute your application.

        + +

        In general, using Eclipse with ADT is a highly recommended +approach to Android development and is the fastest way to get started. +(If you prefer to work in an IDE other than Eclipse, +you do not need to install Eclipse or ADT, instead, you can directly +use the SDK tools to build and debug your application.)

        + +

        Once you have Eclipse installed, as described in Preparing for +Installation, follow the steps below to +download the ADT plugin and install it in your respective Eclipse +environment.

        + + + + + + + +
        Eclipse 3.3 (Europa)Eclipse 3.4 (Ganymede)
        + +
          +
        1. Start Eclipse, then select Help > Software Updates +> Find and Install....
        2. +
        3. In the dialog that appears, select Search for new features to install +and click Next.
        4. +
        5. Click New Remote Site.
        6. +
        7. In the resulting dialog box, enter a name for the remote site (e.g. "Android Plugin") and + enter the URL: +
          https://dl-ssl.google.com/android/eclipse/
          +

          If you have trouble aqcuiring the plugin, try using "http" in the URL, + instead of "https" (https is preferred for security reasons).

          +

          Click OK.

        8. +
        9. You should now see the new site added to the search list (and checked). + Click Finish.
        10. +
        11. In the subsequent Search Results dialog box, select the checkbox for the + "Android Plugin". + This will select the nested tools: "Android DDMS" and "Android Development Tools". + Click Next.
        12. +
        13. Read and accept the license agreement, then click Next.
        14. +
        15. On the following Installation window, click Finish.
        16. +
        17. The ADT plugin is not digitally signed. Accept the installation anyway + by clicking Install All.
        18. +
        19. Restart Eclipse.
        20. +
        + +
        + + +
          +
        1. Start Eclipse, then select Help > Software Updates....
        2. +
        3. In the dialog that appears, click the Available Software tab.
        4. +
        5. Click Add Site...
        6. +
        7. Enter the Location: +
          https://dl-ssl.google.com/android/eclipse/
          +

          If you have trouble aqcuiring the plugin, try using "http" in the Location URL, + instead of "https" (https is preferred for security reasons).

          +

          Click OK.

        8. +
        9. Back in the Available Software view, you should see the plugin listed by the URL, + with "Developer Tools" nested within it. Select the checkbox next to + Developer Tools and click Install...
        10. +
        11. On the subsequent Install window, "Android DDMS" and "Android Development Tools" + should both be checked. Click Next.
        12. +
        13. Read and accept the license agreement, then click Finish.
        14. +
        15. Restart Eclipse.
        16. +
        + +
        + +

        Now modify your Eclipse preferences to point to the Android SDK directory:

        +
          +
        1. Select Window > Preferences... to open the Preferences + panel (Mac: Eclipse > Preferences).
        2. +
        3. Select Android from the left panel.
        4. +
        5. For the SDK Location in the main panel, click Browse... and +locate your downloaded SDK directory.
        6. +
        7. Click Apply, then OK.
        8. +
        + +

        Done! If you haven't encountered any problems, then you're ready to +begin developing Android applications. See the +Next Steps section for suggestions on how to start.

        + + +

        Troubleshooting ADT Installation

        +

        +If you are having trouble downloading the ADT plugin after following the steps above, here are +some suggestions:

        + +
          +
        • If Eclipse can not find the remote update site containing the ADT plugin, try changing + the remote site URL to use http, rather than https. That is, set the Location for the remote site to: +
          http://dl-ssl.google.com/android/eclipse/
        • +
        • If you are behind a firewall (such as a corporate firewall), make + sure that you have properly configured your proxy settings in Eclipse. + In Eclipse 3.3/3.4, you can configure proxy information from the main + Eclipse menu in Window (on Mac, Eclipse) > + Preferences > General > + Network Connections.
        • +
        +

        +If you are still unable to use Eclipse to download the ADT plugin as a remote update site, you +can download the ADT zip file to your local machine and manually install the it: +

        +
          +
        1. Download the ADT zip file (do not unpack it).
        2. +
        3. Follow steps 1 and 2 in the default install instructions (above).
        4. +
        5. In Eclipse 3.3, click New Archive Site....
          + In Eclipse 3.4, click Add Site..., then Archive...
        6. +
        7. Browse and select the downloaded zip file.
        8. +
        9. Follow the remaining procedures, above, starting from steps 5.
        10. +
        +

        To update your plugin once you've installed using the zip file, you will have to +follow these steps again instead of the default update instructions.

        + +

        Other install errors

        + +

        Note that there are features of ADT that require some optional +Eclipse components (for example, WST). If you encounter an error when +installing ADT, your Eclipse installion might not include these components. +For information about how to quickly add the necessary components to your +Eclipse installation, see the troubleshooting topic +ADT +Installation Error: "requires plug-in org.eclipse.wst.sse.ui".

        + +

        For Linux users

        +

        If you encounter this error when installing the ADT Plugin for Eclipse: +

        +An error occurred during provisioning.
        +Cannot connect to keystore.
        +JKS
        +

        +...then your development machine lacks a suitable Java VM. Installing Sun +Java 6 will resolve this issue and you can then reinstall the ADT +Plugin.

        + + +

        Next Steps

        +

        Once you have completed installation, you are ready to +begin developing applications. Here are a few ways you can get started:

        + +

        Learn about Android

        +
          +
        • Take a look at the Dev + Guide and the types of information it provides
        • +
        • Read an introduction to Android as a platform in What is + Android?
        • +
        • Learn about the Android framework and how applications run on it in + Application + Fundamentals
        • +
        • Take a look at the Android framework API specification in the Reference tab
        • +
        + +

        Explore the SDK

        + + +

        Explore some code

        +
          +
        • Set up a Hello + World application (highly recommended, especially for Eclipse users)
        • +
        • Follow the + Notepad Tutorial to build a full Android application
        • +
        • Create a new project for one of the other sample applications + included in <sdk>/platforms/<platfrom>/samples, + then compile and run it in your development environment
        • +
        + +

        Visit the Android developer groups

        +
          +
        • Take a look at the Community tab to see a list of + Android developers groups. In particular, you might want to look at the + Android + Developers group to get a sense for what the Android developer + community is like.
        • +
        + + +

        Installation Notes

        + +

        Ubuntu Linux Notes

        + +
          +
        • If you need help installing and configuring Java on your + development machine, you might find these resources helpful: + +
        • +
        • Here are the steps to install Java and Eclipse, prior to installing + the Android SDK and ADT Plugin. +
            +
          1. If you are running a 64-bit distribution on your development + machine, you need to install the ia32-libs package using + apt-get:: +
            apt-get install ia32-libs
            +
          2. +
          3. Next, install Java:
            apt-get install sun-java6-bin
          4. +
          5. The Ubuntu package manager does not currently offer an Eclipse 3.3 + version for download, so we recommend that you download Eclipse from + eclipse.org (http://www.eclipse.org/ + downloads/). A Java or RCP version of Eclipse is recommended.
          6. +
          7. Follow the steps given in previous sections to install the SDK + and the ADT plugin.
          8. +
          +
        • +
        + +

        Other Linux Notes

        + +
          +
        • If JDK is already installed on your development computer, please + take a moment to make sure that it meets the version requirements listed + in the System Requirements. + In particular, note that some Linux distributions may include JDK 1.4 or Gnu + Compiler for Java, both of which are not supported for Android development.
        • +
        + + + diff --git a/docs/html/sdk/1.5_r3/requirements.jd b/docs/html/sdk/1.5_r3/requirements.jd new file mode 100644 index 0000000000000..4ed38a741261c --- /dev/null +++ b/docs/html/sdk/1.5_r3/requirements.jd @@ -0,0 +1,39 @@ +page.title=System Requirements +@jd:body + +

        The sections below describe the system and software requirements for developing Android applications using the Android SDK tools included in Android SDK, Release .

        + +

        Supported Operating Systems

        +
          +
        • Windows XP (32-bit) or Vista (32- or 64-bit)
        • +
        • Mac OS X 10.4.8 or later (x86 only)
        • +
        • Linux (tested on Linux Ubuntu Dapper Drake)
        • +
        + +

        Supported Development Environments

        +
          +
        • Eclipse IDE +
            +
          • Eclipse 3.3 (Europa), 3.4 (Ganymede) +
              +
            • Recommended Eclipse IDE packages: Eclipse IDE for Java EE Developers, Eclipse IDE for Java Developers, Eclipse for RCP/Plug-in Developers
            • +
            • Eclipse JDT plugin (included in most Eclipse IDE packages)
            • +
            • Eclipse Classic IDE package is not supported.
            • +
            +
          • +
          • JDK 5 or JDK 6 (JRE alone is not sufficient)
          • +
          • Android Development Tools plugin (optional)
          • +
          • Not compatible with Gnu Compiler for Java (gcj)
          • +
          +
        • +
        • Other development environments or IDEs +
            +
          • JDK 5 or JDK 6 (JRE alone is not sufficient)
          • +
          • Apache Ant 1.6.5 or later for Linux and Mac, 1.7 or later for Windows
          • +
          • Not compatible with Gnu Compiler for Java (gcj)
          • +
          +
        • +
        + +

        Note: If JDK is already installed on your development computer, please take a moment to make sure that it meets the version requirements listed above. In +particular, note that some Linux distributions may include JDK 1.4 or Gnu Compiler for Java, both of which are not supported for Android development.

        \ No newline at end of file diff --git a/docs/html/sdk/1.5_r3/upgrading.jd b/docs/html/sdk/1.5_r3/upgrading.jd new file mode 100644 index 0000000000000..a0a62a20c021a --- /dev/null +++ b/docs/html/sdk/1.5_r3/upgrading.jd @@ -0,0 +1,395 @@ +page.title=Upgrading the SDK +sdk.version=1.5_r3 +@jd:body + + +
        +
        + +

        Upgrading the SDK

        +
          +
        • The Android 1.5 SDK uses a new project structure and a new ADT plugin (ADT 0.9).
        • +
        • To move existing projects into the SDK, you must make some minor changes in your + development environment.
        • +
        • The new ADT plugin (ADT 0.9) is not compatible with projects created in previous SDKs.
        • +
        • You need to uninstall your existing ADT plugin, before installing ADT 0.9.
        • +
        + +

        In this document

        +
          +
        1. Install the SDK
        2. +
        3. Update Your Eclipse ADT Plugin
        4. +
        5. Update Your Projects +
            +
          1. Eclipse Users
          2. +
          3. Ant Users
          4. +
          +
        6. +
        7. Migrate Your Applications +
          1. Future-proof your apps
          +
        8. +
        + +

        Migrating references

        +
          +
        1. Android 1.5 API Differences
        2. +
        3. Future-Proofing +Your Apps »
        4. +
        5. UI +framework changes in Android 1.5 »
        6. +
        + +
        +
        + +

        This document describes how to move your development environment and existing +Android applications from an Android 1.0 or 1.1 SDK to the Android 1.5 SDK. +If you are migrating applications from an SDK older than 1.0, please also read the upgrading +document available in the Android 1.0 SDK package.

        + +

        There are several compelling reasons to upgrade, such as new SDK tools +that make developing more efficient and new APIs that allow you to expand the feature-set +of your applications. However, even if you or your applications don't require these enhancements, +it's important that you upgrade to ensure that your applications run properly on the +Android 1.5 platform.

        + +

        The Android 1.5 platform will soon be deployable to devices around the world. +If you have already released Android applications to the public, you should +test the forward-compatibility of your applications on the latest version of the platform +as soon as possible. It's unlikely that you'll encounter breakage in your applications, but +in the interest of maintaining the best user experience, you should take no risks. +So, please install the new Android SDK and test your applications on Android 1.5.

        + +

        For more information on new SDK features and system changes, +see the Android 1.5 Version Notes.

        + + +

        Install the SDK

        + +

        If you haven't yet downloaded the SDK, download from here +and unpack it into a safe location.

        + +

        Before you begin: +If you had previously setup your PATH variable to point to the SDK tools directory, +then you need to update it to point to the new SDK. For example, for a +.bashrc or .bash_profile file:

        +
        export PATH=$PATH:<your_sdk_dir>/tools
        + +

        If you don't use Eclipse for development, +skip to Update Your Projects.

        + + +

        Update Your Eclipse ADT Plugin

        + +

        If you installed ADT-0.9_pre with the early look 1.5 SDK, there have been +additional changes, so please continue with this guide and update to the final ADT 0.9.

        + +

        A new ADT plugin (version 0.9) is required for the Android 1.5 SDK. +Because the component structure has been changed since Android 1.1, +the Android 1.5 SDK does not work with ADT 0.8 (or older) and previously installed SDKs will not +work with ADT 0.9. However, the Android 1.5 SDK includes an Android 1.1 SDK image that you +can build against while using ADT 0.9.

        + +

        For information about using different system images (such as Android 1.1) +while running this SDK, see Developing +In Eclipse, with ADT or In +Other IDEs, as appropriate for your development environment.

        + +

        In order to upgrade your Eclipse IDE to use the new 0.9 ADT, follow the steps below +for your respective version of Eclipse.

        + +

        Uninstall your previous ADT plugin

        + +

        You must uninstall your existing ADT plugin (0.8 or older). If you do not uninstall it, +you will get a conflict with the Android Editors when installing the new ADT. +(If you have already installed ADT-0.9_pre with the early look 1.5 SDK, you can skip this +uninstall procedure and continue to Install the 0.9 ADT plugin).

        + + + + + + + +
        Eclipse 3.3 (Europa)Eclipse 3.4 (Ganymede)
        + +
          +
        1. Select Help > Software Updates > + Manage Configuration.
        2. +
        3. Expand the list in the left panel to reveal the installed tools.
        4. +
        5. Right-click "Android Editors" and click Uninstall. Click OK + to confirm.
        6. +
        7. Restart Eclipse. +

          (Do not uninstall "Android Development Tools".)

        8. +
        +
        + +
          +
        1. Select Help > Software Updates.
        2. +
        3. Select the Installed Software tab.
        4. +
        5. Select "Android Editors". Click Uninstall.
        6. +
        7. In the next window, be sure "Android Editors" is checked, then click Finish + to uninstall.
        8. +
        9. Restart Eclipse. +

          (Do not uninstall "Android Development Tools".)

        10. +
        +
        + + +

        Install the 0.9 ADT plugin

        + +

        Only install the new plugin once you've completed the procedure to +Uninstall your previous ADT plugin.

        + + + + + + + +
        Eclipse 3.3 (Europa)Eclipse 3.4 (Ganymede)
        + +
          +
        1. Select Help > Software Updates > + Find and Install.
        2. +
        3. Select Search for new features to install.
        4. +
        5. Select the Android plugin entry by checking the box next to it, + then click Finish. +

          (Your original entry for the plugin should still be here. If not, see the guide + to Installing the ADT Plugin.) +

        6. +
        7. In the results, expand the entry for the Android plugin and + be sure that "Developer Tools" is checked, then click Next. + (This will install "Android DDMS" and "Android Development Tools".)
        8. +
        9. Read and accept the license agreement, then click Next. +
        10. In the next window, click Finish to start installation.
        11. +
        12. The ADT plugin is not digitally signed. Accept the installation anyway by clicking + Install All.
        13. +
        14. Restart Eclipse.
        15. +
        +
        + +
          +
        1. Select Help > Software Updates.
        2. +
        3. Select the Available Software tab.
        4. +
        5. Expand the entry for the Andriod plugin (may be listed as the location URL) + and select "Developer Tools" by checking the box next to it, then click + Install.
        6. +
        7. On the next window, "Android DDMS" and "Android Development Tools" + should both be checked. Click Finish.
        8. +
        9. Restart Eclipse.
        10. +
        +
        + +

        If you encounter problems, ensure your ADT is fully uninstalled and then +follow the guide to +Installing the ADT Plugin +for Eclipse.

        + +

        Update your Eclipse SDK Preferences

        + +

        The last step is to update your Eclipse preferences to point to the new SDK directory:

        +
          +
        1. Select Window > Preferences to open the Preferences + panel (Mac: Eclipse > Preferences).
        2. +
        3. Select Android from the left panel.
        4. +
        5. For the SDK Location in the main panel, click Browse + and locate your SDK directory.
        6. +
        7. Click Apply, then OK.
        8. +
        + + +

        Update Your Projects

        + +

        You will now need to update any and all Android projects that you have +developed using a previous version of the Android SDK.

        + + +

        Eclipse users

        + +

        If you use Eclipse to develop applications, use the following procedure to +update each project:

        + +
          +
        1. Right-click on the individual project (in the Package Explorer) + and select Properties.
        2. +
        3. In the properties, open the Android panel and select a "build target" to compile + against. This SDK offers the Android 1.1 and Android 1.5 platforms to choose from. When + you are initially updating your projects to the new SDK, we recommend that you select a build + target with the Android 1.1 platform. Click Apply, then + OK.
        4. +
        + +

        The new plugin creates a gen/ folder in your project, in which it puts the +R.java file +and all automatically generated AIDL java files. If you get an error such as +The type R is already defined, +then you probably need to delete your old R.java or your old auto-generated +AIDL Java files in the src/ folder. +(This does not apply to your own hand-crafted parcelable AIDL java files.)

        + +

        Note that, with the Android 1.5 SDK, there is a new process for running +applications in the Android Emulator. +Specifically, you must create an Android Virtual Device (AVD) before you can launch an instance +of the Emulator. Before attempting to run your applications with the new SDK, +please continue with the section below to +Migrate Your Applications.

        + + +

        Ant users

        + +

        If you build your projects using the Ant tool (rather than with Eclipse), note the +following changes with the new SDK tools.

        + +

        build.xml has changed

        + +

        You must re-create your build.xml file.

        + +

        If you had customized your build.xml, first make a copy of it:

        + +
        +$ cd my-project
        +$ cp build.xml build.xml.old
        +
        + +

        Now use the new android tool (located in your_sdk/tools/) +to create a new build.xml that references +a specific platform target:

        + +
        $ android update project --path /path/to/my-project --target 1
        + +

        The "target" corresponds to an Android platform library (including any add-ons, such as +Google APIs) that you would like to build your project against. You can view a list of available +targets (and their corresponding integer ID) with the command, android list targets. +When you are initially updating your projects to the new SDK, we recommend that you select the +first target ("1"), which uses the Android 1.1 platform library.

        + +

        A gen/ folder will be created the first time you build and your R.java and +your AIDL Java files will be generated in here. You must remove +the old R.java and old auto-generated AIDL java files from the +src/ folder. (This +does not apply to your own hand-crafted parcelabe AIDL java files.)

        + +

        Note: The "activitycreator" tool has been replaced +by the new "android" tool. For information on creating new projects with the android tool, +see the documentation about Developing +In Other IDEs.

        + +

        Note that, with the Android 1.5 SDK, there is a new process for running +applications in the Android Emulator. +Specifically, you must create an Android Virtual Device (AVD) before you can launch an instance +of the Emulator. Before attempting to run your applications with the new SDK, +please continue with the section below to +Migrate Your Applications.

        + + +

        Migrate Your Applications

        + +

        After you have completed the process above to Update Your +Projects, you are strongly encouraged to run each of your applications in an instance +of the emulator running the Android 1.5 system image. It's possible (however, unlikely) +that you'll encounter some breakage in your application when you run your applications on +the Android 1.5 system image. Whether you believe your application will be affected by +platform changes or not, it's very important that you test the application's +forward-compatibility on Android 1.5.

        + +

        To test forward-compatibility, simply run your existing application (as-is) on an Android +Emulator that's running the Android 1.5 system image. The following procedure will guide +you through the process to running your existing applications on an emulator. Please read +the following guide completely before you begin.

        + +

        To test your application on an emulator running Android 1.5:

        +
          +
        1. Update Your Project (you should have done this + already, in the section above).
        2. +
        3. Run your existing project, as-is, on an emulator running the Android 1.5 system image. +

          As mentioned in the guide to Update Your Projects, + you should have selected a "build + target" of "1", which compiles your application against the Android 1.1 system image, so there + should be no new errors in your code.

          +

          Eclipse users: follow the + Eclipse guide to + Running Your Application.

          +

          Ant users: follow the + Ant guide to + Running Your Application +

          During the procedure to Running Your Application, select a "deployment target" + for the AVD that includes the Android 1.5 platform. + If your application utilizes the Google Maps APIs (i.e., + MapView), be certain to select a target that includes the Google APIs.

          +

          Once you complete the procedures to run your application in your respective environment, + linked above, return here.

          +
        4. +
        5. With your application running in the emulator, perform all regular testing on the application + to ensure that it functions normally (in both landscape and portrait orientations).
        6. +
        + +

        Chances are, your application runs just fine on the Android 1.5 platform — +new devices will be able to safely install and run your application and +current users who update their devices will be able to continue using your application as usual. +However, if something doesn't work the way you expect, then you might need to revisit +your project and make any necessary changes to your code.

        + +

        You can check for code breakages caused by API changes by opening your project +in Eclipse, changing the "build target" to one using the Android 1.5 platform, +and see where the ADT identifies errors in your code.

        + + +

        Future-proof your apps

        + +

        There have been several API additions made for this release, but there have been +very few actual API changes. Only a couple (relatively unused) elements +have been removed and a few have been deprecated, so your applications written with the +Android 1.1 system library should work just fine. However, +your application is more likely to encounter problems on Android 1.5 +if it performs any of the following:

        + +
          +
        • Uses internal APIs. That is, APIs that are not officially supported + and not available in the reference documentation. Any un-official APIs are always subject + to change (which is why they're un-official) and some have indeed changed. +
        • +
        • Directly manipulates system settings. There are some settings (such as + GPS, data roaming, bluetooth and others) that used to be writable by + applications but have been changed so that they can only be explicitly modified by the user + through the system settings. Refer to {@link android.provider.Settings.Secure} + to see which settings are now secured and cannot be directly changed by your application. +
        • +
        • Uses View hierarchies that are unreasonably deep (more than 10 or so levels) or + broad (more than 30 total). View hierarchies this big have always been troublesome, but + Android 1.5 is much more efficient at exposing this and your application may crash. +
        • +
        • Makes assumptions about the available hardware. With new support for soft keyboards, + not all devices will have full QWERTY keyboards on the hardware. So if your application + listens for special keypress events that only occur on a keypad, then your application + should degrade gracefully when there is no keyboard available. +
        • +
        • Performs its own layout orientation changes based on the acceletometer (or via other + sensors). Some devices running Android 1.5 will automatically rotate the orientation + (and all devices have the option to turn on auto-rotation), so if your application also + attempts to rotate the orientation, it can result in strange behavior. In addition, if your + application uses the accelerometer to detect shaking and you do not want to rotate the + orientation, then you should lock the current orientation with + android:screenOrientation. +
        • +
        + +

        Please read our blog post on Future-Proofing +Your Apps for more information on the issues mentioned above.

        + +

        For information +about other changes made to Android 1.5, refer to the following documents:

        + + +

        If you have additional trouble updating your code, visit the +Android Developers Group +to seek help from other Android developers.

        diff --git a/docs/html/sdk/RELEASENOTES.jd b/docs/html/sdk/RELEASENOTES.jd index f3a1951f71fbc..03eeb4bb8ddbe 100644 --- a/docs/html/sdk/RELEASENOTES.jd +++ b/docs/html/sdk/RELEASENOTES.jd @@ -5,6 +5,75 @@ page.title=SDK Release Notes releases. For the latest known issues, please ensure that you're viewing this page at http://developer.android.com/sdk/RELEASENOTES.html.

        +

        Android 1.5 SDK, Release 3

        + +

        Provides an updated Android 1.5 system image that includes permissions +fixes, as described below, and a new application — an IME for Japanese +text input. Also provides the same set of developer tools included in the +previous SDK, but with bug fixes and several new features.

        + +

        Permissions Fixes

        + +

        The latest version of the Android platform, deployable to +Android-powered devices, includes fixes to the permissions-checking +in certain areas of the framework. Specifically, the Android system +now properly checks and enforces several existing permissions where it +did not do so in the previous release. Because of these changes in +enforcement, you are strongly encouraged to test your application +against the new Android 1.5 system image included in this SDK, to ensure +that it functions normally.

        + +

        In particular, if your application uses any of the system areas listed below, +you should add the required permissions to the application's manifest and then +test the areas of your code that depend on the permission-protected services. +Even if you believe your application does not use the permissions-protected +services, you should compile and test your application under the latest platform +version to ensure that users will not encounter problems when using your +application.

        + +

        The changes to permissions are as follows:

        + +
          +
        • When an application requests access to device camera (through +android.hardware.camera), the CAMERA permission check is now +properly enforced.
        • +
        • When an application requests access to device audio capture (through +android.media.MediaRecorder), the RECORD_AUDIO permission check is +now properly enforced.
        • +
        + +

        For more information, see the issue described in the oCert advisory +below:

        + +

        http://www.ocert.org/advisories/ocert-2009-011.html

        + +

        Resolved Issues, Changes

        + +
          +
        • The SDK includes a new version of the Google APIs add-on. The add-on +provides an updated com.google.android.maps external library that fixes compile +errors related to certain classes such as GeoPoint. For information about the +Google APIs add-on and the library it provides, see: + +

          http://code.google.com/android/add-ons/google-apis

        • + +
        • The SDK add-on architecture now lets device manufacturers specify a USB +Vendor ID in their add-ons. +
        • The android tool provides a new command that scans SDK add-ons +for their USB Vendor IDs and makes them available to adb (OS X and Linux +versions of the SDK only). The command is android update adb. On +Windows versions of the SDK, a custom USB driver is included that supports the +"Google" and "HTC" Vendor IDs, which allow adb to recognize G1 and HTC +Magic devices. For other devices, contact the device manufacturer +to obtain a USB driver, especially if you have an SDK add-on that defines +a new USB Vendor ID.
        • +
        • The telephony, sensor, and geo fix issues in the emulator are now +fixed.
        • +
        • When you use adb to uninstall an upgraded application, the Android system +now properly restores any permissions that had already been granted to the +previous (downgrade) version of the application
        • +

        Android 1.5 SDK, Release 2

        diff --git a/docs/html/sdk/android-1.5.jd b/docs/html/sdk/android-1.5.jd index addd64465fb6d..748f3ee4e44b0 100644 --- a/docs/html/sdk/android-1.5.jd +++ b/docs/html/sdk/android-1.5.jd @@ -125,6 +125,7 @@ application against the Android library that corresponds to the application's
      10. Dialer
      11. Email
      12. Gallery
      13. +
      14. IME for Japanese text input
      15. Messaging
      16. Music
      17. Settings
      18. diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd index 38db6f80de08c..2ac76888ee32a 100644 --- a/docs/html/sdk/index.jd +++ b/docs/html/sdk/index.jd @@ -1,4 +1,5 @@ -sdk.redirect=1.1_r1 +sdk.redirect=true + @jd:body diff --git a/docs/html/sdk/ndk/1.5-r1/index.jd b/docs/html/sdk/ndk/1.5_r1/index.jd similarity index 82% rename from docs/html/sdk/ndk/1.5-r1/index.jd rename to docs/html/sdk/ndk/1.5_r1/index.jd index 3d3137c51dfdc..7ccbbcd4f5ba5 100644 --- a/docs/html/sdk/ndk/1.5-r1/index.jd +++ b/docs/html/sdk/ndk/1.5_r1/index.jd @@ -1,32 +1,35 @@ ndk=true ndk.version=1.5 ndk.rel.id=1 -ndk.date=May 2009 +ndk.date=June 2009 ndk.win_download=android-ndk-1.5_r1-windows.zip -ndk.win_bytes=22450814 -ndk.win_checksum=7b7836f705ec7e66225794edda34000f +ndk.win_bytes=22500667 +ndk.win_checksum=e5c53915903d8b81f3e2ea422e2e2717 ndk.mac_download=android-ndk-1.5_r1-darwin-x86.zip -ndk.mac_bytes=17165450 -ndk.mac_checksum=214ccfd704c0307609fbabeb7bf86acc +ndk.mac_bytes=17215303 +ndk.mac_checksum=1931f0e182798a4c98924fd87380b5b8 ndk.linux_download=android-ndk-1.5_r1-linux-x86.zip -ndk.linux_bytes=15976032 -ndk.linux_checksum=808fd4d6a7e45f76d546ba04ab9ef060 - -ndk.linux_64_download=android-ndk-1.5_r1-linux-x86_64.zip -ndk.linux_64_bytes=18112300 -ndk.linux_64_checksum=f8664c187b3ae077bcfe2b44294d0758 +ndk.linux_bytes=16025885 +ndk.linux_checksum=80a4e14704ca84c21bf1824cb25fbd8b page.title=Android 1.5 NDK, Release 1 @jd:body -

        What is the NDK?

        +

        What is the Android NDK?

        -

        The Android 1.5 NDK provides tools that allow Android application developers -to embed and deploy native code within their Android applications. It -provides:

        +

        The Android NDK provides tools that allow Android application developers +to embed components that make use of native code in their Android applications. +

        + +

        Android applications run in the Dalvik virtual machine. The NDK allows +developers to implement parts of their applications using native-code languages +such as C and C++. This can provide benefits to certain classes of applications, +in the form of reuse of existing code and in some cases increased speed.

        + +

        The NDK provides:

        • A set of tools and build files used to generate native code libraries from C @@ -35,18 +38,21 @@ and C++ sources
        • files (.apks) that can be deployed on Android devices
        • A set of native system headers and libraries that will be supported in all future versions of the Android platform, starting from Android 1.5
        • +
        • Documentation, samples, and tutorials
        -

        This release of the NDK release supports the ARMv5TE machine instruction set -and provides stable headers for libc (the C library), libm (the Math library) -and the JNI interface.

        +

        This release of the NDK supports the ARMv5TE machine instruction set +and provides stable headers for libc (the C library), libm (the Math library), +the JNI interface, and other libraries.

        -

        Using the NDK may not be relevant for all Android applications. As a -developer, you will need to balance its benefits (faster execution) and its -drawbacks (no portability, JNI overhead, no access to system libraries, and -difficult debugging). Typical good candidates for the NDK are CPU-intensive -operations that don't allocate too much memory, such as signal processing, -physics simulation, custom bytecode/instruction interpreters, and so on.

        +

        The NDK will not benefit most applications. As a developer, you will need +to balance its benefits against its drawbacks; notably, using native code does +not result in an automatic performance increase, but does always increase +application complexity. Typical good candidates for the NDK are self-contained, +CPU-intensive operations that don't allocate much memory, such as signal processing, +physics simulation, and so on. Simply re-coding a method to run in C usually does +not result in a large performance increase. The NDK can, however, can be +an effective way to reuse a large corpus of existing C/C++ code.

        Please note that the NDK does not enable you to develop native-only applications. Android's primary runtime remains the Dalvik virtual machine.

        @@ -64,8 +70,11 @@ guaranteed to be supported in all later releases of the platform:

        • libc (C library) headers
        • -
        • libm (Math library) headers
        • +
        • libm (math library) headers
        • JNI interface headers
        • +
        • libz (Zlib compression) headers
        • +
        • liblog (Android logging) header
        • +
        • A Minimal set of headers for C++ support

        The NDK also provides a build system that lets you work efficiently with your @@ -97,6 +106,22 @@ usage defines the native sources you want to compile

      19. APPLICATION-MK.TXT — describes the use of the Application.mk file, which describes the native sources required by your Android application
      20. +
      21. HOWTO.TXT — information about common tasks associated with NDK +development.
      22. +
      23. SYSTEM-ISSUES.TXT — known issues in the Android system images +that you should be aware of, if you are developing using the NDK.
      24. +
      25. STABLE-APIS.TXT — a complete list of the stable APIs exposed +by headers in the NDK.
      26. + + +

        Additionally, the package includes detailed information about the "bionic" +C library provided with the Android platform that you should be aware of, if you +are developing using the NDK. You can find the documentation in the +<ndk>/docs/system/libc/ directory:

        + +
          +
        • OVERVIEW.TXT — provides an overview of the "bionic" C library and the +features it offers.

        Sample applications

        @@ -142,13 +167,14 @@ required.
      27. For all development platforms, GNU Make 3.81 or later is required. Earlier versions of GNU Make might work but have not been tested.
      28. For Windows, a recent release of Cygwin is required.
      29. +href="http://www.cygwin.com">Cygwin, including both the gmake and gcc +packages, is required.

        Android platform compatibility

        • The native libraries created by the Android NDK can only be used on -devices running the Android 1.5 platform version or later. This is due to subtle +devices running the Android 1.5 platform version or later. This is due to toolchain and ABI related changes that make the native libraries incompatible with 1.0 and 1.1 system images.
        • For this reason, you should use native libraries produced with the NDK in diff --git a/docs/html/sdk/older_releases.jd b/docs/html/sdk/older_releases.jd index 3c2bbd403129d..febccd04d0465 100644 --- a/docs/html/sdk/older_releases.jd +++ b/docs/html/sdk/older_releases.jd @@ -25,6 +25,12 @@ release.

        Date Description
        Android 1.5 SDK, Release 2Android 1.5
        Android 1.1
        May 2009Replaced by Android 1.5 SDK, Release 3. Release notes
        Android 1.5 SDK, Release 1 Android 1.5
        Android 1.1
        - - - - - - - - - - - - - -
        -
        -
        - - - -
        -
        - - - -
        - - - - -
        - -
        - - - - - - diff --git a/docs/html/sdk/preview/features.jd b/docs/html/sdk/preview/features.jd new file mode 100644 index 0000000000000..43856deab0bae --- /dev/null +++ b/docs/html/sdk/preview/features.jd @@ -0,0 +1,6 @@ +sdk.redirect=true +sdk.redirect.path=android-1.5-highlights.html + +@jd:body + + diff --git a/docs/html/sdk/preview/index.jd b/docs/html/sdk/preview/index.jd index cb699e9121d1d..1e6b26b9077ab 100644 --- a/docs/html/sdk/preview/index.jd +++ b/docs/html/sdk/preview/index.jd @@ -1,5 +1,5 @@ sdk.redirect=true + @jd:body - diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs index 2079dd8a62f36..22d6f43ea969c 100644 --- a/docs/html/sdk/sdk_toc.cs +++ b/docs/html/sdk/sdk_toc.cs @@ -1,16 +1,42 @@ - +
      30. -

        System Image Version Notes

        +

        System Image Version Notes + Versionshinweise zum Systemabbild + Notas de la versión de System Image + Notes de version de l'image système + Note sulla versione dell'immagine
        di sistema
        + システム イメージ バージョンに
        関する注意事項
        + 系统图片版本说明 + 系統影像版本資訊 +

      31. -

        Previous SDK Releases

        +

        Native Development Tools

        + +
      32. +
      33. +

        + Previous SDK Releases + Frühere SDK-Releases + Versiones anteriores del SDK + Anciennes versions du SDK + Release SDK precedenti + SDK の過去のリリース + 以前的 SDK 版本 + 較舊的 SDK 發行版本 +

        • Android 1.1 SDK, r1
        • Android 1.0 SDK, r2
        • @@ -40,5 +89,7 @@ \ No newline at end of file + + \ No newline at end of file diff --git a/docs/html/sitemap-intl.txt b/docs/html/sitemap-intl.txt new file mode 100644 index 0000000000000..ded0554b3c410 --- /dev/null +++ b/docs/html/sitemap-intl.txt @@ -0,0 +1,12 @@ +http://developer.android.com/ja/sdk/1.5_r3/installing.html +http://developer.android.com/ja/community/index.html +http://developer.android.com/ja/index.html +http://developer.android.com/ja/guide/publishing/versioning.html +http://developer.android.com/ja/guide/publishing/app-signing.html +http://developer.android.com/ja/guide/publishing/preparing.html +http://developer.android.com/ja/guide/tutorials/hello-world.html +http://developer.android.com/ja/guide/topics/fundamentals.html +http://developer.android.com/ja/guide/index.html +http://developer.android.com/ja/guide/basics/what-is-android.html +http://developer.android.com/ja/guide/developing/other-ide.html +http://developer.android.com/ja/guide/developing/eclipse-adt.html diff --git a/docs/html/videos/index.jd b/docs/html/videos/index.jd new file mode 100644 index 0000000000000..c9c88cfa3d028 --- /dev/null +++ b/docs/html/videos/index.jd @@ -0,0 +1,338 @@ +videos=true +page.title=Videos +@jd:body + + + + + +
          + +
          +
          +
          +
          +
          + +
          +
          +
          +
          + +
          +

          Featured Videos

          +
            +
            + + + +
            +
            +
            +
            +
            +
            + +
            + + + + \ No newline at end of file diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index df659ef224dee..eef1096fb6c4b 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -30,11 +30,11 @@ public final class Bitmap implements Parcelable { /** * Indicates that the bitmap was created for an unknown pixel density. * - * @see Bitmap#getDensityScale() - * @see Bitmap#setDensityScale(float) + * @see Bitmap#getDensity() + * @see Bitmap#setDensity(int) */ - public static final float DENSITY_SCALE_UNKNOWN = -1.0f; - + public static final int DENSITY_NONE = 0; + // Note: mNativeBitmap is used by FaceDetector_jni.cpp // Don't change/rename without updating FaceDetector_jni.cpp private final int mNativeBitmap; @@ -45,11 +45,30 @@ public final class Bitmap implements Parcelable { private int mHeight = -1; private boolean mRecycled; + // Package-scoped for fast access. + /*package*/ int mDensity = sDefaultDensity = getDefaultDensity(); + private static volatile Matrix sScaleMatrix; - private float mDensityScale = DENSITY_SCALE_UNKNOWN; - private boolean mAutoScaling; - + private static volatile int sDefaultDensity = -1; + + /** + * For backwards compatibility, allows the app layer to change the default + * density when running old apps. + * @hide + */ + public static void setDefaultDensity(int density) { + sDefaultDensity = density; + } + + /*package*/ static int getDefaultDensity() { + if (sDefaultDensity >= 0) { + return sDefaultDensity; + } + sDefaultDensity = DisplayMetrics.DENSITY_DEVICE; + return sDefaultDensity; + } + /** * @noinspection UnusedDeclaration */ @@ -70,84 +89,46 @@ public final class Bitmap implements Parcelable { } /** - *

            Returns the density scale for this bitmap, expressed as a factor of - * the default density (160.) For instance, a bitmap designed for - * displays with a density of 240 will have a density scale of 1.5 whereas a bitmap - * designed for a density of 160 will have a density scale of 1.0.

            + *

            Returns the density for this bitmap.

            * - *

            The default density scale is {@link #DENSITY_SCALE_UNKNOWN}.

            + *

            The default density is the same density as the current display, + * unless the current application does not support different screen + * densities in which case it is + * {@link android.util.DisplayMetrics#DENSITY_DEFAULT}. Note that + * compatibility mode is determined by the application that was initially + * loaded into a process -- applications that share the same process should + * all have the same compatibility, or ensure they explicitly set the + * density of their bitmaps appropriately.

            * - * @return A scaling factor of the default density (160) or {@link #DENSITY_SCALE_UNKNOWN} + * @return A scaling factor of the default density or {@link #DENSITY_NONE} * if the scaling factor is unknown. * - * @see #setDensityScale(float) - * @see #isAutoScalingEnabled() - * @see #setAutoScalingEnabled(boolean) + * @see #setDensity(int) * @see android.util.DisplayMetrics#DENSITY_DEFAULT - * @see android.util.DisplayMetrics#density - * @see #DENSITY_SCALE_UNKNOWN + * @see android.util.DisplayMetrics#densityDpi + * @see #DENSITY_NONE */ - public float getDensityScale() { - return mDensityScale; + public int getDensity() { + return mDensity; } /** - *

            Specifies the density scale for this bitmap, expressed as a factor of - * the default density (160.) For instance, a bitmap designed for - * displays with a density of 240 will have a density scale of 1.5 whereas a bitmap - * designed for a density of 160 will have a density scale of 1.0.

            + *

            Specifies the density for this bitmap. When the bitmap is + * drawn to a Canvas that also has a density, it will be scaled + * appropriately.

            * - * @param densityScale The density scaling factor to use with this bitmap or - * {@link #DENSITY_SCALE_UNKNOWN} if the factor is unknown. + * @param density The density scaling factor to use with this bitmap or + * {@link #DENSITY_NONE} if the density is unknown. * - * @see #getDensityScale() - * @see #isAutoScalingEnabled() - * @see #setAutoScalingEnabled(boolean) + * @see #getDensity() * @see android.util.DisplayMetrics#DENSITY_DEFAULT - * @see android.util.DisplayMetrics#density - * @see #DENSITY_SCALE_UNKNOWN + * @see android.util.DisplayMetrics#densityDpi + * @see #DENSITY_NONE */ - public void setDensityScale(float densityScale) { - mDensityScale = densityScale; + public void setDensity(int density) { + mDensity = density; } - - /** - *

            Indicates whether this bitmap will be automatically be scaled at the - * target's density at drawing time. If auto scaling is enabled, this bitmap - * will be drawn with the following scale factor:

            - * - *
            scale = (bitmap density scale factor) / (target density scale factor)
            - * - *

            Auto scaling is turned off by default. If auto scaling is enabled but the - * bitmap has an unknown density scale, then the bitmap will never be automatically - * scaled at drawing time.

            - * - * @return True if the bitmap must be scaled at drawing time, false otherwise. - * - * @see #setAutoScalingEnabled(boolean) - * @see #getDensityScale() - * @see #setDensityScale(float) - */ - public boolean isAutoScalingEnabled() { - return mAutoScaling; - } - - /** - *

            Enables or disables auto scaling for this bitmap. When auto scaling is enabled, - * the bitmap will be scaled at drawing time to accomodate the drawing target's pixel - * density. The final scale factor for this bitmap is thus defined:

            - * - *
            scale = (bitmap density scale factor) / (target density scale factor)
            - * - *

            If auto scaling is enabled but the bitmap has an unknown density scale, then - * the bitmap will never be automatically scaled at drawing time.

            - * - * @param autoScalingEnabled True to scale the bitmap at drawing time, false otherwise. - */ - public void setAutoScalingEnabled(boolean autoScalingEnabled) { - mAutoScaling = autoScalingEnabled; - } - + /** * Sets the nine patch chunk. * @@ -317,7 +298,8 @@ public final class Bitmap implements Parcelable { * Tries to make a new bitmap based on the dimensions of this bitmap, * setting the new bitmap's config to the one specified, and then copying * this bitmap's pixels into the new bitmap. If the conversion is not - * supported, or the allocator fails, then this returns NULL. + * supported, or the allocator fails, then this returns NULL. The returned + * bitmap initially has the same density as the original. * * @param config The desired config for the resulting bitmap * @param isMutable True if the resulting bitmap should be mutable (i.e. @@ -326,7 +308,11 @@ public final class Bitmap implements Parcelable { */ public Bitmap copy(Config config, boolean isMutable) { checkRecycled("Can't copy a recycled bitmap"); - return nativeCopy(mNativeBitmap, config.nativeInt, isMutable); + Bitmap b = nativeCopy(mNativeBitmap, config.nativeInt, isMutable); + if (b != null) { + b.mDensity = mDensity; + } + return b; } public static Bitmap createScaledBitmap(Bitmap src, int dstWidth, @@ -361,7 +347,8 @@ public final class Bitmap implements Parcelable { /** * Returns an immutable bitmap from the source bitmap. The new bitmap may - * be the same object as source, or a copy may have been made. + * be the same object as source, or a copy may have been made. It is + * initialized with the same density as the original bitmap. */ public static Bitmap createBitmap(Bitmap src) { return createBitmap(src, 0, 0, src.getWidth(), src.getHeight()); @@ -370,7 +357,8 @@ public final class Bitmap implements Parcelable { /** * Returns an immutable bitmap from the specified subset of the source * bitmap. The new bitmap may be the same object as source, or a copy may - * have been made. + * have been made. It is + * initialized with the same density as the original bitmap. * * @param source The bitmap we are subsetting * @param x The x coordinate of the first pixel in source @@ -384,7 +372,8 @@ public final class Bitmap implements Parcelable { /** * Returns an immutable bitmap from subset of the source bitmap, - * transformed by the optional matrix. + * transformed by the optional matrix. It is + * initialized with the same density as the original bitmap. * * @param source The bitmap we are subsetting * @param x The x coordinate of the first pixel in source @@ -451,19 +440,20 @@ public final class Bitmap implements Parcelable { paint.setAntiAlias(true); } } + + // The new bitmap was created from a known bitmap source so assume that + // they use the same density + bitmap.mDensity = source.mDensity; + canvas.setBitmap(bitmap); canvas.drawBitmap(source, srcR, dstR, paint); - // The new bitmap was created from a known bitmap source so assume that - // they use the same density scale - bitmap.mDensityScale = source.mDensityScale; - bitmap.mAutoScaling = source.mAutoScaling; - return bitmap; } /** - * Returns a mutable bitmap with the specified width and height. + * Returns a mutable bitmap with the specified width and height. Its + * initial density is as per {@link #getDensity}. * * @param width The width of the bitmap * @param height The height of the bitmap @@ -478,7 +468,8 @@ public final class Bitmap implements Parcelable { /** * Returns a immutable bitmap with the specified width and height, with each - * pixel value set to the corresponding value in the colors array. + * pixel value set to the corresponding value in the colors array. Its + * initial density is as per {@link #getDensity}. * * @param colors Array of {@link Color} used to initialize the pixels. * @param offset Number of values to skip before the first color in the @@ -512,7 +503,8 @@ public final class Bitmap implements Parcelable { /** * Returns a immutable bitmap with the specified width and height, with each - * pixel value set to the corresponding value in the colors array. + * pixel value set to the corresponding value in the colors array. Its + * initial density is as per {@link #getDensity}. * * @param colors Array of {@link Color} used to initialize the pixels. * This array must be at least as large as width * height. @@ -603,65 +595,71 @@ public final class Bitmap implements Parcelable { } /** - * Convenience method that returns the width of this bitmap divided - * by the density scale factor. - * - * @param canvas The Canvas the bitmap will be drawn to. - * @return The scaled width of this bitmap, according to the density scale factor. + * Convenience for calling {@link #getScaledWidth(int)} with the target + * density of the given {@link Canvas}. */ public int getScaledWidth(Canvas canvas) { - final float scale = mDensityScale; - if (!mAutoScaling || scale < 0) { - return getWidth(); - } - return (int)(getWidth() * canvas.getDensityScale() / scale); + return scaleFromDensity(getWidth(), mDensity, canvas.mDensity); } /** - * Convenience method that returns the height of this bitmap divided - * by the density scale factor. - * - * @param canvas The Canvas the bitmap will be drawn to. - * @return The scaled height of this bitmap, according to the density scale factor. + * Convenience for calling {@link #getScaledHeight(int)} with the target + * density of the given {@link Canvas}. */ public int getScaledHeight(Canvas canvas) { - final float scale = mDensityScale; - if (!mAutoScaling || scale < 0) { - return getHeight(); - } - return (int)(getHeight() * canvas.getDensityScale() / scale); + return scaleFromDensity(getHeight(), mDensity, canvas.mDensity); + } + + /** + * Convenience for calling {@link #getScaledWidth(int)} with the target + * density of the given {@link DisplayMetrics}. + */ + public int getScaledWidth(DisplayMetrics metrics) { + return scaleFromDensity(getWidth(), mDensity, metrics.densityDpi); + } + + /** + * Convenience for calling {@link #getScaledHeight(int)} with the target + * density of the given {@link DisplayMetrics}. + */ + public int getScaledHeight(DisplayMetrics metrics) { + return scaleFromDensity(getHeight(), mDensity, metrics.densityDpi); } /** * Convenience method that returns the width of this bitmap divided * by the density scale factor. * - * @param metrics The target display metrics. + * @param targetDensity The density of the target canvas of the bitmap. * @return The scaled width of this bitmap, according to the density scale factor. */ - public int getScaledWidth(DisplayMetrics metrics) { - final float scale = mDensityScale; - if (!mAutoScaling || scale < 0) { - return getWidth(); - } - return (int)(getWidth() * metrics.density / scale); + public int getScaledWidth(int targetDensity) { + return scaleFromDensity(getWidth(), mDensity, targetDensity); } /** * Convenience method that returns the height of this bitmap divided * by the density scale factor. * - * @param metrics The target display metrics. + * @param targetDensity The density of the target canvas of the bitmap. * @return The scaled height of this bitmap, according to the density scale factor. */ - public int getScaledHeight(DisplayMetrics metrics) { - final float scale = mDensityScale; - if (!mAutoScaling || scale < 0) { - return getHeight(); - } - return (int)(getHeight() * metrics.density / scale); + public int getScaledHeight(int targetDensity) { + return scaleFromDensity(getHeight(), mDensity, targetDensity); } - + + /** + * @hide + */ + static public int scaleFromDensity(int size, int sdensity, int tdensity) { + if (sdensity == DENSITY_NONE || sdensity == tdensity) { + return size; + } + + // Scale by tdensity / sdensity, rounding up. + return ( (size * tdensity) + (sdensity >> 1) ) / sdensity; + } + /** * Return the number of bytes between rows in the bitmap's pixels. Note that * this refers to the pixels as stored natively by the bitmap. If you call @@ -922,6 +920,9 @@ public final class Bitmap implements Parcelable { * -2, -2, so that drawing the alpha bitmap offset by (-2, -2) and then * drawing the original would result in the blur visually aligning with * the original. + * + *

            The initial density of the returned bitmap is the same as the original's. + * * @param paint Optional paint used to modify the alpha values in the * resulting bitmap. Pass null for default behavior. * @param offsetXY Optional array that returns the X (index 0) and Y @@ -939,6 +940,7 @@ public final class Bitmap implements Parcelable { if (bm == null) { throw new RuntimeException("Failed to extractAlpha on Bitmap"); } + bm.mDensity = mDensity; return bm; } diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java index 76abaa23b9a09..c8bed24967669 100644 --- a/graphics/java/android/graphics/BitmapFactory.java +++ b/graphics/java/android/graphics/BitmapFactory.java @@ -39,7 +39,6 @@ public class BitmapFactory { */ public Options() { inDither = true; - inDensity = 0; inScaled = true; } @@ -79,22 +78,87 @@ public class BitmapFactory { public boolean inDither; /** - * The desired pixel density of the bitmap. + * The pixel density to use for the bitmap. This will always result + * in the returned bitmap having a density set for it (see + * {@link Bitmap#setDensity(int) Bitmap.setDensity(int)). In addition, + * if {@link #inScaled} is set (which it is by default} and this + * density does not match {@link #inTargetDensity}, then the bitmap + * will be scaled to the target density before being returned. + * + *

            If this is 0, + * {@link BitmapFactory#decodeResource(Resources, int)}, + * {@link BitmapFactory#decodeResource(Resources, int, android.graphics.BitmapFactory.Options)}, + * and {@link BitmapFactory#decodeResourceStream} + * will fill in the density associated with the resource. The other + * functions will leave it as-is and no density will be applied. * - * @see android.util.DisplayMetrics#DENSITY_DEFAULT - * @see android.util.DisplayMetrics#density + * @see #inTargetDensity + * @see #inScreenDensity + * @see #inScaled + * @see Bitmap#setDensity(int) + * @see android.util.DisplayMetrics#densityDpi */ public int inDensity; /** - *

            If the bitmap is loaded from {@link android.content.res.Resources} and - * this flag is turned on, the bitmap will be scaled to match the default - * display's pixel density.

            + * The pixel density of the destination this bitmap will be drawn to. + * This is used in conjunction with {@link #inDensity} and + * {@link #inScaled} to determine if and how to scale the bitmap before + * returning it. + * + *

            If this is 0, + * {@link BitmapFactory#decodeResource(Resources, int)}, + * {@link BitmapFactory#decodeResource(Resources, int, android.graphics.BitmapFactory.Options)}, + * and {@link BitmapFactory#decodeResourceStream} + * will fill in the density associated the Resources object's + * DisplayMetrics. The other + * functions will leave it as-is and no scaling for density will be + * performed. + * + * @see #inDensity + * @see #inScreenDensity + * @see #inScaled + * @see android.util.DisplayMetrics#densityDpi + */ + public int inTargetDensity; + + /** + * The pixel density of the actual screen that is being used. This is + * purely for applications running in density compatibility code, where + * {@link #inTargetDensity} is actually the density the application + * sees rather than the real screen density. + * + *

            By setting this, you + * allow the loading code to avoid scaling a bitmap that is currently + * in the screen density up/down to the compatibility density. Instead, + * if {@link #inDensity} is the same as {@link #inScreenDensity}, the + * bitmap will be left as-is. Anything using the resulting bitmap + * must also used {@link Bitmap#getScaledWidth(int) + * Bitmap.getScaledWidth} and {@link Bitmap#getScaledHeight + * Bitmap.getScaledHeight} to account for any different between the + * bitmap's density and the target's density. + * + *

            This is never set automatically for the caller by + * {@link BitmapFactory} itself. It must be explicitly set, since the + * caller must deal with the resulting bitmap in a density-aware way. + * + * @see #inDensity + * @see #inTargetDensity + * @see #inScaled + * @see android.util.DisplayMetrics#densityDpi + */ + public int inScreenDensity; + + /** + * When this flag is set, if {@link #inDensity} and + * {@link #inTargetDensity} are not 0, the + * bitmap will be scaled to match {@link #inTargetDensity} when loaded, + * rather than relying on the graphics system scaling it each time it + * is drawn to a Canvas. * - *

            This flag is turned on by default and should be turned off if you need - * a non-scaled version of the bitmap. In this case, - * {@link android.graphics.Bitmap#setAutoScalingEnabled(boolean)} can be used - * to properly scale the bitmap at drawing time.

            + *

            This flag is turned on by default and should be turned off if you need + * a non-scaled version of the bitmap. Nine-patch bitmaps ignore this + * flag and are always scaled. */ public boolean inScaled; @@ -235,58 +299,32 @@ public class BitmapFactory { * Decode a new Bitmap from an InputStream. This InputStream was obtained from * resources, which we pass to be able to scale the bitmap accordingly. */ - public static Bitmap decodeStream(Resources res, TypedValue value, InputStream is, - Rect pad, Options opts) { + public static Bitmap decodeResourceStream(Resources res, TypedValue value, + InputStream is, Rect pad, Options opts) { if (opts == null) { opts = new Options(); } - Bitmap bm = decodeStream(is, pad, opts); - - if (bm != null && res != null && value != null) { + if (opts.inDensity == 0 && value != null) { final int density = value.density; - if (density == TypedValue.DENSITY_NONE) { - return bm; - } - - byte[] np = bm.getNinePatchChunk(); - final boolean isNinePatch = np != null && NinePatch.isNinePatchChunk(np); - - if (opts.inDensity == 0) { - opts.inDensity = density == TypedValue.DENSITY_DEFAULT ? - DisplayMetrics.DENSITY_DEFAULT : density; - } - float scale = opts.inDensity / (float) DisplayMetrics.DENSITY_DEFAULT; - - if (opts.inScaled || isNinePatch) { - bm.setDensityScale(1.0f); - bm.setAutoScalingEnabled(false); - // Assume we are going to prescale for the screen - scale = res.getDisplayMetrics().density / scale; - if (scale != 1.0f) { - // TODO: This is very inefficient and should be done in native by Skia - final Bitmap oldBitmap = bm; - bm = Bitmap.createScaledBitmap(oldBitmap, (int) (bm.getWidth() * scale + 0.5f), - (int) (bm.getHeight() * scale + 0.5f), true); - oldBitmap.recycle(); - - if (isNinePatch) { - np = nativeScaleNinePatch(np, scale, pad); - bm.setNinePatchChunk(np); - } - } - } else { - bm.setDensityScale(scale); - bm.setAutoScalingEnabled(true); + if (density == TypedValue.DENSITY_DEFAULT) { + opts.inDensity = DisplayMetrics.DENSITY_DEFAULT; + } else if (density != TypedValue.DENSITY_NONE) { + opts.inDensity = density; } } - - return bm; + + if (opts.inTargetDensity == 0 && res != null) { + opts.inTargetDensity = res.getDisplayMetrics().densityDpi; + } + + return decodeStream(is, pad, opts); } /** - * Decode an image referenced by a resource ID. + * Synonym for opening the given resource and calling + * {@link #decodeResourceStream}. * * @param res The resources object containing the image data * @param id The resource id of the image data @@ -303,7 +341,7 @@ public class BitmapFactory { final TypedValue value = new TypedValue(); final InputStream is = res.openRawResource(id, value); - bm = decodeStream(res, value, is, null, opts); + bm = decodeResourceStream(res, value, is, null, opts); is.close(); } catch (java.io.IOException e) { /* do nothing. @@ -315,7 +353,8 @@ public class BitmapFactory { } /** - * Decode an image referenced by a resource ID. + * Synonym for {@link #decodeResource(Resources, int, android.graphics.BitmapFactory.Options)} + * will null Options. * * @param res The resources object containing the image data * @param id The resource id of the image data @@ -412,6 +451,39 @@ public class BitmapFactory { bm = nativeDecodeStream(is, tempStorage, outPadding, opts); } + if (bm == null || opts == null) { + return bm; + } + + final int density = opts.inDensity; + if (density == 0) { + return bm; + } + + bm.setDensity(density); + final int targetDensity = opts.inTargetDensity; + if (targetDensity == 0 || density == targetDensity + || density == opts.inScreenDensity) { + return bm; + } + + byte[] np = bm.getNinePatchChunk(); + final boolean isNinePatch = np != null && NinePatch.isNinePatchChunk(np); + if (opts.inScaled || isNinePatch) { + float scale = targetDensity / (float)density; + // TODO: This is very inefficient and should be done in native by Skia + final Bitmap oldBitmap = bm; + bm = Bitmap.createScaledBitmap(oldBitmap, (int) (bm.getWidth() * scale + 0.5f), + (int) (bm.getHeight() * scale + 0.5f), true); + oldBitmap.recycle(); + + if (isNinePatch) { + np = nativeScaleNinePatch(np, scale, outPadding); + bm.setNinePatchChunk(np); + } + bm.setDensity(targetDensity); + } + return bm; } diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java index da7359772ee38..345f810ecf2a9 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -20,6 +20,7 @@ import android.text.TextUtils; import android.text.SpannedString; import android.text.SpannableString; import android.text.GraphicsOperations; +import android.util.DisplayMetrics; import javax.microedition.khronos.opengles.GL; @@ -47,15 +48,21 @@ public class Canvas { // optional field set by the caller private DrawFilter mDrawFilter; + // Package-scoped for quick access. + /*package*/ int mDensity = Bitmap.DENSITY_NONE; + + // Used to determine when compatibility scaling is in effect. + private int mScreenDensity = Bitmap.DENSITY_NONE; + // Used by native code @SuppressWarnings({"UnusedDeclaration"}) private int mSurfaceFormat; - @SuppressWarnings({"UnusedDeclaration"}) - private float mDensityScale = 1.0f; /** * Construct an empty raster canvas. Use setBitmap() to specify a bitmap to - * draw into. + * draw into. The initial target density is {@link Bitmap#DENSITY_NONE}; + * this will typically be replaced when a target bitmap is set for the + * canvas. */ public Canvas() { // 0 means no native bitmap @@ -65,6 +72,9 @@ public class Canvas { /** * Construct a canvas with the specified bitmap to draw into. The bitmap * must be mutable. + * + *

            The initial target density of the canvas is the same as the given + * bitmap's density. * * @param bitmap Specifies a mutable bitmap for the canvas to draw into. */ @@ -76,8 +86,7 @@ public class Canvas { throwIfRecycled(bitmap); mNativeCanvas = initRaster(bitmap.ni()); mBitmap = bitmap; - mDensityScale = bitmap.getDensityScale(); - if (mDensityScale == Bitmap.DENSITY_SCALE_UNKNOWN) mDensityScale = 1.0f; + mDensity = bitmap.mDensity; } /*package*/ Canvas(int nativeCanvas) { @@ -85,6 +94,7 @@ public class Canvas { throw new IllegalStateException(); } mNativeCanvas = nativeCanvas; + mDensity = Bitmap.getDefaultDensity(); } /** @@ -93,10 +103,14 @@ public class Canvas { * be supported in this mode (e.g. some GL implementations may not support * antialiasing or certain effects like ColorMatrix or certain Xfermodes). * However, no exception will be thrown in those cases. + * + *

            The initial target density of the canvas is the same as the initial + * density of bitmaps as per {@link Bitmap#getDensity() Bitmap.getDensity()}. */ public Canvas(GL gl) { mNativeCanvas = initGL(); mGL = gl; + mDensity = Bitmap.getDefaultDensity(); } /** @@ -117,9 +131,13 @@ public class Canvas { } /** - * Specify a bitmap for the canvas to draw into. + * Specify a bitmap for the canvas to draw into. As a side-effect, also + * updates the canvas's target density to match that of the bitmap. * * @param bitmap Specifies a mutable bitmap for the canvas to draw into. + * + * @see #setDensity(int) + * @see #getDensity() */ public void setBitmap(Bitmap bitmap) { if (!bitmap.isMutable()) { @@ -132,8 +150,7 @@ public class Canvas { native_setBitmap(mNativeCanvas, bitmap.ni()); mBitmap = bitmap; - mDensityScale = bitmap.getDensityScale(); - if (mDensityScale == Bitmap.DENSITY_SCALE_UNKNOWN) mDensityScale = 1.0f; + mDensity = bitmap.mDensity; } /** @@ -172,46 +189,44 @@ public class Canvas { public native int getHeight(); /** - *

            Returns the density scale for this Canvas' backing bitmap, expressed as a - * factor of the default density (160dpi.) For instance, a bitmap designed for - * 240dpi displays will have a density scale of 1.5 whereas a bitmap - * designed for 160dpi will have a density scale of 1.0.

            + *

            Returns the target density of the canvas. The default density is + * derived from the density of its backing bitmap, or + * {@link Bitmap#DENSITY_NONE} if there is not one.

            * - *

            The default density scale is {@link Bitmap#DENSITY_SCALE_UNKNOWN}.

            + * @return Returns the current target density of the canvas, which is used + * to determine the scaling factor when drawing a bitmap into it. * - * @return A scaling factor of the default density (160dpi) or - * {@link Bitmap#DENSITY_SCALE_UNKNOWN} if the scaling factor is unknown. - * - * @see #setDensityScale(float) - * @see Bitmap#getDensityScale() + * @see #setDensity(int) + * @see Bitmap#getDensity() */ - public float getDensityScale() { - if (mBitmap != null) { - return mBitmap.getDensityScale(); - } - return mDensityScale; + public int getDensity() { + return mDensity; } /** - *

            Specifies the density scale for this Canvas' backing bitmap, expressed as a - * factor of the default density (160dpi.) For instance, a bitmap designed for - * 240dpi displays will have a density scale of 1.5 whereas a bitmap - * designed for 160dpi will have a density scale of 1.0.

            + *

            Specifies the density for this Canvas' backing bitmap. This modifies + * the target density of the canvas itself, as well as the density of its + * backing bitmap via {@link Bitmap#setDensity(int) Bitmap.setDensity(int)}. * - * @param densityScale The density scaling factor to use with this bitmap or - * {@link Bitmap#DENSITY_SCALE_UNKNOWN} if the factor is unknown. + * @param density The new target density of the canvas, which is used + * to determine the scaling factor when drawing a bitmap into it. Use + * {@link Bitmap#DENSITY_NONE} to disable bitmap scaling. * - * @see #getDensityScale() - * @see Bitmap#setDensityScale(float) + * @see #getDensity() + * @see Bitmap#setDensity(int) */ - public void setDensityScale(float densityScale) { + public void setDensity(int density) { if (mBitmap != null) { - mBitmap.setDensityScale(densityScale); + mBitmap.setDensity(density); } - mDensityScale = densityScale; - if (mDensityScale == Bitmap.DENSITY_SCALE_UNKNOWN) mDensityScale = 1.0f; + mDensity = density; } + /** @hide */ + public void setScreenDensity(int density) { + mScreenDensity = density; + } + // the SAVE_FLAG constants must match their native equivalents /** restore the current matrix when restore() is called */ @@ -945,12 +960,17 @@ public class Canvas { /** * Draw the specified bitmap, with its top/left corner at (x,y), using * the specified paint, transformed by the current matrix. - * Note: if the paint contains a maskfilter that generates a mask which + * + *

            Note: if the paint contains a maskfilter that generates a mask which * extends beyond the bitmap's original width/height (e.g. BlurMaskFilter), * then the bitmap will be drawn as if it were in a Shader with CLAMP mode. * Thus the color outside of the original width/height will be the edge * color replicated. * + *

            If the bitmap and canvas have different densities, this function + * will take care of automatically scaling the bitmap to draw at the + * same density as the canvas. + * * @param bitmap The bitmap to be drawn * @param left The position of the left side of the bitmap being drawn * @param top The position of the top side of the bitmap being drawn @@ -959,20 +979,26 @@ public class Canvas { public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) { throwIfRecycled(bitmap); native_drawBitmap(mNativeCanvas, bitmap.ni(), left, top, - paint != null ? paint.mNativePaint : 0, bitmap.isAutoScalingEnabled(), - bitmap.getDensityScale()); + paint != null ? paint.mNativePaint : 0, mDensity, mScreenDensity, + bitmap.mDensity); } /** * Draw the specified bitmap, scaling/translating automatically to fill * the destination rectangle. If the source rectangle is not null, it * specifies the subset of the bitmap to draw. - * Note: if the paint contains a maskfilter that generates a mask which + * + *

            Note: if the paint contains a maskfilter that generates a mask which * extends beyond the bitmap's original width/height (e.g. BlurMaskFilter), * then the bitmap will be drawn as if it were in a Shader with CLAMP mode. * Thus the color outside of the original width/height will be the edge * color replicated. * + *

            This function ignores the density associated with the bitmap. + * This is because the source and destination rectangle coordinate + * spaces are in their respective densities, so must already have the + * appropriate scaling factor applied. + * * @param bitmap The bitmap to be drawn * @param src May be null. The subset of the bitmap to be drawn * @param dst The rectangle that the bitmap will be scaled/translated @@ -985,19 +1011,26 @@ public class Canvas { } throwIfRecycled(bitmap); native_drawBitmap(mNativeCanvas, bitmap.ni(), src, dst, - paint != null ? paint.mNativePaint : 0); + paint != null ? paint.mNativePaint : 0, + mScreenDensity, bitmap.mDensity); } /** * Draw the specified bitmap, scaling/translating automatically to fill * the destination rectangle. If the source rectangle is not null, it * specifies the subset of the bitmap to draw. - * Note: if the paint contains a maskfilter that generates a mask which + * + *

            Note: if the paint contains a maskfilter that generates a mask which * extends beyond the bitmap's original width/height (e.g. BlurMaskFilter), * then the bitmap will be drawn as if it were in a Shader with CLAMP mode. * Thus the color outside of the original width/height will be the edge * color replicated. * + *

            This function ignores the density associated with the bitmap. + * This is because the source and destination rectangle coordinate + * spaces are in their respective densities, so must already have the + * appropriate scaling factor applied. + * * @param bitmap The bitmap to be drawn * @param src May be null. The subset of the bitmap to be drawn * @param dst The rectangle that the bitmap will be scaled/translated @@ -1010,7 +1043,8 @@ public class Canvas { } throwIfRecycled(bitmap); native_drawBitmap(mNativeCanvas, bitmap.ni(), src, dst, - paint != null ? paint.mNativePaint : 0); + paint != null ? paint.mNativePaint : 0, + mScreenDensity, bitmap.mDensity); } /** @@ -1489,14 +1523,20 @@ public class Canvas { int paint); private native void native_drawBitmap(int nativeCanvas, int bitmap, float left, float top, - int nativePaintOrZero, boolean autoScale, - float densityScale); + int nativePaintOrZero, + int canvasDensity, + int screenDensity, + int bitmapDensity); private native void native_drawBitmap(int nativeCanvas, int bitmap, Rect src, RectF dst, - int nativePaintOrZero); + int nativePaintOrZero, + int screenDensity, + int bitmapDensity); private static native void native_drawBitmap(int nativeCanvas, int bitmap, Rect src, Rect dst, - int nativePaintOrZero); + int nativePaintOrZero, + int screenDensity, + int bitmapDensity); private static native void native_drawBitmap(int nativeCanvas, int[] colors, int offset, int stride, float x, float y, int width, int height, diff --git a/graphics/java/android/graphics/NinePatch.java b/graphics/java/android/graphics/NinePatch.java index 778c90304dcb5..88dfd6790f3a2 100644 --- a/graphics/java/android/graphics/NinePatch.java +++ b/graphics/java/android/graphics/NinePatch.java @@ -68,7 +68,7 @@ public class NinePatch { } /** - * Draw a bitmap to nine patches. + * Draw a bitmap of nine patches. * * @param canvas A container for the current matrix and clip used to draw the bitmap. * @param location Where to draw the bitmap. @@ -76,23 +76,25 @@ public class NinePatch { public void draw(Canvas canvas, RectF location) { nativeDraw(canvas.mNativeCanvas, location, mBitmap.ni(), mChunk, - mPaint != null ? mPaint.mNativePaint : 0); + mPaint != null ? mPaint.mNativePaint : 0, + canvas.mDensity, mBitmap.mDensity); } /** - * Draw a bitmap to nine patches. + * Draw a bitmap of nine patches. * * @param canvas A container for the current matrix and clip used to draw the bitmap. * @param location Where to draw the bitmap. */ public void draw(Canvas canvas, Rect location) { nativeDraw(canvas.mNativeCanvas, location, - mBitmap.ni(), mChunk, - mPaint != null ? mPaint.mNativePaint : 0); + mBitmap.ni(), mChunk, + mPaint != null ? mPaint.mNativePaint : 0, + canvas.mDensity, mBitmap.mDensity); } /** - * Draw a bitmap to nine patches. + * Draw a bitmap of nine patches. * * @param canvas A container for the current matrix and clip used to draw the bitmap. * @param location Where to draw the bitmap. @@ -100,9 +102,18 @@ public class NinePatch { */ public void draw(Canvas canvas, Rect location, Paint paint) { nativeDraw(canvas.mNativeCanvas, location, - mBitmap.ni(), mChunk, paint != null ? paint.mNativePaint : 0); + mBitmap.ni(), mChunk, paint != null ? paint.mNativePaint : 0, + canvas.mDensity, mBitmap.mDensity); } + /** + * Return the underlying bitmap's density, as per + * {@link Bitmap#getDensity() Bitmap.getDensity()}. + */ + public int getDensity() { + return mBitmap.mDensity; + } + public int getWidth() { return mBitmap.getWidth(); } @@ -129,9 +140,11 @@ public class NinePatch { private static native void validateNinePatchChunk(int bitmap, byte[] chunk); private static native void nativeDraw(int canvas_instance, RectF loc, int bitmap_instance, - byte[] c, int paint_instance_or_null); + byte[] c, int paint_instance_or_null, + int destDensity, int srcDensity); private static native void nativeDraw(int canvas_instance, Rect loc, int bitmap_instance, - byte[] c, int paint_instance_or_null); + byte[] c, int paint_instance_or_null, + int destDensity, int srcDensity); private static native int nativeGetTransparentRegion( int bitmap, byte[] chunk, Rect location); } diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java index 5b32246c9bb93..eade73ae92766 100644 --- a/graphics/java/android/graphics/drawable/BitmapDrawable.java +++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java @@ -63,18 +63,56 @@ public class BitmapDrawable extends Drawable { private boolean mApplyGravity; private boolean mRebuildShader; + private boolean mMutated; + + private int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT; + + // These are scaled to match the target density. private int mBitmapWidth; private int mBitmapHeight; - private boolean mMutated; - + + /** + * Create an empty drawable, not dealing with density. + * @deprecated Use {@link #BitmapDrawable(Resources)} to ensure + * that the drawable has correctly set its target density. + */ public BitmapDrawable() { mBitmapState = new BitmapState((Bitmap) null); } + /** + * Create an empty drawable, setting initial target density based on + * the display metrics of the resources. + */ + public BitmapDrawable(Resources res) { + mBitmapState = new BitmapState((Bitmap) null); + if (res != null) { + setTargetDensity(res.getDisplayMetrics()); + mBitmapState.mTargetDensity = mTargetDensity; + } + } + + /** + * Create drawable from a bitmap, not dealing with density. + * @deprecated Use {@link #BitmapDrawable(Resources, Bitmap)} to ensure + * that the drawable has correctly set its target density. + */ public BitmapDrawable(Bitmap bitmap) { this(new BitmapState(bitmap)); } + /** + * Create drawable from a bitmap, setting initial target density based on + * the display metrics of the resources. + */ + public BitmapDrawable(Resources res, Bitmap bitmap) { + this(new BitmapState(bitmap)); + if (res != null) { + setTargetDensity(res.getDisplayMetrics()); + mBitmapState.mTargetDensity = mTargetDensity; + } + } + public BitmapDrawable(String filepath) { this(new BitmapState(BitmapFactory.decodeFile(filepath))); if (mBitmap == null) { @@ -97,11 +135,15 @@ public class BitmapDrawable extends Drawable { return mBitmap; } + private void computeBitmapSize() { + mBitmapWidth = mBitmap.getScaledWidth(mTargetDensity); + mBitmapHeight = mBitmap.getScaledHeight(mTargetDensity); + } + private void setBitmap(Bitmap bitmap) { mBitmap = bitmap; if (bitmap != null) { - mBitmapWidth = bitmap.getWidth(); - mBitmapHeight = bitmap.getHeight(); + computeBitmapSize(); } else { mBitmapWidth = mBitmapHeight = -1; } @@ -114,13 +156,11 @@ public class BitmapDrawable extends Drawable { * * @param canvas The Canvas from which the density scale must be obtained. * - * @see android.graphics.Bitmap#setDensityScale(float) - * @see android.graphics.Bitmap#getDensityScale() - * - * @hide pending API council approval + * @see android.graphics.Bitmap#setDensity(int) + * @see android.graphics.Bitmap#getDensity() */ - public void setDensityScale(Canvas canvas) { - setDensityScale(canvas.getDensityScale()); + public void setTargetDensity(Canvas canvas) { + setTargetDensity(canvas.getDensity()); } /** @@ -128,32 +168,33 @@ public class BitmapDrawable extends Drawable { * * @param metrics The DisplayMetrics indicating the density scale for this drawable. * - * @see android.graphics.Bitmap#setDensityScale(float) - * @see android.graphics.Bitmap#getDensityScale() - * - * @hide pending API council approval + * @see android.graphics.Bitmap#setDensity(int) + * @see android.graphics.Bitmap#getDensity() */ - public void setDensityScale(DisplayMetrics metrics) { - setDensityScale(metrics.density); + public void setTargetDensity(DisplayMetrics metrics) { + mTargetDensity = metrics.densityDpi; + if (mBitmap != null) { + computeBitmapSize(); + } } /** - * Set the density scale at which this drawable will be rendered. + * Set the density at which this drawable will be rendered. * * @param density The density scale for this drawable. * - * @see android.graphics.Bitmap#setDensityScale(float) - * @see android.graphics.Bitmap#getDensityScale() - * - * @hide pending API council approval + * @see android.graphics.Bitmap#setDensity(int) + * @see android.graphics.Bitmap#getDensity() */ - public void setDensityScale(float density) { - density = (density == Bitmap.DENSITY_SCALE_UNKNOWN ? 1.0f : density); - mBitmapState.mTargetDensityScale = density; + public void setTargetDensity(int density) { + mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density; + if (mBitmap != null) { + computeBitmapSize(); + } } /** Get the gravity used to position/stretch the bitmap within its bounds. - See android.view.Gravity + * See android.view.Gravity * @return the gravity applied to the bitmap */ public int getGravity() { @@ -302,7 +343,7 @@ public class BitmapDrawable extends Drawable { } mBitmapState.mBitmap = bitmap; setBitmap(bitmap); - setDensityScale(r.getDisplayMetrics()); + setTargetDensity(r.getDisplayMetrics()); final Paint paint = mBitmapState.mPaint; paint.setAntiAlias(a.getBoolean(com.android.internal.R.styleable.BitmapDrawable_antialias, @@ -332,29 +373,12 @@ public class BitmapDrawable extends Drawable { @Override public int getIntrinsicWidth() { - final Bitmap bitmap = mBitmap; - final BitmapState state = mBitmapState; - - if (!state.mAutoScale || state.mBitmapScale == Bitmap.DENSITY_SCALE_UNKNOWN) { - return mBitmapWidth; - } else { - return bitmap != null ? (int) (mBitmapWidth / - (state.mBitmapScale / state.mTargetDensityScale) + 0.5f) : -1; - - } + return mBitmapWidth; } @Override public int getIntrinsicHeight() { - final Bitmap bitmap = mBitmap; - final BitmapState state = mBitmapState; - - if (!state.mAutoScale || state.mBitmapScale == Bitmap.DENSITY_SCALE_UNKNOWN) { - return mBitmapHeight; - } else { - return bitmap != null ? (int) (mBitmapHeight / - (state.mBitmapScale / state.mTargetDensityScale) + 0.5f) : -1; - } + return mBitmapHeight; } @Override @@ -380,19 +404,10 @@ public class BitmapDrawable extends Drawable { Paint mPaint = new Paint(DEFAULT_PAINT_FLAGS); Shader.TileMode mTileModeX; Shader.TileMode mTileModeY; - boolean mAutoScale; - float mBitmapScale; - float mTargetDensityScale = 1.0f; + int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT; BitmapState(Bitmap bitmap) { mBitmap = bitmap; - if (bitmap != null) { - mBitmapScale = bitmap.getDensityScale(); - mAutoScale = bitmap.isAutoScalingEnabled(); - } else { - mBitmapScale = 1.0f; - mAutoScale = false; - } } BitmapState(BitmapState bitmapState) { @@ -401,7 +416,7 @@ public class BitmapDrawable extends Drawable { mGravity = bitmapState.mGravity; mTileModeX = bitmapState.mTileModeX; mTileModeY = bitmapState.mTileModeY; - mTargetDensityScale = bitmapState.mTargetDensityScale; + mTargetDensity = bitmapState.mTargetDensity; mPaint = new Paint(bitmapState.mPaint); } @@ -418,6 +433,7 @@ public class BitmapDrawable extends Drawable { private BitmapDrawable(BitmapState state) { mBitmapState = state; + mTargetDensity = state.mTargetDensity; setBitmap(state.mBitmap); } } diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index 910e111e0947c..0a0e4eb51fb89 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -27,6 +27,7 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.*; import android.util.AttributeSet; +import android.util.DisplayMetrics; import android.util.StateSet; import android.util.Xml; import android.util.TypedValue; @@ -657,9 +658,8 @@ public abstract class Drawable { } /** - * Create a drawable from an inputstream - * - * @hide pending API council approval + * Create a drawable from an inputstream, using the given resources and + * value to determine density information. */ public static Drawable createFromResourceStream(Resources res, TypedValue value, InputStream is, String srcName) { @@ -675,7 +675,17 @@ public abstract class Drawable { Rects only to drop them on the floor. */ Rect pad = new Rect(); - Bitmap bm = BitmapFactory.decodeStream(res, value, is, pad, null); + + // Special stuff for compatibility mode: if the target density is not + // the same as the display density, but the resource -is- the same as + // the display density, then don't scale it down to the target density. + // This allows us to load the system's density-correct resources into + // an application in compatibility mode, without scaling those down + // to the compatibility density only to have them scaled back up when + // drawn to the screen. + BitmapFactory.Options opts = new BitmapFactory.Options(); + opts.inScreenDensity = DisplayMetrics.DENSITY_DEVICE; + Bitmap bm = BitmapFactory.decodeResourceStream(res, value, is, pad, opts); if (bm != null) { byte[] np = bm.getNinePatchChunk(); if (np == null || !NinePatch.isNinePatchChunk(np)) { @@ -754,10 +764,13 @@ public abstract class Drawable { } else if (name.equals("bitmap")) { drawable = new BitmapDrawable(); if (r != null) { - ((BitmapDrawable) drawable).setDensityScale(r.getDisplayMetrics()); + ((BitmapDrawable) drawable).setTargetDensity(r.getDisplayMetrics()); } } else if (name.equals("nine-patch")) { drawable = new NinePatchDrawable(); + if (r != null) { + ((NinePatchDrawable) drawable).setTargetDensity(r.getDisplayMetrics()); + } } else { throw new XmlPullParserException(parser.getPositionDescription() + ": invalid drawable tag " + name); @@ -812,15 +825,10 @@ public abstract class Drawable { Rect pad, String srcName) { if (np != null) { - return new NinePatchDrawable(bm, np, pad, srcName); + return new NinePatchDrawable(res, bm, np, pad, srcName); } - final BitmapDrawable drawable = new BitmapDrawable(bm); - if (res != null) { - drawable.setDensityScale(res.getDisplayMetrics()); - } - - return drawable; + return new BitmapDrawable(res, bm); } } diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java index 376b1df81b6af..dc80cf5ac97f6 100644 --- a/graphics/java/android/graphics/drawable/DrawableContainer.java +++ b/graphics/java/android/graphics/drawable/DrawableContainer.java @@ -272,6 +272,8 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { boolean mCheckedConstantState; boolean mCanConstantState; + boolean mPaddingChecked = false; + DrawableContainerState(DrawableContainerState orig, DrawableContainer owner) { mOwner = owner; @@ -334,6 +336,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { mHaveStateful = false; mConstantPadding = null; + mPaddingChecked = false; mComputedConstantSize = false; return pos; @@ -359,23 +362,25 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { if (mVariablePadding) { return null; } - if (mConstantPadding != null) { + if (mConstantPadding != null || mPaddingChecked) { return mConstantPadding; } - final Rect r = new Rect(0, 0, 0, 0); + Rect r = null; final Rect t = new Rect(); final int N = getChildCount(); final Drawable[] drawables = mDrawables; for (int i = 0; i < N; i++) { if (drawables[i].getPadding(t)) { + if (r == null) r = new Rect(0, 0, 0, 0); if (t.left > r.left) r.left = t.left; if (t.top > r.top) r.top = t.top; if (t.right > r.right) r.right = t.right; if (t.bottom > r.bottom) r.bottom = t.bottom; } } - return (mConstantPadding=r); + mPaddingChecked = true; + return (mConstantPadding = r); } public final void setConstantSize(boolean constant) { diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java index dace96c9c8919..d5c8a089b5e0a 100644 --- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java +++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java @@ -20,6 +20,7 @@ import android.graphics.*; import android.content.res.Resources; import android.content.res.TypedArray; import android.util.AttributeSet; +import android.util.DisplayMetrics; import android.util.TypedValue; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -41,24 +42,122 @@ public class NinePatchDrawable extends Drawable { private Paint mPaint; private boolean mMutated; + private int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT; + + // These are scaled to match the target density. + private int mBitmapWidth; + private int mBitmapHeight; + NinePatchDrawable() { } + /** + * Create drawable from raw nine-patch data, not dealing with density. + * @deprecated Use {@link #NinePatchDrawable(Resources, Bitmap, byte[], Rect, String)} + * to ensure that the drawable has correctly set its target density. + */ public NinePatchDrawable(Bitmap bitmap, byte[] chunk, Rect padding, String srcName) { this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding)); } + /** + * Create drawable from raw nine-patch data, setting initial target density + * based on the display metrics of the resources. + */ + public NinePatchDrawable(Resources res, Bitmap bitmap, byte[] chunk, + Rect padding, String srcName) { + this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding)); + if (res != null) { + setTargetDensity(res.getDisplayMetrics()); + mNinePatchState.mTargetDensity = mTargetDensity; + } + } + + /** + * Create drawable from existing nine-patch, not dealing with density. + * @deprecated Use {@link #NinePatchDrawable(Resources, NinePatch)} + * to ensure that the drawable has correctly set its target density. + */ public NinePatchDrawable(NinePatch patch) { this(new NinePatchState(patch, null)); } + /** + * Create drawable from existing nine-patch, setting initial target density + * based on the display metrics of the resources. + */ + public NinePatchDrawable(Resources res, NinePatch patch) { + this(new NinePatchState(patch, null)); + if (res != null) { + setTargetDensity(res.getDisplayMetrics()); + mNinePatchState.mTargetDensity = mTargetDensity; + } + } + private void setNinePatchState(NinePatchState state) { mNinePatchState = state; mNinePatch = state.mNinePatch; mPadding = state.mPadding; + mTargetDensity = state.mTargetDensity; if (state.mDither) setDither(state.mDither); + if (mNinePatch != null) { + computeBitmapSize(); + } } + /** + * Set the density scale at which this drawable will be rendered. This + * method assumes the drawable will be rendered at the same density as the + * specified canvas. + * + * @param canvas The Canvas from which the density scale must be obtained. + * + * @see android.graphics.Bitmap#setDensity(int) + * @see android.graphics.Bitmap#getDensity() + */ + public void setTargetDensity(Canvas canvas) { + setTargetDensity(canvas.getDensity()); + } + + /** + * Set the density scale at which this drawable will be rendered. + * + * @param metrics The DisplayMetrics indicating the density scale for this drawable. + * + * @see android.graphics.Bitmap#setDensity(int) + * @see android.graphics.Bitmap#getDensity() + */ + public void setTargetDensity(DisplayMetrics metrics) { + mTargetDensity = metrics.densityDpi; + if (mNinePatch != null) { + computeBitmapSize(); + } + } + + /** + * Set the density at which this drawable will be rendered. + * + * @param density The density scale for this drawable. + * + * @see android.graphics.Bitmap#setDensity(int) + * @see android.graphics.Bitmap#getDensity() + */ + public void setTargetDensity(int density) { + mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density; + if (mNinePatch != null) { + computeBitmapSize(); + } + } + + private void computeBitmapSize() { + final int sdensity = mNinePatch.getDensity(); + final int tdensity = mTargetDensity; + mBitmapWidth = Bitmap.scaleFromDensity(mNinePatch.getWidth(), + sdensity, tdensity); + mBitmapHeight = Bitmap.scaleFromDensity(mNinePatch.getHeight(), + sdensity, tdensity); + } + // overrides @Override @@ -111,6 +210,7 @@ public class NinePatchDrawable extends Drawable { if (dither) { options.inDither = false; } + options.inScreenDensity = DisplayMetrics.DENSITY_DEVICE; final Rect padding = new Rect(); Bitmap bitmap = null; @@ -119,7 +219,7 @@ public class NinePatchDrawable extends Drawable { final TypedValue value = new TypedValue(); final InputStream is = r.openRawResource(id, value); - bitmap = BitmapFactory.decodeStream(r, value, is, padding, options); + bitmap = BitmapFactory.decodeResourceStream(r, value, is, padding, options); is.close(); } catch (IOException e) { @@ -136,6 +236,7 @@ public class NinePatchDrawable extends Drawable { setNinePatchState(new NinePatchState( new NinePatch(bitmap, bitmap.getNinePatchChunk(), "XML 9-patch"), padding, dither)); + mNinePatchState.mTargetDensity = mTargetDensity; a.recycle(); } @@ -153,7 +254,7 @@ public class NinePatchDrawable extends Drawable { */ @Override public int getIntrinsicWidth() { - return mNinePatch.getWidth(); + return mBitmapWidth; } /** @@ -161,17 +262,17 @@ public class NinePatchDrawable extends Drawable { */ @Override public int getIntrinsicHeight() { - return mNinePatch.getHeight(); + return mBitmapHeight; } @Override public int getMinimumWidth() { - return mNinePatch.getWidth(); + return mBitmapWidth; } @Override public int getMinimumHeight() { - return mNinePatch.getHeight(); + return mBitmapHeight; } /** @@ -211,6 +312,7 @@ public class NinePatchDrawable extends Drawable { final Rect mPadding; final boolean mDither; int mChangingConfigurations; + int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT; NinePatchState(NinePatch ninePatch, Rect padding) { this(ninePatch, padding, false); @@ -225,8 +327,9 @@ public class NinePatchDrawable extends Drawable { NinePatchState(NinePatchState state) { mNinePatch = new NinePatch(state.mNinePatch); mPadding = new Rect(state.mPadding); - mChangingConfigurations = state.mChangingConfigurations; mDither = state.mDither; + mChangingConfigurations = state.mChangingConfigurations; + mTargetDensity = state.mTargetDensity; } @Override diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h index edd0cae637261..e524e2a31ed92 100644 --- a/include/utils/ResourceTypes.h +++ b/include/utils/ResourceTypes.h @@ -1655,7 +1655,8 @@ public: ssize_t resolveReference(Res_value* inOutValue, ssize_t blockIndex, uint32_t* outLastRef = NULL, - uint32_t* inoutTypeSpecFlags = NULL) const; + uint32_t* inoutTypeSpecFlags = NULL, + ResTable_config* outConfig = NULL) const; enum { TMP_BUFFER_SIZE = 16 @@ -1729,7 +1730,8 @@ public: */ ssize_t resolveAttributeReference(Res_value* inOutValue, ssize_t blockIndex, uint32_t* outLastRef = NULL, - uint32_t* inoutTypeSpecFlags = NULL) const; + uint32_t* inoutTypeSpecFlags = NULL, + ResTable_config* inoutConfig = NULL) const; void dumpToLog() const; diff --git a/keystore/java/android/security/CertTool.java b/keystore/java/android/security/CertTool.java index 79418bd489958..b1b78ea963626 100644 --- a/keystore/java/android/security/CertTool.java +++ b/keystore/java/android/security/CertTool.java @@ -72,7 +72,7 @@ public class CertTool { private native String getPkcs12PrivateKey(int handle); private native String popPkcs12CertificateStack(int handle); private native void freePkcs12Handle(int handle); - private native String generateCertificateRequest(int bits, String subject); + private native String generateCertificateRequest(int bits, String challenge); private native boolean isPkcs12Keystore(byte[] data); private native int generateX509Certificate(byte[] data); private native boolean isCaCertificate(int handle); @@ -124,7 +124,7 @@ public class CertTool { public String generateKeyPair(int keyStrengthIndex, String challenge, String dirName) { return generateCertificateRequest(getKeyLength(keyStrengthIndex), - dirName); + challenge); } private Intent prepareIntent(String title, byte[] data, String namespace, @@ -140,7 +140,7 @@ public class CertTool { private void addExtraIntentInfo(Intent intent, String namespace, String data) { - intent.putExtra(KEY_ITEM + "1", data); + intent.putExtra(KEY_ITEM + "1", data.getBytes()); intent.putExtra(KEY_NAMESPACE + "1", namespace); } diff --git a/keystore/jni/cert.c b/keystore/jni/cert.c index 0db28fd0e8227..006a0a3512586 100644 --- a/keystore/jni/cert.c +++ b/keystore/jni/cert.c @@ -36,17 +36,17 @@ static char emsg[][30] = { STR(ERR_CONSTRUCT_NEW_DATA), STR(ERR_RSA_KEYGEN), STR(ERR_X509_PROCESS), - STR(ERR_BIO_READ), + STR(ERR_SPKAC_TOO_LONG), + STR(ERR_INVALID_ARGS), }; -static void save_in_store(X509_REQ *req, EVP_PKEY *pkey) +static void save_in_store(EVP_PKEY *pkey) { EVP_PKEY *newpkey = EVP_PKEY_new(); RSA *rsa = EVP_PKEY_get1_RSA(pkey); EVP_PKEY_set1_RSA(newpkey, rsa); PKEY_STORE_free(pkey_store[store_index]); - pkey_store[store_index].key_len = - i2d_X509_PUBKEY(req->req_info->pubkey, &pkey_store[store_index].public_key); + pkey_store[store_index].key_len = i2d_RSA_PUBKEY(rsa, &pkey_store[store_index].public_key); pkey_store[store_index++].pkey = newpkey; store_index %= KEYGEN_STORE_SIZE; RSA_free(rsa); @@ -69,17 +69,19 @@ static EVP_PKEY *get_pkey_from_store(X509 *cert) return (i == KEYGEN_STORE_SIZE) ? NULL : pkey_store[i].pkey; } -int gen_csr(int bits, const char *organizations, char reply[REPLY_MAX]) +int gen_csr(int bits, const char *challenge, char reply[REPLY_MAX]) { int len, ret_code = 0; BIGNUM *bn = NULL; - BIO *bio = NULL; + char *spkstr = NULL; EVP_PKEY *pkey = NULL; RSA *rsa = NULL; - X509_REQ *req = NULL; - X509_NAME *name = NULL; + NETSCAPE_SPKI *req = NULL; - if ((bio = BIO_new(BIO_s_mem())) == NULL) goto err; + if (challenge == NULL) { + ret_code = ERR_INVALID_ARGS; + goto err; + } if ((bits != KEYLENGTH_MEDIUM) && (bits != KEYLENGTH_MAXIMUM)) { ret_code = ERR_INVALID_KEY_LENGTH; @@ -87,7 +89,7 @@ int gen_csr(int bits, const char *organizations, char reply[REPLY_MAX]) } if (((pkey = EVP_PKEY_new()) == NULL) || - ((req = X509_REQ_new()) == NULL) || + ((req = NETSCAPE_SPKI_new()) == NULL) || ((rsa = RSA_new()) == NULL) || ((bn = BN_new()) == NULL)) { ret_code = ERR_CONSTRUCT_NEW_DATA; goto err; @@ -100,40 +102,26 @@ int gen_csr(int bits, const char *organizations, char reply[REPLY_MAX]) goto err; } - // rsa will be part of the req, it will be freed in X509_REQ_free(req) rsa = NULL; + ASN1_STRING_set(req->spkac->challenge, challenge, (int)strlen(challenge)); + NETSCAPE_SPKI_set_pubkey(req, pkey); + NETSCAPE_SPKI_sign(req, pkey, EVP_md5()); + spkstr = NETSCAPE_SPKI_b64_encode(req); - X509_REQ_set_pubkey(req, pkey); - name = X509_REQ_get_subject_name(req); - - X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, - (const unsigned char *)"US", -1, -1, 0); - X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, - (const unsigned char *) ANDROID_KEYSTORE, - -1, -1, 0); - X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, - (const unsigned char *)organizations, -1, -1, 0); - - if (!X509_REQ_sign(req, pkey, EVP_md5()) || - (PEM_write_bio_X509_REQ(bio, req) <= 0)) { - ret_code = ERR_X509_PROCESS; - goto err; - } - if ((len = BIO_read(bio, reply, REPLY_MAX - 1)) > 0) { - reply[len] = 0; - save_in_store(req, pkey); + if ((strlcpy(reply, spkstr, REPLY_MAX)) < REPLY_MAX) { + save_in_store(pkey); } else { - ret_code = ERR_BIO_READ; + ret_code = ERR_SPKAC_TOO_LONG; } err: if (rsa) RSA_free(rsa); if (bn) BN_free(bn); - if (req) X509_REQ_free(req); + if (req) NETSCAPE_SPKI_free(req); if (pkey) EVP_PKEY_free(pkey); - if (bio) BIO_free(bio); + if (spkstr) OPENSSL_free(spkstr); if ((ret_code > 0) && (ret_code < ERR_MAXIMUM)) LOGE(emsg[ret_code]); - return ret_code; + return -ret_code; } PKCS12 *get_p12_handle(const char *buf, int bufLen) diff --git a/keystore/jni/cert.h b/keystore/jni/cert.h index aaa7602d81262..a9e1a9e404e87 100644 --- a/keystore/jni/cert.h +++ b/keystore/jni/cert.h @@ -32,8 +32,9 @@ #define ERR_CONSTRUCT_NEW_DATA 2 #define ERR_RSA_KEYGEN 3 #define ERR_X509_PROCESS 4 -#define ERR_BIO_READ 5 -#define ERR_MAXIMUM 6 +#define ERR_SPKAC_TOO_LONG 5 +#define ERR_INVALID_ARGS 6 +#define ERR_MAXIMUM 7 typedef struct { EVP_PKEY *pkey; diff --git a/keystore/jni/certtool.c b/keystore/jni/certtool.c index 1ae8dab4281f5..b36b34a2c5517 100644 --- a/keystore/jni/certtool.c +++ b/keystore/jni/certtool.c @@ -30,13 +30,17 @@ jstring android_security_CertTool_generateCertificateRequest(JNIEnv* env, jobject thiz, jint bits, - jstring subject) + jstring jChallenge) { + int ret = -1; + jboolean bIsCopy; char csr[REPLY_MAX]; - if (gen_csr(bits, subject, csr) == 0) { - return (*env)->NewStringUTF(env, csr); - } + const char* challenge = (*env)->GetStringUTFChars(env, jChallenge, &bIsCopy); + + ret = gen_csr(bits, challenge , csr); + (*env)->ReleaseStringUTFChars(env, jChallenge, challenge); + if (ret == 0) return (*env)->NewStringUTF(env, csr); return NULL; } diff --git a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp index eec645edc907a..ab02fa0ee1a29 100644 --- a/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp +++ b/libs/surfaceflinger/DisplayHardware/DisplayHardware.cpp @@ -197,6 +197,9 @@ void DisplayHardware::init(uint32_t dpy) LOGW("ro.sf.lcd_density not defined, using 160 dpi by default."); strcpy(property, "160"); } + } else { + /* for the emulator case, reset the dpi values too */ + mDpiX = mDpiY = atoi(property); } mDensity = atoi(property) * (1.0f/160.0f); diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp index fb256638cd716..97dfeccae1d49 100644 --- a/libs/surfaceflinger/SurfaceFlinger.cpp +++ b/libs/surfaceflinger/SurfaceFlinger.cpp @@ -691,9 +691,14 @@ void SurfaceFlinger::handleTransaction(uint32_t transactionFlags) // some layers might have been removed, so // we need to update the regions they're exposing. - size_t c = mRemovedLayers.size(); + const SortedVector& removedLayers(mRemovedLayers); + size_t c = removedLayers.size(); if (c) { mVisibleRegionsDirty = true; + while (c--) { + mDirtyRegionRemovedLayer.orSelf( + removedLayers[c]->visibleRegionScreen); + } } const LayerVector& currentLayers = mCurrentState.layersSortedByZ; @@ -733,17 +738,15 @@ void SurfaceFlinger::computeVisibleRegions( layer->validateVisibility(planeTransform); // start with the whole surface at its current location - const Layer::State& s = layer->drawingState(); - const Rect bounds(layer->visibleBounds()); + const Layer::State& s(layer->drawingState()); // handle hidden surfaces by setting the visible region to empty Region opaqueRegion; Region visibleRegion; Region coveredRegion; - if (UNLIKELY((s.flags & ISurfaceComposer::eLayerHidden) || !s.alpha)) { - visibleRegion.clear(); - } else { + if (LIKELY(!(s.flags & ISurfaceComposer::eLayerHidden) && s.alpha)) { const bool translucent = layer->needsBlending(); + const Rect bounds(layer->visibleBounds()); visibleRegion.set(bounds); coveredRegion = visibleRegion; @@ -790,12 +793,16 @@ void SurfaceFlinger::computeVisibleRegions( layer->setVisibleRegion(visibleRegion); layer->setCoveredRegion(coveredRegion); - // If a secure layer is partially visible, lockdown the screen! + // If a secure layer is partially visible, lock-down the screen! if (layer->isSecure() && !visibleRegion.isEmpty()) { secureFrameBuffer = true; } } + // invalidate the areas where a layer was removed + dirtyRegion.orSelf(mDirtyRegionRemovedLayer); + mDirtyRegionRemovedLayer.clear(); + mSecureFrameBuffer = secureFrameBuffer; opaqueRegion = aboveOpaqueLayers; } diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h index 15913f2318f72..0d63e1db6a522 100644 --- a/libs/surfaceflinger/SurfaceFlinger.h +++ b/libs/surfaceflinger/SurfaceFlinger.h @@ -351,6 +351,7 @@ private: // Can only accessed from the main thread, these members // don't need synchronization Region mDirtyRegion; + Region mDirtyRegionRemovedLayer; Region mInvalidRegion; Region mWormholeRegion; Client* mLastScheduledBroadcast; diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp index 4dca8bd81608d..0831f4a0c0f0e 100644 --- a/libs/utils/ResourceTypes.cpp +++ b/libs/utils/ResourceTypes.cpp @@ -1486,7 +1486,7 @@ ssize_t ResTable::Theme::getAttribute(uint32_t resID, Res_value* outValue, ssize_t ResTable::Theme::resolveAttributeReference(Res_value* inOutValue, ssize_t blockIndex, uint32_t* outLastRef, - uint32_t* inoutTypeSpecFlags) const + uint32_t* inoutTypeSpecFlags, ResTable_config* inoutConfig) const { //printf("Resolving type=0x%x\n", inOutValue->dataType); if (inOutValue->dataType == Res_value::TYPE_ATTRIBUTE) { @@ -1498,7 +1498,8 @@ ssize_t ResTable::Theme::resolveAttributeReference(Res_value* inOutValue, return blockIndex; } } - return mTable.resolveReference(inOutValue, blockIndex, outLastRef); + return mTable.resolveReference(inOutValue, blockIndex, outLastRef, + inoutTypeSpecFlags, inoutConfig); } void ResTable::Theme::dumpToLog() const @@ -1891,7 +1892,8 @@ ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag } ssize_t ResTable::resolveReference(Res_value* value, ssize_t blockIndex, - uint32_t* outLastRef, uint32_t* inoutTypeSpecFlags) const + uint32_t* outLastRef, uint32_t* inoutTypeSpecFlags, + ResTable_config* outConfig) const { int count=0; while (blockIndex >= 0 && value->dataType == value->TYPE_REFERENCE @@ -1899,7 +1901,8 @@ ssize_t ResTable::resolveReference(Res_value* value, ssize_t blockIndex, if (outLastRef) *outLastRef = value->data; uint32_t lastRef = value->data; uint32_t newFlags = 0; - const ssize_t newIndex = getResource(value->data, value, true, &newFlags); + const ssize_t newIndex = getResource(value->data, value, true, &newFlags, + outConfig); //LOGI("Resolving reference d=%p: newIndex=%d, t=0x%02x, d=%p\n", // (void*)lastRef, (int)newIndex, (int)value->dataType, (void*)value->data); //printf("Getting reference 0x%08x: newIndex=%d\n", value->data, newIndex); diff --git a/media/java/android/media/JetPlayer.java b/media/java/android/media/JetPlayer.java index 4fb0ead7ff59b..d75d81d92e53e 100644 --- a/media/java/android/media/JetPlayer.java +++ b/media/java/android/media/JetPlayer.java @@ -183,6 +183,7 @@ public class JetPlayer */ public void release() { native_release(); + singletonRef = null; } diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp index ce80f92dbb0ea..1fdecdd054df9 100644 --- a/media/jni/soundpool/SoundPool.cpp +++ b/media/jni/soundpool/SoundPool.cpp @@ -18,8 +18,7 @@ #define LOG_TAG "SoundPool" #include -// -#define USE_SHARED_MEM_BUFFER +//#define USE_SHARED_MEM_BUFFER // XXX needed for timing latency #include diff --git a/packages/SettingsProvider/res/values-cs/defaults.xml b/packages/SettingsProvider/res/values-cs/defaults.xml deleted file mode 100644 index a7c01b39e143f..0000000000000 --- a/packages/SettingsProvider/res/values-cs/defaults.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - "mobil,bluetooth,wifi" - "gps" - - - diff --git a/packages/SettingsProvider/res/values-cs/strings.xml b/packages/SettingsProvider/res/values-cs/strings.xml index dc75a92d6cf4f..2b089d92e127b 100644 --- a/packages/SettingsProvider/res/values-cs/strings.xml +++ b/packages/SettingsProvider/res/values-cs/strings.xml @@ -15,5 +15,5 @@ --> - "Paměť pro nastavení" + "Paměť pro nastavení" diff --git a/packages/SettingsProvider/res/values-de/defaults.xml b/packages/SettingsProvider/res/values-de/defaults.xml deleted file mode 100644 index f85d3f0ce8b7c..0000000000000 --- a/packages/SettingsProvider/res/values-de/defaults.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - "Mobilfunk, Bluetooth, WLAN" - "GPS" - - - diff --git a/packages/SettingsProvider/res/values-de/strings.xml b/packages/SettingsProvider/res/values-de/strings.xml index 50c8a142357af..a293522a2e0b1 100644 --- a/packages/SettingsProvider/res/values-de/strings.xml +++ b/packages/SettingsProvider/res/values-de/strings.xml @@ -15,5 +15,5 @@ --> - "Einstellungsspeicher" + "Einstellungsspeicher" diff --git a/packages/SettingsProvider/res/values-es/defaults.xml b/packages/SettingsProvider/res/values-es/defaults.xml deleted file mode 100644 index a64805aaa0ce8..0000000000000 --- a/packages/SettingsProvider/res/values-es/defaults.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - "móvil,bluetooth,wifi" - "gps" - - - diff --git a/packages/SettingsProvider/res/values-es/strings.xml b/packages/SettingsProvider/res/values-es/strings.xml index d30d1953f47ef..de3958b37485e 100644 --- a/packages/SettingsProvider/res/values-es/strings.xml +++ b/packages/SettingsProvider/res/values-es/strings.xml @@ -15,5 +15,5 @@ --> - "Almacenamiento de configuración" + "Almacenamiento de configuración" diff --git a/packages/SettingsProvider/res/values-fr/defaults.xml b/packages/SettingsProvider/res/values-fr/defaults.xml deleted file mode 100644 index 56334cc3fc402..0000000000000 --- a/packages/SettingsProvider/res/values-fr/defaults.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - "cellulaire, Bluetooth, Wi-Fi" - "gps" - - - diff --git a/packages/SettingsProvider/res/values-fr/strings.xml b/packages/SettingsProvider/res/values-fr/strings.xml index 686ec8b8f36d0..7a1386a861c3c 100644 --- a/packages/SettingsProvider/res/values-fr/strings.xml +++ b/packages/SettingsProvider/res/values-fr/strings.xml @@ -15,5 +15,5 @@ --> - "Stockage des paramètres" + "Stockage des paramètres" diff --git a/packages/SettingsProvider/res/values-it/defaults.xml b/packages/SettingsProvider/res/values-it/defaults.xml deleted file mode 100644 index 19c0896553e6d..0000000000000 --- a/packages/SettingsProvider/res/values-it/defaults.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - "cellulare,bluetooth,wifi" - "gps" - - - diff --git a/packages/SettingsProvider/res/values-it/strings.xml b/packages/SettingsProvider/res/values-it/strings.xml index 29e462fa4bbf7..f88a6540c1f2a 100644 --- a/packages/SettingsProvider/res/values-it/strings.xml +++ b/packages/SettingsProvider/res/values-it/strings.xml @@ -15,5 +15,5 @@ --> - "Archiviazione impostazioni" + "Archiviazione impostazioni" diff --git a/packages/SettingsProvider/res/values-nl/defaults.xml b/packages/SettingsProvider/res/values-nl/defaults.xml deleted file mode 100644 index 625235ac7e2c0..0000000000000 --- a/packages/SettingsProvider/res/values-nl/defaults.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - "mobiel,bluetooth,wifi" - "gps" - - - diff --git a/packages/SettingsProvider/res/values-nl/strings.xml b/packages/SettingsProvider/res/values-nl/strings.xml index b37b5357f82d2..7a0e416737166 100644 --- a/packages/SettingsProvider/res/values-nl/strings.xml +++ b/packages/SettingsProvider/res/values-nl/strings.xml @@ -15,5 +15,5 @@ --> - "Opslagruimte voor instellingen" + "Opslagruimte voor instellingen" diff --git a/packages/SettingsProvider/res/values-pl/defaults.xml b/packages/SettingsProvider/res/values-pl/defaults.xml deleted file mode 100644 index b60832ebbf3f8..0000000000000 --- a/packages/SettingsProvider/res/values-pl/defaults.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - "komórka,bluetooth,wifi" - "gps" - - - diff --git a/packages/SettingsProvider/res/values-pl/strings.xml b/packages/SettingsProvider/res/values-pl/strings.xml index 4ab1e915de992..ccff82e372a1e 100644 --- a/packages/SettingsProvider/res/values-pl/strings.xml +++ b/packages/SettingsProvider/res/values-pl/strings.xml @@ -15,5 +15,5 @@ --> - "Pamięć ustawień" + "Pamięć ustawień" diff --git a/packages/SettingsProvider/res/values-zh-rTW/strings.xml b/packages/SettingsProvider/res/values-zh-rTW/strings.xml index b24144a255a8a..0700a762ada8c 100644 --- a/packages/SettingsProvider/res/values-zh-rTW/strings.xml +++ b/packages/SettingsProvider/res/values-zh-rTW/strings.xml @@ -15,5 +15,5 @@ --> - "設定儲存空間" + "設定儲存空間" diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml index f8adaa12e43d1..f60ea57eb6f82 100644 --- a/packages/SettingsProvider/res/values/defaults.xml +++ b/packages/SettingsProvider/res/values/defaults.xml @@ -21,7 +21,7 @@ 60000 false - cell,bluetooth,wifi + cell,bluetooth,wifi true true @@ -35,7 +35,7 @@ Network location is off by default because it requires user opt-in via Setup Wizard or Settings. --> - gps + gps 1 true @@ -43,5 +43,5 @@ true false - + diff --git a/packages/TtsService/src/android/tts/TtsService.java b/packages/TtsService/src/android/tts/TtsService.java index e52ba80eefa47..1b99d32cc9c08 100755 --- a/packages/TtsService/src/android/tts/TtsService.java +++ b/packages/TtsService/src/android/tts/TtsService.java @@ -109,7 +109,9 @@ public class TtsService extends Service implements OnCompletionListener { mFilename = file; } } - + // If the speech queue is locked for more than 5 seconds, something has gone + // very wrong with processSpeechQueue. + private static final int SPEECHQUEUELOCK_TIMEOUT = 5000; private static final int MAX_SPEECH_ITEM_CHAR_LENGTH = 4000; private static final int MAX_FILENAME_LENGTH = 250; // TODO use the TTS stream type when available @@ -192,7 +194,7 @@ public class TtsService extends Service implements OnCompletionListener { private boolean isDefaultEnforced() { return (android.provider.Settings.Secure.getInt(mResolver, android.provider.Settings.Secure.TTS_USE_DEFAULTS, - TextToSpeech.Engine.FALLBACK_TTS_USE_DEFAULTS) + TextToSpeech.Engine.USE_DEFAULTS) == 1 ); } @@ -200,7 +202,7 @@ public class TtsService extends Service implements OnCompletionListener { private int getDefaultRate() { return android.provider.Settings.Secure.getInt(mResolver, android.provider.Settings.Secure.TTS_DEFAULT_RATE, - TextToSpeech.Engine.FALLBACK_TTS_DEFAULT_RATE); + TextToSpeech.Engine.DEFAULT_RATE); } @@ -344,7 +346,7 @@ public class TtsService extends Service implements OnCompletionListener { */ private int speak(String callingApp, String text, int queueMode, ArrayList params) { Log.v("TtsService", "TTS service received " + text); - if (queueMode == TextToSpeech.TTS_QUEUE_FLUSH) { + if (queueMode == TextToSpeech.QUEUE_FLUSH) { stop(callingApp); } else if (queueMode == 2) { stopAll(callingApp); @@ -353,7 +355,7 @@ public class TtsService extends Service implements OnCompletionListener { if (!mIsSpeaking) { processSpeechQueue(); } - return TextToSpeech.TTS_SUCCESS; + return TextToSpeech.SUCCESS; } /** @@ -370,7 +372,7 @@ public class TtsService extends Service implements OnCompletionListener { */ private int playEarcon(String callingApp, String earcon, int queueMode, ArrayList params) { - if (queueMode == TextToSpeech.TTS_QUEUE_FLUSH) { + if (queueMode == TextToSpeech.QUEUE_FLUSH) { stop(callingApp); } else if (queueMode == 2) { stopAll(callingApp); @@ -379,19 +381,18 @@ public class TtsService extends Service implements OnCompletionListener { if (!mIsSpeaking) { processSpeechQueue(); } - return TextToSpeech.TTS_SUCCESS; + return TextToSpeech.SUCCESS; } /** * Stops all speech output and removes any utterances still in the queue for the calling app. */ private int stop(String callingApp) { - int result = TextToSpeech.TTS_ERROR; + int result = TextToSpeech.ERROR; boolean speechQueueAvailable = false; try{ - // If the queue is locked for more than 1 second, - // something has gone very wrong with processSpeechQueue. - speechQueueAvailable = speechQueueLock.tryLock(1000, TimeUnit.MILLISECONDS); + speechQueueAvailable = + speechQueueLock.tryLock(SPEECHQUEUELOCK_TIMEOUT, TimeUnit.MILLISECONDS); if (speechQueueAvailable) { Log.i("TtsService", "Stopping"); for (int i = mSpeechQueue.size() - 1; i > -1; i--){ @@ -413,7 +414,7 @@ public class TtsService extends Service implements OnCompletionListener { mIsSpeaking = false; mCurrentSpeechItem = null; } else { - result = TextToSpeech.TTS_SUCCESS; + result = TextToSpeech.SUCCESS; } Log.i("TtsService", "Stopped"); } @@ -436,12 +437,11 @@ public class TtsService extends Service implements OnCompletionListener { * Stops all speech output and removes any utterances still in the queue globally. */ private int stopAll(String callingApp) { - int result = TextToSpeech.TTS_ERROR; + int result = TextToSpeech.ERROR; boolean speechQueueAvailable = false; try{ - // If the queue is locked for more than 1 second, - // something has gone very wrong with processSpeechQueue. - speechQueueAvailable = speechQueueLock.tryLock(1000, TimeUnit.MILLISECONDS); + speechQueueAvailable = + speechQueueLock.tryLock(SPEECHQUEUELOCK_TIMEOUT, TimeUnit.MILLISECONDS); if (speechQueueAvailable) { for (int i = mSpeechQueue.size() - 1; i > -1; i--){ if (mSpeechQueue.get(i).mType != SpeechItem.TEXT_TO_FILE){ @@ -463,7 +463,7 @@ public class TtsService extends Service implements OnCompletionListener { mIsSpeaking = false; mCurrentSpeechItem = null; } else { - result = TextToSpeech.TTS_SUCCESS; + result = TextToSpeech.SUCCESS; } Log.i("TtsService", "Stopped all"); } @@ -487,7 +487,7 @@ public class TtsService extends Service implements OnCompletionListener { if (params != null){ for (int i = 0; i < params.size() - 1; i = i + 2){ String param = params.get(i); - if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_UTTERANCE_ID)){ + if (param.equals(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID)){ utteranceId = params.get(i+1); } } @@ -500,14 +500,14 @@ public class TtsService extends Service implements OnCompletionListener { private int playSilence(String callingApp, long duration, int queueMode, ArrayList params) { - if (queueMode == TextToSpeech.TTS_QUEUE_FLUSH) { + if (queueMode == TextToSpeech.QUEUE_FLUSH) { stop(callingApp); } mSpeechQueue.add(new SpeechItem(callingApp, duration, params)); if (!mIsSpeaking) { processSpeechQueue(); } - return TextToSpeech.TTS_SUCCESS; + return TextToSpeech.SUCCESS; } private void silence(final SpeechItem speechItem) { @@ -517,7 +517,7 @@ public class TtsService extends Service implements OnCompletionListener { if (speechItem.mParams != null){ for (int i = 0; i < speechItem.mParams.size() - 1; i = i + 2){ String param = speechItem.mParams.get(i); - if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_UTTERANCE_ID)){ + if (param.equals(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID)){ utteranceId = speechItem.mParams.get(i+1); } } @@ -562,17 +562,17 @@ public class TtsService extends Service implements OnCompletionListener { for (int i = 0; i < speechItem.mParams.size() - 1; i = i + 2){ String param = speechItem.mParams.get(i); if (param != null) { - if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_RATE)) { + if (param.equals(TextToSpeech.Engine.KEY_PARAM_RATE)) { speechRate = speechItem.mParams.get(i+1); - } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_LANGUAGE)){ + } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_LANGUAGE)){ language = speechItem.mParams.get(i+1); - } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_COUNTRY)){ + } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_COUNTRY)){ country = speechItem.mParams.get(i+1); - } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_VARIANT)){ + } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_VARIANT)){ variant = speechItem.mParams.get(i+1); - } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_UTTERANCE_ID)){ + } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID)){ utteranceId = speechItem.mParams.get(i+1); - } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_STREAM)) { + } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_STREAM)) { try { streamType = Integer.parseInt(speechItem.mParams.get(i + 1)); @@ -638,15 +638,15 @@ public class TtsService extends Service implements OnCompletionListener { for (int i = 0; i < speechItem.mParams.size() - 1; i = i + 2){ String param = speechItem.mParams.get(i); if (param != null) { - if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_RATE)) { + if (param.equals(TextToSpeech.Engine.KEY_PARAM_RATE)) { speechRate = speechItem.mParams.get(i+1); - } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_LANGUAGE)){ + } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_LANGUAGE)){ language = speechItem.mParams.get(i+1); - } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_COUNTRY)){ + } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_COUNTRY)){ country = speechItem.mParams.get(i+1); - } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_VARIANT)){ + } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_VARIANT)){ variant = speechItem.mParams.get(i+1); - } else if (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_UTTERANCE_ID)){ + } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID)){ utteranceId = speechItem.mParams.get(i+1); } } @@ -698,7 +698,7 @@ public class TtsService extends Service implements OnCompletionListener { } private void broadcastTtsQueueProcessingCompleted(){ - Intent i = new Intent(Intent.ACTION_TTS_QUEUE_PROCESSING_COMPLETED); + Intent i = new Intent(TextToSpeech.ACTION_TTS_QUEUE_PROCESSING_COMPLETED); sendBroadcast(i); } @@ -752,8 +752,10 @@ public class TtsService extends Service implements OnCompletionListener { private void processSpeechQueue() { boolean speechQueueAvailable = false; try { - speechQueueAvailable = speechQueueLock.tryLock(); + speechQueueAvailable = + speechQueueLock.tryLock(SPEECHQUEUELOCK_TIMEOUT, TimeUnit.MILLISECONDS); if (!speechQueueAvailable) { + Log.e("TtsService", "processSpeechQueue - Speech queue is unavailable."); return; } if (mSpeechQueue.size() < 1) { @@ -822,6 +824,9 @@ public class TtsService extends Service implements OnCompletionListener { if (mSpeechQueue.size() > 0) { mSpeechQueue.remove(0); } + } catch (InterruptedException e) { + Log.e("TtsService", "TTS processSpeechQueue: tryLock interrupted"); + e.printStackTrace(); } finally { // This check is needed because finally will always run; even if the // method returns somewhere in the try block. @@ -838,7 +843,7 @@ public class TtsService extends Service implements OnCompletionListener { } for (int i = 0; i < paramList.size() - 1; i = i + 2) { String param = paramList.get(i); - if ((param != null) && (param.equals(TextToSpeech.Engine.TTS_KEY_PARAM_STREAM))) { + if ((param != null) && (param.equals(TextToSpeech.Engine.KEY_PARAM_STREAM))) { try { streamType = Integer.parseInt(paramList.get(i + 1)); } catch (NumberFormatException e) { @@ -905,18 +910,18 @@ public class TtsService extends Service implements OnCompletionListener { if (cb != null) { mCallbacks.register(cb); mCallbacksMap.put(packageName, cb); - return TextToSpeech.TTS_SUCCESS; + return TextToSpeech.SUCCESS; } - return TextToSpeech.TTS_ERROR; + return TextToSpeech.ERROR; } public int unregisterCallback(String packageName, ITtsCallback cb) { if (cb != null) { mCallbacksMap.remove(packageName); mCallbacks.unregister(cb); - return TextToSpeech.TTS_SUCCESS; + return TextToSpeech.SUCCESS; } - return TextToSpeech.TTS_ERROR; + return TextToSpeech.ERROR; } /** diff --git a/packages/VpnServices/src/com/android/server/vpn/AndroidServiceProxy.java b/packages/VpnServices/src/com/android/server/vpn/AndroidServiceProxy.java deleted file mode 100644 index e4c070ff8b296..0000000000000 --- a/packages/VpnServices/src/com/android/server/vpn/AndroidServiceProxy.java +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright (C) 2009, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.vpn; - -import android.net.LocalSocket; -import android.net.LocalSocketAddress; -import android.net.vpn.VpnManager; -import android.os.SystemProperties; -import android.util.Log; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * Proxy to start, stop and interact with an Android service defined in init.rc. - * The android service is expected to accept connection through Unix domain - * socket. When the proxy successfully starts the service, it will establish a - * socket connection with the service. The socket serves two purposes: (1) send - * commands to the service; (2) for the proxy to know whether the service is - * alive. - * - * After the service receives commands from the proxy, it should return either - * 0 if the service will close the socket (and the proxy will re-establish - * another connection immediately after), or 1 if the socket is remained alive. - */ -public class AndroidServiceProxy extends ProcessProxy { - private static final int WAITING_TIME = 15; // sec - - private static final String SVC_STATE_CMD_PREFIX = "init.svc."; - private static final String SVC_START_CMD = "ctl.start"; - private static final String SVC_STOP_CMD = "ctl.stop"; - private static final String SVC_STATE_RUNNING = "running"; - private static final String SVC_STATE_STOPPED = "stopped"; - - private static final int END_OF_ARGUMENTS = 255; - - private static final int STOP_SERVICE = -1; - private static final int AUTH_ERROR_CODE = 51; - - private String mServiceName; - private String mSocketName; - private LocalSocket mKeepaliveSocket; - private boolean mControlSocketInUse; - private Integer mSocketResult = null; - private String mTag; - - /** - * Creates a proxy with the service name. - * @param serviceName the service name - */ - public AndroidServiceProxy(String serviceName) { - mServiceName = serviceName; - mSocketName = serviceName; - mTag = "SProxy_" + serviceName; - } - - @Override - public String getName() { - return "Service " + mServiceName; - } - - @Override - public synchronized void stop() { - if (isRunning()) { - try { - setResultAndCloseControlSocket(STOP_SERVICE); - } catch (IOException e) { - // should not occur - throw new RuntimeException(e); - } - } - Log.d(mTag, "----- Stop: " + mServiceName); - SystemProperties.set(SVC_STOP_CMD, mServiceName); - } - - /** - * Sends a command with arguments to the service through the control socket. - */ - public synchronized void sendCommand(String ...args) throws IOException { - OutputStream out = getControlSocketOutput(); - for (String arg : args) outputString(out, arg); - out.write(END_OF_ARGUMENTS); - out.flush(); - checkSocketResult(); - } - - /** - * {@inheritDoc} - * The method returns when the service exits. - */ - @Override - protected void performTask() throws IOException { - String svc = mServiceName; - Log.d(mTag, "----- Stop the daemon just in case: " + mServiceName); - SystemProperties.set(SVC_STOP_CMD, mServiceName); - if (!blockUntil(SVC_STATE_STOPPED, 5)) { - throw new IOException("cannot start service anew: " + svc - + ", it is still running"); - } - - Log.d(mTag, "+++++ Start: " + svc); - SystemProperties.set(SVC_START_CMD, svc); - - boolean success = blockUntil(SVC_STATE_RUNNING, WAITING_TIME); - - if (success) { - Log.d(mTag, "----- Running: " + svc + ", create keepalive socket"); - LocalSocket s = mKeepaliveSocket = createServiceSocket(); - setState(ProcessState.RUNNING); - - if (s == null) { - // no socket connection, stop hosting the service - stop(); - return; - } - try { - for (;;) { - InputStream in = s.getInputStream(); - int data = in.read(); - if (data >= 0) { - Log.d(mTag, "got data from control socket: " + data); - - setSocketResult(data); - } else { - // service is gone - if (mControlSocketInUse) setSocketResult(-1); - break; - } - } - Log.d(mTag, "control connection closed"); - } catch (IOException e) { - if (e instanceof VpnConnectingError) { - throw e; - } else { - Log.d(mTag, "control socket broken: " + e.getMessage()); - } - } - - // Wait 5 seconds for the service to exit - success = blockUntil(SVC_STATE_STOPPED, 5); - Log.d(mTag, "stopping " + svc + ", success? " + success); - } else { - setState(ProcessState.STOPPED); - throw new IOException("cannot start service: " + svc); - } - } - - private LocalSocket createServiceSocket() throws IOException { - LocalSocket s = new LocalSocket(); - LocalSocketAddress a = new LocalSocketAddress(mSocketName, - LocalSocketAddress.Namespace.RESERVED); - - // try a few times in case the service has not listen()ed - IOException excp = null; - for (int i = 0; i < 10; i++) { - try { - s.connect(a); - return s; - } catch (IOException e) { - Log.d(mTag, "service not yet listen()ing; try again"); - excp = e; - sleep(500); - } - } - throw excp; - } - - private OutputStream getControlSocketOutput() throws IOException { - if (mKeepaliveSocket != null) { - mControlSocketInUse = true; - mSocketResult = null; - return mKeepaliveSocket.getOutputStream(); - } else { - throw new IOException("no control socket available"); - } - } - - private void checkSocketResult() throws IOException { - try { - // will be notified when the result comes back from service - if (mSocketResult == null) wait(); - } catch (InterruptedException e) { - Log.d(mTag, "checkSocketResult(): " + e); - } finally { - mControlSocketInUse = false; - if ((mSocketResult == null) || (mSocketResult < 0)) { - throw new IOException("socket error, result from service: " - + mSocketResult); - } - } - } - - private synchronized void setSocketResult(int result) - throws VpnConnectingError { - if (mControlSocketInUse) { - mSocketResult = result; - notifyAll(); - } else if (result > 0) { - // error from daemon - throw new VpnConnectingError((result == AUTH_ERROR_CODE) - ? VpnManager.VPN_ERROR_AUTH - : VpnManager.VPN_ERROR_CONNECTION_FAILED); - } - } - - private void setResultAndCloseControlSocket(int result) - throws VpnConnectingError { - setSocketResult(result); - try { - mKeepaliveSocket.shutdownInput(); - mKeepaliveSocket.shutdownOutput(); - mKeepaliveSocket.close(); - } catch (IOException e) { - Log.e(mTag, "close keepalive socket", e); - } finally { - mKeepaliveSocket = null; - } - } - - /** - * Waits for the process to be in the expected state. The method returns - * false if after the specified duration (in seconds), the process is still - * not in the expected state. - */ - private boolean blockUntil(String expectedState, int waitTime) { - String cmd = SVC_STATE_CMD_PREFIX + mServiceName; - int sleepTime = 200; // ms - int n = waitTime * 1000 / sleepTime; - for (int i = 0; i < n; i++) { - if (expectedState.equals(SystemProperties.get(cmd))) { - Log.d(mTag, mServiceName + " is " + expectedState + " after " - + (i * sleepTime) + " msec"); - break; - } - sleep(sleepTime); - } - return expectedState.equals(SystemProperties.get(cmd)); - } - - private void outputString(OutputStream out, String s) throws IOException { - byte[] bytes = s.getBytes(); - out.write(bytes.length); - out.write(bytes); - out.flush(); - } -} diff --git a/packages/VpnServices/src/com/android/server/vpn/DaemonProxy.java b/packages/VpnServices/src/com/android/server/vpn/DaemonProxy.java new file mode 100644 index 0000000000000..289ee458a0bed --- /dev/null +++ b/packages/VpnServices/src/com/android/server/vpn/DaemonProxy.java @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2009, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT 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.vpn; + +import android.net.LocalSocket; +import android.net.LocalSocketAddress; +import android.net.vpn.VpnManager; +import android.os.SystemProperties; +import android.util.Log; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Serializable; + +/** + * Proxy to start, stop and interact with a VPN daemon. + * The daemon is expected to accept connection through Unix domain socket. + * When the proxy successfully starts the daemon, it will establish a socket + * connection with the daemon, to both send commands to the daemon and receive + * response and connecting error code from the daemon. + */ +class DaemonProxy implements Serializable { + private static final long serialVersionUID = 1L; + private static final boolean DBG = true; + + private static final int WAITING_TIME = 15; // sec + + private static final String SVC_STATE_CMD_PREFIX = "init.svc."; + private static final String SVC_START_CMD = "ctl.start"; + private static final String SVC_STOP_CMD = "ctl.stop"; + private static final String SVC_STATE_RUNNING = "running"; + private static final String SVC_STATE_STOPPED = "stopped"; + + private static final int END_OF_ARGUMENTS = 255; + + private String mName; + private String mTag; + private transient LocalSocket mControlSocket; + + /** + * Creates a proxy of the specified daemon. + * @param daemonName name of the daemon + */ + DaemonProxy(String daemonName) { + mName = daemonName; + mTag = "SProxy_" + daemonName; + } + + String getName() { + return mName; + } + + void start() throws IOException { + String svc = mName; + + Log.i(mTag, "Start VPN daemon: " + svc); + SystemProperties.set(SVC_START_CMD, svc); + + if (!blockUntil(SVC_STATE_RUNNING, WAITING_TIME)) { + throw new IOException("cannot start service: " + svc); + } else { + mControlSocket = createServiceSocket(); + } + } + + void sendCommand(String ...args) throws IOException { + OutputStream out = getControlSocketOutput(); + for (String arg : args) outputString(out, arg); + out.write(END_OF_ARGUMENTS); + out.flush(); + + int result = getResultFromSocket(true); + if (result != args.length) { + throw new IOException("socket error, result from service: " + + result); + } + } + + // returns 0 if nothing is in the receive buffer + int getResultFromSocket() throws IOException { + return getResultFromSocket(false); + } + + void closeControlSocket() { + if (mControlSocket == null) return; + try { + mControlSocket.close(); + } catch (IOException e) { + Log.w(mTag, "close control socket", e); + } finally { + mControlSocket = null; + } + } + + void stop() { + String svc = mName; + Log.i(mTag, "Stop VPN daemon: " + svc); + SystemProperties.set(SVC_STOP_CMD, svc); + boolean success = blockUntil(SVC_STATE_STOPPED, 5); + if (DBG) Log.d(mTag, "stopping " + svc + ", success? " + success); + } + + boolean isStopped() { + String cmd = SVC_STATE_CMD_PREFIX + mName; + return SVC_STATE_STOPPED.equals(SystemProperties.get(cmd)); + } + + private int getResultFromSocket(boolean blocking) throws IOException { + LocalSocket s = mControlSocket; + if (s == null) return 0; + InputStream in = s.getInputStream(); + if (!blocking && in.available() == 0) return 0; + + int data = in.read(); + Log.i(mTag, "got data from control socket: " + data); + + return data; + } + + private LocalSocket createServiceSocket() throws IOException { + LocalSocket s = new LocalSocket(); + LocalSocketAddress a = new LocalSocketAddress(mName, + LocalSocketAddress.Namespace.RESERVED); + + // try a few times in case the service has not listen()ed + IOException excp = null; + for (int i = 0; i < 10; i++) { + try { + s.connect(a); + return s; + } catch (IOException e) { + if (DBG) Log.d(mTag, "service not yet listen()ing; try again"); + excp = e; + sleep(500); + } + } + throw excp; + } + + private OutputStream getControlSocketOutput() throws IOException { + if (mControlSocket != null) { + return mControlSocket.getOutputStream(); + } else { + throw new IOException("no control socket available"); + } + } + + /** + * Waits for the process to be in the expected state. The method returns + * false if after the specified duration (in seconds), the process is still + * not in the expected state. + */ + private boolean blockUntil(String expectedState, int waitTime) { + String cmd = SVC_STATE_CMD_PREFIX + mName; + int sleepTime = 200; // ms + int n = waitTime * 1000 / sleepTime; + for (int i = 0; i < n; i++) { + if (expectedState.equals(SystemProperties.get(cmd))) { + if (DBG) { + Log.d(mTag, mName + " is " + expectedState + " after " + + (i * sleepTime) + " msec"); + } + break; + } + sleep(sleepTime); + } + return expectedState.equals(SystemProperties.get(cmd)); + } + + private void outputString(OutputStream out, String s) throws IOException { + byte[] bytes = s.getBytes(); + out.write(bytes.length); + out.write(bytes); + out.flush(); + } + + private void sleep(int msec) { + try { + Thread.currentThread().sleep(msec); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } +} diff --git a/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecPskService.java b/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecPskService.java index 7b3ddf85faece..7910f4a7f6450 100644 --- a/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecPskService.java +++ b/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecPskService.java @@ -25,7 +25,7 @@ import java.io.IOException; * connection. */ class L2tpIpsecPskService extends VpnService { - private static final String IPSEC_DAEMON = "racoon"; + private static final String IPSEC = "racoon"; @Override protected void connect(String serverIp, String username, String password) @@ -33,9 +33,9 @@ class L2tpIpsecPskService extends VpnService { L2tpIpsecPskProfile p = getProfile(); // IPSEC - AndroidServiceProxy ipsecService = startService(IPSEC_DAEMON); - ipsecService.sendCommand(serverIp, L2tpService.L2TP_PORT, - p.getPresharedKey()); + DaemonProxy ipsec = startDaemon(IPSEC); + ipsec.sendCommand(serverIp, L2tpService.L2TP_PORT, p.getPresharedKey()); + ipsec.closeControlSocket(); sleep(2000); // 2 seconds @@ -45,4 +45,10 @@ class L2tpIpsecPskService extends VpnService { (p.isSecretEnabled() ? p.getSecretString() : null), username, password); } + + @Override + protected void stopPreviouslyRunDaemons() { + stopDaemon(IPSEC); + stopDaemon(MtpdHelper.MTPD); + } } diff --git a/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java b/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java index e2d4ff49ea56a..13b49521dbc0e 100644 --- a/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java +++ b/packages/VpnServices/src/com/android/server/vpn/L2tpIpsecService.java @@ -25,15 +25,16 @@ import java.io.IOException; * The service that manages the certificate based L2TP-over-IPSec VPN connection. */ class L2tpIpsecService extends VpnService { - private static final String IPSEC_DAEMON = "racoon"; + private static final String IPSEC = "racoon"; @Override protected void connect(String serverIp, String username, String password) throws IOException { // IPSEC - AndroidServiceProxy ipsecService = startService(IPSEC_DAEMON); - ipsecService.sendCommand(serverIp, L2tpService.L2TP_PORT, + DaemonProxy ipsec = startDaemon(IPSEC); + ipsec.sendCommand(serverIp, L2tpService.L2TP_PORT, getUserkeyPath(), getUserCertPath(), getCaCertPath()); + ipsec.closeControlSocket(); sleep(2000); // 2 seconds @@ -45,6 +46,12 @@ class L2tpIpsecService extends VpnService { username, password); } + @Override + protected void stopPreviouslyRunDaemons() { + stopDaemon(IPSEC); + stopDaemon(MtpdHelper.MTPD); + } + private String getCaCertPath() { return CertTool.getInstance().getCaCertificate( getProfile().getCaCertificate()); diff --git a/packages/VpnServices/src/com/android/server/vpn/L2tpService.java b/packages/VpnServices/src/com/android/server/vpn/L2tpService.java index 9273f3557a8ea..d658a366b4353 100644 --- a/packages/VpnServices/src/com/android/server/vpn/L2tpService.java +++ b/packages/VpnServices/src/com/android/server/vpn/L2tpService.java @@ -35,4 +35,9 @@ class L2tpService extends VpnService { (p.isSecretEnabled() ? p.getSecretString() : null), username, password); } + + @Override + protected void stopPreviouslyRunDaemons() { + stopDaemon(MtpdHelper.MTPD); + } } diff --git a/packages/VpnServices/src/com/android/server/vpn/MtpdHelper.java b/packages/VpnServices/src/com/android/server/vpn/MtpdHelper.java index 5fac799b288ac..9078d9bbe4e03 100644 --- a/packages/VpnServices/src/com/android/server/vpn/MtpdHelper.java +++ b/packages/VpnServices/src/com/android/server/vpn/MtpdHelper.java @@ -24,26 +24,33 @@ import java.util.Arrays; * A helper class for sending commands to the MTP daemon (mtpd). */ class MtpdHelper { - private static final String MTPD_SERVICE = "mtpd"; + static final String MTPD = "mtpd"; private static final String VPN_LINKNAME = "vpn"; private static final String PPP_ARGS_SEPARATOR = ""; static void sendCommand(VpnService vpnService, String protocol, String serverIp, String port, String secret, String username, String password) throws IOException { + sendCommand(vpnService, protocol, serverIp, port, secret, username, + password, false); + } + + static void sendCommand(VpnService vpnService, String protocol, + String serverIp, String port, String secret, String username, + String password, boolean encryption) throws IOException { ArrayList args = new ArrayList(); args.addAll(Arrays.asList(protocol, serverIp, port)); if (secret != null) args.add(secret); args.add(PPP_ARGS_SEPARATOR); - addPppArguments(vpnService, args, serverIp, username, password); + addPppArguments(args, serverIp, username, password, encryption); - AndroidServiceProxy mtpd = vpnService.startService(MTPD_SERVICE); + DaemonProxy mtpd = vpnService.startDaemon(MTPD); mtpd.sendCommand(args.toArray(new String[args.size()])); } - private static void addPppArguments(VpnService vpnService, - ArrayList args, String serverIp, String username, - String password) throws IOException { + private static void addPppArguments(ArrayList args, String serverIp, + String username, String password, boolean encryption) + throws IOException { args.addAll(Arrays.asList( "linkname", VPN_LINKNAME, "name", username, @@ -52,6 +59,9 @@ class MtpdHelper { "idle", "1800", "mtu", "1400", "mru", "1400")); + if (encryption) { + args.add("+mppe"); + } } private MtpdHelper() { diff --git a/packages/VpnServices/src/com/android/server/vpn/NormalProcessProxy.java b/packages/VpnServices/src/com/android/server/vpn/NormalProcessProxy.java deleted file mode 100644 index f0bbc3488798a..0000000000000 --- a/packages/VpnServices/src/com/android/server/vpn/NormalProcessProxy.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2009, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.vpn; - -import android.util.Log; - -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.io.IOException; - -/** - * Proxy to perform a command with arguments. - */ -public class NormalProcessProxy extends ProcessProxy { - private Process mProcess; - private String[] mArgs; - private String mTag; - - /** - * Creates a proxy with the arguments. - * @param args the argument list with the first one being the command - */ - public NormalProcessProxy(String ...args) { - if ((args == null) || (args.length == 0)) { - throw new IllegalArgumentException(); - } - mArgs = args; - mTag = "PProxy_" + getName(); - } - - @Override - public String getName() { - return mArgs[0]; - } - - @Override - public synchronized void stop() { - if (isStopped()) return; - getHostThread().interrupt(); - // TODO: not sure how to reliably kill a process - mProcess.destroy(); - setState(ProcessState.STOPPING); - } - - @Override - protected void performTask() throws IOException, InterruptedException { - String[] args = mArgs; - Log.d(mTag, "+++++ Execute: " + getEntireCommand()); - ProcessBuilder pb = new ProcessBuilder(args); - setState(ProcessState.RUNNING); - Process p = mProcess = pb.start(); - BufferedReader reader = new BufferedReader(new InputStreamReader( - p.getInputStream())); - while (true) { - String line = reader.readLine(); - if ((line == null) || isStopping()) break; - Log.d(mTag, line); - } - - Log.d(mTag, "----- p.waitFor(): " + getName()); - p.waitFor(); - Log.d(mTag, "----- Done: " + getName()); - } - - private CharSequence getEntireCommand() { - String[] args = mArgs; - StringBuilder sb = new StringBuilder(args[0]); - for (int i = 1; i < args.length; i++) sb.append(' ').append(args[i]); - return sb; - } -} diff --git a/packages/VpnServices/src/com/android/server/vpn/PptpService.java b/packages/VpnServices/src/com/android/server/vpn/PptpService.java index 01362a55e46b1..d903d1b3e7097 100644 --- a/packages/VpnServices/src/com/android/server/vpn/PptpService.java +++ b/packages/VpnServices/src/com/android/server/vpn/PptpService.java @@ -26,11 +26,17 @@ import java.io.IOException; class PptpService extends VpnService { static final String PPTP_DAEMON = "pptp"; static final String PPTP_PORT = "1723"; + @Override protected void connect(String serverIp, String username, String password) throws IOException { + PptpProfile p = getProfile(); MtpdHelper.sendCommand(this, PPTP_DAEMON, serverIp, PPTP_PORT, null, - username, password); + username, password, p.isEncryptionEnabled()); } + @Override + protected void stopPreviouslyRunDaemons() { + stopDaemon(MtpdHelper.MTPD); + } } diff --git a/packages/VpnServices/src/com/android/server/vpn/ProcessProxy.java b/packages/VpnServices/src/com/android/server/vpn/ProcessProxy.java deleted file mode 100644 index 50fbf4b87822e..0000000000000 --- a/packages/VpnServices/src/com/android/server/vpn/ProcessProxy.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (C) 2009, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.vpn; - -import android.os.ConditionVariable; - -import java.io.IOException; - -/** - * A proxy class that spawns a process to accomplish a certain task. - */ -public abstract class ProcessProxy { - /** - * Defines the interface to call back when the process is finished or an - * error occurs during execution. - */ - public static interface Callback { - /** - * Called when the process is finished. - * @param proxy the proxy that hosts the process - */ - void done(ProcessProxy proxy); - - /** - * Called when some error occurs. - * @param proxy the proxy that hosts the process - */ - void error(ProcessProxy proxy, Throwable error); - } - - protected enum ProcessState { - STOPPED, STARTING, RUNNING, STOPPING, ERROR - } - - private ProcessState mState = ProcessState.STOPPED; - private ConditionVariable mLock = new ConditionVariable(); - private Thread mThread; - - /** - * Returns the name of the process. - */ - public abstract String getName(); - - /** - * Starts the process with a callback. - * @param callback the callback to get notified when the process is finished - * or an error occurs during execution - * @throws IOException when the process is already running or failed to - * start - */ - public synchronized void start(final Callback callback) throws IOException { - if (!isStopped()) { - throw new IOException("Process is already running: " + this); - } - mLock.close(); - setState(ProcessState.STARTING); - Thread thread = new Thread(new Runnable() { - public void run() { - try { - performTask(); - setState(ProcessState.STOPPED); - mLock.open(); - if (callback != null) callback.done(ProcessProxy.this); - } catch (Throwable e) { - setState(ProcessState.ERROR); - if (callback != null) callback.error(ProcessProxy.this, e); - } finally { - mThread = null; - } - } - }); - thread.setPriority(Thread.MIN_PRIORITY); - thread.start(); - mThread = thread; - if (!waitUntilRunning()) { - throw new IOException("Failed to start the process: " + this); - } - } - - /** - * Starts the process. - * @throws IOException when the process is already running or failed to - * start - */ - public synchronized void start() throws IOException { - start(null); - if (!waitUntilDone()) { - throw new IOException("Failed to complete the process: " + this); - } - } - - /** - * Returns the thread that hosts the process. - */ - public Thread getHostThread() { - return mThread; - } - - /** - * Blocks the current thread until the hosted process is finished. - * - * @return true if the process is finished normally; false if an error - * occurs - */ - public boolean waitUntilDone() { - while (!mLock.block(1000)) { - if (isStopped() || isInError()) break; - } - return isStopped(); - } - - /** - * Blocks the current thread until the hosted process is running. - * - * @return true if the process is running normally; false if the process - * is in another state - */ - private boolean waitUntilRunning() { - for (;;) { - if (!isStarting()) break; - } - return isRunning(); - } - - /** - * Stops and destroys the process. - */ - public abstract void stop(); - - /** - * Checks whether the process is finished. - * @return true if the process is stopped - */ - public boolean isStopped() { - return (mState == ProcessState.STOPPED); - } - - /** - * Checks whether the process is being stopped. - * @return true if the process is being stopped - */ - public boolean isStopping() { - return (mState == ProcessState.STOPPING); - } - - /** - * Checks whether the process is being started. - * @return true if the process is being started - */ - public boolean isStarting() { - return (mState == ProcessState.STARTING); - } - - /** - * Checks whether the process is running. - * @return true if the process is running - */ - public boolean isRunning() { - return (mState == ProcessState.RUNNING); - } - - /** - * Checks whether some error has occurred and the process is stopped. - * @return true if some error has occurred and the process is stopped - */ - public boolean isInError() { - return (mState == ProcessState.ERROR); - } - - /** - * Performs the actual task. Subclasses must make sure that the method - * is blocked until the task is done or an error occurs. - */ - protected abstract void performTask() - throws IOException, InterruptedException; - - /** - * Sets the process state. - * @param state the new state to be in - */ - protected void setState(ProcessState state) { - mState = state; - } - - /** - * Makes the current thread sleep for the specified time. - * @param msec time to sleep in miliseconds - */ - protected void sleep(int msec) { - try { - Thread.currentThread().sleep(msec); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } -} diff --git a/packages/VpnServices/src/com/android/server/vpn/VpnService.java b/packages/VpnServices/src/com/android/server/vpn/VpnService.java index 87bd780ff8b48..b107c7dcb1916 100644 --- a/packages/VpnServices/src/com/android/server/vpn/VpnService.java +++ b/packages/VpnServices/src/com/android/server/vpn/VpnService.java @@ -28,7 +28,11 @@ import android.text.TextUtils; import android.util.Log; import java.io.IOException; +import java.io.Serializable; +import java.net.DatagramSocket; +import java.net.Socket; import java.net.InetAddress; +import java.net.NetworkInterface; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; @@ -36,7 +40,9 @@ import java.util.List; /** * The service base class for managing a type of VPN connection. */ -abstract class VpnService { +abstract class VpnService implements Serializable { + protected static final long serialVersionUID = 1L; + private static final boolean DBG = true; private static final int NOTIFICATION_ID = 1; private static final String DNS1 = "net.dns1"; @@ -50,29 +56,34 @@ abstract class VpnService { private static final String REMOTE_IP = "net.ipremote"; private static final String DNS_DOMAIN_SUFFICES = "net.dns.search"; + private static final int CHALLENGE_ERROR_CODE = 5; + private static final int REMOTE_HUNG_UP_ERROR_CODE = 7; + private static final int AUTH_ERROR_CODE = 51; + private final String TAG = VpnService.class.getSimpleName(); + // FIXME: profile is only needed in connecting phase, so we can just save + // the profile name and service class name for recovery E mProfile; - VpnServiceBinder mContext; + transient VpnServiceBinder mContext; private VpnState mState = VpnState.IDLE; - private boolean mInError; - private VpnConnectingError mError; + private Throwable mError; // connection settings private String mOriginalDns1; private String mOriginalDns2; - private String mVpnDns1 = ""; - private String mVpnDns2 = ""; private String mOriginalDomainSuffices; + private String mLocalIp; + private String mLocalIf; private long mStartTime; // VPN connection start time - // for helping managing multiple Android services - private ServiceHelper mServiceHelper = new ServiceHelper(); + // for helping managing multiple daemons + private DaemonHelper mDaemonHelper = new DaemonHelper(); // for helping showing, updating notification - private NotificationHelper mNotification = new NotificationHelper(); + private transient NotificationHelper mNotification; /** * Establishes a VPN connection with the specified username and password. @@ -80,19 +91,21 @@ abstract class VpnService { protected abstract void connect(String serverIp, String username, String password) throws IOException; + protected abstract void stopPreviouslyRunDaemons(); + /** - * Tears down the VPN connection. The base class simply terminates all the - * Android services. A subclass may need to do some clean-up before that. + * Starts a VPN daemon. */ - protected void disconnect() { + protected DaemonProxy startDaemon(String daemonName) + throws IOException { + return mDaemonHelper.startDaemon(daemonName); } /** - * Starts an Android service defined in init.rc. + * Stops a VPN daemon. */ - protected AndroidServiceProxy startService(String serviceName) - throws IOException { - return mServiceHelper.startService(serviceName); + protected void stopDaemon(String daemonName) { + new DaemonProxy(daemonName).stop(); } /** @@ -109,31 +122,23 @@ abstract class VpnService { return InetAddress.getByName(hostName).getHostAddress(); } - /** - * Sets the system property. The method is blocked until the value is - * settled in. - * @param name the name of the property - * @param value the value of the property - * @throws IOException if it fails to set the property within 2 seconds - */ - protected void setSystemProperty(String name, String value) - throws IOException { - SystemProperties.set(name, value); - for (int i = 0; i < 5; i++) { - String v = SystemProperties.get(name); - if (v.equals(value)) { - return; - } else { - Log.d(TAG, "sys_prop: wait for " + name + " to settle in"); - sleep(400); - } - } - throw new IOException("Failed to set system property: " + name); + void setContext(VpnServiceBinder context, E profile) { + mProfile = profile; + recover(context); } - void setContext(VpnServiceBinder context, E profile) { + void recover(VpnServiceBinder context) { mContext = context; - mProfile = profile; + mNotification = new NotificationHelper(); + + if (VpnState.CONNECTED.equals(mState)) { + Log.i("VpnService", " recovered: " + mProfile.getName()); + new Thread(new Runnable() { + public void run() { + enterConnectivityLoop(); + } + }).start(); + } } VpnState getState() { @@ -145,189 +150,161 @@ abstract class VpnService { mState = VpnState.CONNECTING; broadcastConnectivity(VpnState.CONNECTING); + stopPreviouslyRunDaemons(); String serverIp = getIp(getProfile().getServerName()); - + saveLocalIpAndInterface(serverIp); onBeforeConnect(); connect(serverIp, username, password); waitUntilConnectedOrTimedout(); return true; } catch (Throwable e) { - Log.e(TAG, "onConnect()", e); - mError = newConnectingError(e); - onError(); + onError(e); return false; } } - synchronized void onDisconnect(boolean cleanUpServices) { + synchronized void onDisconnect() { try { - Log.d(TAG, " disconnecting VPN..."); + Log.i(TAG, "disconnecting VPN..."); mState = VpnState.DISCONNECTING; broadcastConnectivity(VpnState.DISCONNECTING); mNotification.showDisconnect(); - // subclass implementation - if (cleanUpServices) disconnect(); - - mServiceHelper.stop(); + mDaemonHelper.stopAll(); } catch (Throwable e) { Log.e(TAG, "onDisconnect()", e); + } finally { onFinalCleanUp(); } } - synchronized void onError() { + private void onError(Throwable error) { // error may occur during or after connection setup // and it may be due to one or all services gone - mInError = true; - switch (mState) { - case CONNECTED: - onDisconnect(true); - break; + if (mError != null) { + Log.w(TAG, " multiple errors occur, record the last one: " + + error); + } + Log.e(TAG, "onError()", error); + mError = error; + onDisconnect(); + } - case CONNECTING: - onDisconnect(false); - break; + private void onError(int errorCode) { + onError(new VpnConnectingError(errorCode)); + } + + + private void onBeforeConnect() throws IOException { + mNotification.disableNotification(); + + SystemProperties.set(VPN_DNS1, ""); + SystemProperties.set(VPN_DNS2, ""); + SystemProperties.set(VPN_STATUS, VPN_IS_DOWN); + if (DBG) { + Log.d(TAG, " VPN UP: " + SystemProperties.get(VPN_STATUS)); } } - private void onBeforeConnect() { - mNotification.disableNotification(); - - SystemProperties.set(VPN_DNS1, "-"); - SystemProperties.set(VPN_DNS2, "-"); - SystemProperties.set(VPN_STATUS, VPN_IS_DOWN); - Log.d(TAG, " VPN UP: " + SystemProperties.get(VPN_STATUS)); - } - - private void waitUntilConnectedOrTimedout() { - // Run this in the background thread to not block UI - new Thread(new Runnable() { - public void run() { - sleep(2000); // 2 seconds - for (int i = 0; i < 60; i++) { - if (VPN_IS_UP.equals(SystemProperties.get(VPN_STATUS))) { - onConnected(); - return; - } else if (mState != VpnState.CONNECTING) { - break; - } - sleep(500); // 0.5 second - } - - synchronized (VpnService.this) { - if (mState == VpnState.CONNECTING) { - Log.d(TAG, " connecting timed out !!"); - mError = newConnectingError( - new IOException("Connecting timed out")); - onError(); - } - } + private void waitUntilConnectedOrTimedout() throws IOException { + sleep(2000); // 2 seconds + for (int i = 0; i < 60; i++) { + if (mState != VpnState.CONNECTING) { + break; + } else if (VPN_IS_UP.equals( + SystemProperties.get(VPN_STATUS))) { + onConnected(); + return; + } else if (mDaemonHelper.anySocketError()) { + return; } - }).start(); + sleep(500); // 0.5 second + } + + synchronized (VpnService.this) { + if (mState == VpnState.CONNECTING) { + onError(new IOException("Connecting timed out")); + } + } } - private synchronized void onConnected() { - Log.d(TAG, "onConnected()"); + private synchronized void onConnected() throws IOException { + if (DBG) Log.d(TAG, "onConnected()"); - saveVpnDnsProperties(); + mDaemonHelper.closeSockets(); + saveOriginalDns(); saveAndSetDomainSuffices(); - startConnectivityMonitor(); mState = VpnState.CONNECTED; + mStartTime = System.currentTimeMillis(); + + // set DNS after saving the states in case the process gets killed + // before states are saved + saveSelf(); + setVpnDns(); broadcastConnectivity(VpnState.CONNECTED); + + enterConnectivityLoop(); + } + + private void saveSelf() throws IOException { + mContext.saveStates(); } private synchronized void onFinalCleanUp() { - Log.d(TAG, "onFinalCleanUp()"); + if (DBG) Log.d(TAG, "onFinalCleanUp()"); if (mState == VpnState.IDLE) return; // keep the notification when error occurs - if (!mInError) mNotification.disableNotification(); + if (!anyError()) mNotification.disableNotification(); - restoreOriginalDnsProperties(); + restoreOriginalDns(); restoreOriginalDomainSuffices(); mState = VpnState.IDLE; broadcastConnectivity(VpnState.IDLE); // stop the service itself + mContext.removeStates(); mContext.stopSelf(); } - private VpnConnectingError newConnectingError(Throwable e) { - return new VpnConnectingError( - (e instanceof UnknownHostException) - ? VpnManager.VPN_ERROR_UNKNOWN_SERVER - : VpnManager.VPN_ERROR_CONNECTION_FAILED); + private boolean anyError() { + return (mError != null); } - private synchronized void onOneServiceGone() { - switch (mState) { - case IDLE: - case DISCONNECTING: - break; - - default: - onError(); - } - } - - private synchronized void onAllServicesGone() { - switch (mState) { - case IDLE: - break; - - case DISCONNECTING: - // daemons are gone; now clean up everything - onFinalCleanUp(); - break; - - default: - onError(); - } - } - - private void restoreOriginalDnsProperties() { + private void restoreOriginalDns() { // restore only if they are not overridden - if (mVpnDns1.equals(SystemProperties.get(DNS1))) { - Log.d(TAG, String.format("restore original dns prop: %s --> %s", + String vpnDns1 = SystemProperties.get(VPN_DNS1); + if (vpnDns1.equals(SystemProperties.get(DNS1))) { + Log.i(TAG, String.format("restore original dns prop: %s --> %s", SystemProperties.get(DNS1), mOriginalDns1)); - Log.d(TAG, String.format("restore original dns prop: %s --> %s", + Log.i(TAG, String.format("restore original dns prop: %s --> %s", SystemProperties.get(DNS2), mOriginalDns2)); SystemProperties.set(DNS1, mOriginalDns1); SystemProperties.set(DNS2, mOriginalDns2); } } - private void saveVpnDnsProperties() { - mOriginalDns1 = mOriginalDns2 = ""; - for (int i = 0; i < 5; i++) { - mVpnDns1 = SystemProperties.get(VPN_DNS1); - mVpnDns2 = SystemProperties.get(VPN_DNS2); - if (mOriginalDns1.equals(mVpnDns1)) { - Log.d(TAG, "wait for vpn dns to settle in..." + i); - sleep(200); - } else { - mOriginalDns1 = SystemProperties.get(DNS1); - mOriginalDns2 = SystemProperties.get(DNS2); - SystemProperties.set(DNS1, mVpnDns1); - SystemProperties.set(DNS2, mVpnDns2); - Log.d(TAG, String.format("save original dns prop: %s, %s", - mOriginalDns1, mOriginalDns2)); - Log.d(TAG, String.format("set vpn dns prop: %s, %s", - mVpnDns1, mVpnDns2)); - return; - } - } - Log.d(TAG, "saveVpnDnsProperties(): DNS not updated??"); - mOriginalDns1 = mVpnDns1 = SystemProperties.get(DNS1); - mOriginalDns2 = mVpnDns2 = SystemProperties.get(DNS2); + private void saveOriginalDns() { + mOriginalDns1 = SystemProperties.get(DNS1); + mOriginalDns2 = SystemProperties.get(DNS2); + Log.i(TAG, String.format("save original dns prop: %s, %s", + mOriginalDns1, mOriginalDns2)); + } + + private void setVpnDns() { + String vpnDns1 = SystemProperties.get(VPN_DNS1); + String vpnDns2 = SystemProperties.get(VPN_DNS2); + SystemProperties.set(DNS1, vpnDns1); + SystemProperties.set(DNS2, vpnDns2); + Log.i(TAG, String.format("set vpn dns prop: %s, %s", + vpnDns1, vpnDns2)); } private void saveAndSetDomainSuffices() { mOriginalDomainSuffices = SystemProperties.get(DNS_DOMAIN_SUFFICES); - Log.d(TAG, "save original dns search: " + mOriginalDomainSuffices); + Log.i(TAG, "save original suffices: " + mOriginalDomainSuffices); String list = mProfile.getDomainSuffices(); if (!TextUtils.isEmpty(list)) { SystemProperties.set(DNS_DOMAIN_SUFFICES, list); @@ -335,52 +312,98 @@ abstract class VpnService { } private void restoreOriginalDomainSuffices() { - Log.d(TAG, "restore original dns search --> " + mOriginalDomainSuffices); + Log.i(TAG, "restore original suffices --> " + mOriginalDomainSuffices); SystemProperties.set(DNS_DOMAIN_SUFFICES, mOriginalDomainSuffices); } private void broadcastConnectivity(VpnState s) { VpnManager m = new VpnManager(mContext); - if ((s == VpnState.IDLE) && (mError != null)) { - m.broadcastConnectivity(mProfile.getName(), s, - mError.getErrorCode()); + Throwable err = mError; + if ((s == VpnState.IDLE) && (err != null)) { + if (err instanceof UnknownHostException) { + m.broadcastConnectivity(mProfile.getName(), s, + VpnManager.VPN_ERROR_UNKNOWN_SERVER); + } else if (err instanceof VpnConnectingError) { + m.broadcastConnectivity(mProfile.getName(), s, + ((VpnConnectingError) err).getErrorCode()); + } else { + m.broadcastConnectivity(mProfile.getName(), s, + VpnManager.VPN_ERROR_CONNECTION_FAILED); + } } else { m.broadcastConnectivity(mProfile.getName(), s); } } - private void startConnectivityMonitor() { - mStartTime = System.currentTimeMillis(); - - new Thread(new Runnable() { - public void run() { - Log.d(TAG, " +++++ connectivity monitor running"); - try { - for (;;) { - synchronized (VpnService.this) { - if (mState != VpnState.CONNECTED) break; - mNotification.update(); - checkConnectivity(); - VpnService.this.wait(1000); // 1 second - } + private void enterConnectivityLoop() { + Log.i(TAG, "VPN connectivity monitor running"); + try { + for (;;) { + synchronized (VpnService.this) { + if (mState != VpnState.CONNECTED || !checkConnectivity()) { + break; } - } catch (InterruptedException e) { - Log.e(TAG, "connectivity monitor", e); + mNotification.update(); + checkDns(); + VpnService.this.wait(1000); // 1 second } - Log.d(TAG, " ----- connectivity monitor stopped"); } - }).start(); + } catch (InterruptedException e) { + onError(e); + } + Log.i(TAG, "VPN connectivity monitor stopped"); } - private void checkConnectivity() { - checkDnsProperties(); + private void saveLocalIpAndInterface(String serverIp) throws IOException { + DatagramSocket s = new DatagramSocket(); + int port = 80; // arbitrary + s.connect(InetAddress.getByName(serverIp), port); + InetAddress localIp = s.getLocalAddress(); + mLocalIp = localIp.getHostAddress(); + NetworkInterface localIf = NetworkInterface.getByInetAddress(localIp); + mLocalIf = (localIf == null) ? null : localIf.getName(); + if (TextUtils.isEmpty(mLocalIf)) { + throw new IOException("Local interface is empty!"); + } + if (DBG) { + Log.d(TAG, " Local IP: " + mLocalIp + ", if: " + mLocalIf); + } } - private void checkDnsProperties() { + // returns false if vpn connectivity is broken + private boolean checkConnectivity() { + if (mDaemonHelper.anyDaemonStopped() || isLocalIpChanged()) { + onDisconnect(); + return false; + } else { + return true; + } + } + + private void checkDns() { String dns1 = SystemProperties.get(DNS1); - if (!mVpnDns1.equals(dns1)) { - Log.w(TAG, " dns being overridden by: " + dns1); - onError(); + String vpnDns1 = SystemProperties.get(VPN_DNS1); + if (!dns1.equals(vpnDns1) && dns1.equals(mOriginalDns1)) { + // dhcp expires? + setVpnDns(); + } + } + + private boolean isLocalIpChanged() { + try { + InetAddress localIp = InetAddress.getByName(mLocalIp); + NetworkInterface localIf = + NetworkInterface.getByInetAddress(localIp); + if (localIf == null || !mLocalIf.equals(localIf.getName())) { + Log.w(TAG, " local If changed from " + mLocalIf + + " to " + localIf); + return true; + } else { + return false; + } + } catch (IOException e) { + Log.w(TAG, "isLocalIpChanged()", e); + return true; } } @@ -391,56 +414,72 @@ abstract class VpnService { } } - private InetAddress toInetAddress(int addr) throws IOException { - byte[] aa = new byte[4]; - for (int i= 0; i < aa.length; i++) { - aa[i] = (byte) (addr & 0x0FF); - addr >>= 8; - } - return InetAddress.getByAddress(aa); - } + private class DaemonHelper implements Serializable { + private List mDaemonList = + new ArrayList(); - private class ServiceHelper implements ProcessProxy.Callback { - private List mServiceList = - new ArrayList(); - - // starts an Android service - AndroidServiceProxy startService(String serviceName) + synchronized DaemonProxy startDaemon(String daemonName) throws IOException { - AndroidServiceProxy service = new AndroidServiceProxy(serviceName); - mServiceList.add(service); - service.start(this); - return service; + DaemonProxy daemon = new DaemonProxy(daemonName); + mDaemonList.add(daemon); + daemon.start(); + return daemon; } - // stops all the Android services - void stop() { - if (mServiceList.isEmpty()) { + synchronized void stopAll() { + if (mDaemonList.isEmpty()) { onFinalCleanUp(); } else { - for (AndroidServiceProxy s : mServiceList) s.stop(); + for (DaemonProxy s : mDaemonList) s.stop(); } } - //@Override - public void done(ProcessProxy p) { - Log.d(TAG, "service done: " + p.getName()); - commonCallback((AndroidServiceProxy) p); + synchronized void closeSockets() { + for (DaemonProxy s : mDaemonList) s.closeControlSocket(); } - //@Override - public void error(ProcessProxy p, Throwable e) { - Log.e(TAG, "service error: " + p.getName(), e); - if (e instanceof VpnConnectingError) { - mError = (VpnConnectingError) e; + synchronized boolean anyDaemonStopped() { + for (DaemonProxy s : mDaemonList) { + if (s.isStopped()) { + Log.w(TAG, " VPN daemon gone: " + s.getName()); + return true; + } } - commonCallback((AndroidServiceProxy) p); + return false; } - private void commonCallback(AndroidServiceProxy service) { - mServiceList.remove(service); - onOneServiceGone(); - if (mServiceList.isEmpty()) onAllServicesGone(); + private int getResultFromSocket(DaemonProxy s) { + try { + return s.getResultFromSocket(); + } catch (IOException e) { + return -1; + } + } + + synchronized boolean anySocketError() { + for (DaemonProxy s : mDaemonList) { + switch (getResultFromSocket(s)) { + case 0: + continue; + + case AUTH_ERROR_CODE: + onError(VpnManager.VPN_ERROR_AUTH); + return true; + + case CHALLENGE_ERROR_CODE: + onError(VpnManager.VPN_ERROR_CHALLENGE); + return true; + + case REMOTE_HUNG_UP_ERROR_CODE: + onError(VpnManager.VPN_ERROR_REMOTE_HUNG_UP); + return true; + + default: + onError(VpnManager.VPN_ERROR_CONNECTION_FAILED); + return true; + } + } + return false; } } diff --git a/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java b/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java index 32b8e51f278da..4892a7b57b6a0 100644 --- a/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java +++ b/packages/VpnServices/src/com/android/server/vpn/VpnServiceBinder.java @@ -27,15 +27,25 @@ import android.net.vpn.VpnManager; import android.net.vpn.VpnProfile; import android.net.vpn.VpnState; import android.os.IBinder; +import android.util.Log; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; /** * The service class for managing a VPN connection. It implements the * {@link IVpnService} binder interface. */ public class VpnServiceBinder extends Service { - private final String TAG = VpnServiceBinder.class.getSimpleName(); + private static final String TAG = VpnServiceBinder.class.getSimpleName(); + private static final boolean DBG = true; + + private static final String STATES_FILE_PATH = "/data/misc/vpn/.states"; // The actual implementation is delegated to the VpnService class. private VpnService mService; @@ -46,7 +56,7 @@ public class VpnServiceBinder extends Service { } public void disconnect() { - if (mService != null) mService.onDisconnect(true); + VpnServiceBinder.this.disconnect(); } public void checkStatus(VpnProfile p) { @@ -54,21 +64,61 @@ public class VpnServiceBinder extends Service { } }; - public void onStart (Intent intent, int startId) { - super.onStart(intent, startId); - setForeground(true); - android.util.Log.d("VpnServiceBinder", "becomes a foreground service"); + @Override + public void onCreate() { + super.onCreate(); + checkSavedStates(); } + + @Override + public void onStart(Intent intent, int startId) { + super.onStart(intent, startId); + } + + @Override public IBinder onBind(Intent intent) { return mBinder; } - private synchronized boolean connect( - VpnProfile p, String username, String password) { + void saveStates() throws IOException { + if (DBG) Log.d("VpnServiceBinder", " saving states"); + ObjectOutputStream oos = + new ObjectOutputStream(new FileOutputStream(STATES_FILE_PATH)); + oos.writeObject(mService); + oos.close(); + } + + void removeStates() { + try { + new File(STATES_FILE_PATH).delete(); + } catch (Throwable e) { + if (DBG) Log.d("VpnServiceBinder", " remove states: " + e); + } + } + + private synchronized boolean connect(final VpnProfile p, + final String username, final String password) { if (mService != null) return false; - mService = createService(p); - return mService.onConnect(username, password); + final VpnService s = mService = createService(p); + + new Thread(new Runnable() { + public void run() { + s.onConnect(username, password); + } + }).start(); + return true; + } + + private synchronized void disconnect() { + if (mService == null) return; + final VpnService s = mService; + + new Thread(new Runnable() { + public void run() { + s.onDisconnect(); + } + }).start(); } private synchronized void checkStatus(VpnProfile p) { @@ -80,6 +130,21 @@ public class VpnServiceBinder extends Service { } } + private void checkSavedStates() { + try { + ObjectInputStream ois = new ObjectInputStream(new FileInputStream( + STATES_FILE_PATH)); + mService = (VpnService) ois.readObject(); + mService.recover(this); + ois.close(); + } catch (FileNotFoundException e) { + // do nothing + } catch (Throwable e) { + Log.i("VpnServiceBinder", "recovery error, remove states: " + e); + removeStates(); + } + } + private VpnService createService(VpnProfile p) { switch (p.getType()) { case L2TP: diff --git a/services/java/com/android/server/AccessibilityManagerService.java b/services/java/com/android/server/AccessibilityManagerService.java index c205fc03ac4f4..55007ba701751 100644 --- a/services/java/com/android/server/AccessibilityManagerService.java +++ b/services/java/com/android/server/AccessibilityManagerService.java @@ -323,15 +323,22 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub */ private void notifyAccessibilityServicesDelayedLocked(AccessibilityEvent event, boolean isDefault) { - for (int i = 0, count = mServices.size(); i < count; i++) { - Service service = mServices.get(i); + try { + for (int i = 0, count = mServices.size(); i < count; i++) { + Service service = mServices.get(i); - if (service.mIsDefault == isDefault) { - if (canDispathEventLocked(service, event, mHandledFeedbackTypes)) { - mHandledFeedbackTypes |= service.mFeedbackType; - notifyAccessibilityServiceDelayedLocked(service, event); + if (service.mIsDefault == isDefault) { + if (canDispathEventLocked(service, event, mHandledFeedbackTypes)) { + mHandledFeedbackTypes |= service.mFeedbackType; + notifyAccessibilityServiceDelayedLocked(service, event); + } } } + } catch (IndexOutOfBoundsException oobe) { + // An out of bounds exception can happen if services are going away + // as the for loop is running. If that happens, just bail because + // there are no more services to notify. + return; } } @@ -368,6 +375,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub * @param event The event. */ private void tryRecycleLocked(AccessibilityEvent event) { + if (event == null) { + return; + } int eventType = event.getEventType(); List services = mServices; @@ -378,7 +388,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub return; } } - event.recycle(); } diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index 38fb7c9cd9d85..aac7124b0c4f6 100644 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -90,7 +90,7 @@ class NotificationManagerService extends INotificationManager.Stub private NotificationRecord mSoundNotification; private AsyncPlayer mSound; private boolean mSystemReady; - private int mDisabledNotifications = StatusBarManager.DISABLE_NOTIFICATION_ALERTS; + private int mDisabledNotifications; private NotificationRecord mVibrateNotification; private Vibrator mVibrator = new Vibrator(); @@ -368,6 +368,15 @@ class NotificationManagerService extends INotificationManager.Stub mStatusBarService = statusBar; statusBar.setNotificationCallbacks(mNotificationCallbacks); + // Don't start allowing notifications until the setup wizard has run once. + // After that, including subsequent boots, init with notifications turned on. + // This works on the first boot because the setup wizard will toggle this + // flag at least once and we'll go back to 0 after that. + if (0 == Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.DEVICE_PROVISIONED, 0)) { + mDisabledNotifications = StatusBarManager.DISABLE_NOTIFICATION_ALERTS; + } + // register for battery changed notifications IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_BATTERY_CHANGED); @@ -1049,6 +1058,8 @@ class NotificationManagerService extends INotificationManager.Stub pw.println(" mSoundNotification=" + mSoundNotification); pw.println(" mSound=" + mSound); pw.println(" mVibrateNotification=" + mVibrateNotification); + pw.println(" mDisabledNotifications=0x" + Integer.toHexString(mDisabledNotifications)); + pw.println(" mSystemReady=" + mSystemReady); } } } diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index ee53274ec1c1e..bd79d1dd3fa15 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -60,7 +60,6 @@ import android.net.Uri; import android.os.Binder; import android.os.Build; import android.os.Bundle; -import android.os.Debug; import android.os.HandlerThread; import android.os.Parcel; import android.os.RemoteException; @@ -495,7 +494,7 @@ class PackageManagerService extends IPackageManager.Stub { mDrmAppInstallObserver = new AppDirObserver( mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false); mDrmAppInstallObserver.startWatching(); - scanDirLI(mDrmAppPrivateInstallDir, 0, scanMode); + scanDirLI(mDrmAppPrivateInstallDir, 0, scanMode | SCAN_FORWARD_LOCKED); EventLog.writeEvent(LOG_BOOT_PROGRESS_PMS_SCAN_END, SystemClock.uptimeMillis()); @@ -1764,7 +1763,12 @@ class PackageManagerService extends IPackageManager.Stub { int i; for (i=0; i(dis.grantedPermissions); + p.loadedPermissions = new HashSet(dis.loadedPermissions); + // Clone component info + p.disabledComponents = new HashSet(dis.disabledComponents); + p.enabledComponents = new HashSet(dis.enabledComponents); + // Add new setting to list of user ids + addUserIdLP(p.userId, p, name); + } else { + // Assign new user id + p.userId = newUserIdLP(p); + } } else { p.userId = FIRST_APPLICATION_UID; } @@ -5887,15 +5952,39 @@ class PackageManagerService extends IPackageManager.Stub { if (add) { // Finish adding new package by adding it and updating shared // user preferences - insertPackageSettingLP(p, name, sharedUser); + addPackageSettingLP(p, name, sharedUser); } } return p; } - + + private void insertPackageSettingLP(PackageSetting p, PackageParser.Package pkg, + File codePath, File resourcePath) { + p.pkg = pkg; + // Update code path if needed + if (!codePath.toString().equalsIgnoreCase(p.codePathString)) { + Log.w(TAG, "Code path for pkg : " + p.pkg.packageName + + " changing form " + p.codePathString + " to " + codePath); + p.codePath = codePath; + p.codePathString = codePath.toString(); + } + //Update resource path if needed + if (!resourcePath.toString().equalsIgnoreCase(p.resourcePathString)) { + Log.w(TAG, "Resource path for pkg : " + p.pkg.packageName + + " changing form " + p.resourcePathString + " to " + resourcePath); + p.resourcePath = resourcePath; + p.resourcePathString = resourcePath.toString(); + } + // Update version code if needed + if (pkg.mVersionCode != p.versionCode) { + p.versionCode = pkg.mVersionCode; + } + addPackageSettingLP(p, pkg.packageName, p.sharedUser); + } + // Utility method that adds a PackageSetting to mPackages and // completes updating the shared user attributes - private void insertPackageSettingLP(PackageSetting p, String name, + private void addPackageSettingLP(PackageSetting p, String name, SharedUserSetting sharedUser) { mPackages.put(name, p); if (sharedUser != null) { @@ -5988,7 +6077,7 @@ class PackageManagerService extends IPackageManager.Stub { } if (mUserIds.get(index) != null) { reportSettingsProblem(Log.ERROR, - "Adding duplicate shared id: " + uid + "Adding duplicate user id: " + uid + " name=" + name); return false; } diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java index b4754b6d48e96..394ed3ac39453 100644 --- a/services/java/com/android/server/WifiService.java +++ b/services/java/com/android/server/WifiService.java @@ -1075,6 +1075,17 @@ public class WifiService extends IWifiManager.Stub { break setVariables; } + if ((config.phase2 != null) && !WifiNative.setNetworkVariableCommand( + netId, + WifiConfiguration.phase2VarName, + config.phase2)) { + if (DBG) { + Log.d(TAG, config.SSID + ": failed to set phase2: "+ + config.phase2); + } + break setVariables; + } + if ((config.identity != null) && !WifiNative.setNetworkVariableCommand( netId, WifiConfiguration.identityVarName, diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index 0be841790d871..5a02c4d3330db 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -6837,6 +6837,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo pw.print(mOrientationChanging); pw.print(" mAppFreezing="); pw.println(mAppFreezing); } + if (mHScale != 1 || mVScale != 1) { + pw.print(prefix); pw.print("mHScale="); pw.print(mHScale); + pw.print(" mVScale="); pw.println(mVScale); + } } @Override @@ -8175,7 +8179,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo // This has changed the visibility of windows, so perform // a new layout to get them all up-to-date. mLayoutNeeded = true; - moveInputMethodWindowsIfNeededLocked(true); + if (!moveInputMethodWindowsIfNeededLocked(true)) { + assignLayersLocked(); + } performLayoutLockedInner(); updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES); diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index d9c40ec602f6b..51ee41afb56e8 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -184,8 +184,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050; // The flags that are set for all calls we make to the package manager. - static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES - | PackageManager.GET_SUPPORTS_DENSITIES; + static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES; private static final String SYSTEM_SECURE = "ro.secure"; @@ -723,6 +722,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen */ Configuration mConfiguration = new Configuration(); + /** + * Hardware-reported OpenGLES version. + */ + final int GL_ES_VERSION; + /** * List of initialization arguments to pass to all processes when binding applications to them. * For example, references to the commonly used services. @@ -1396,6 +1400,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen mUsageStatsService = new UsageStatsService( new File( systemDir, "usagestats").toString()); + GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version", + ConfigurationInfo.GL_ES_VERSION_UNDEFINED); + mConfiguration.makeDefault(); mProcessStats.init(); @@ -4729,6 +4736,57 @@ public final class ActivityManagerService extends ActivityManagerNative implemen Binder.restoreCallingIdentity(callingId); } } + + /* + * The pkg name and uid have to be specified. + * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int) + */ + public void killApplicationWithUid(String pkg, int uid) { + if (pkg == null) { + return; + } + // Make sure the uid is valid. + if (uid < 0) { + Log.w(TAG, "Invalid uid specified for pkg : " + pkg); + return; + } + int callerUid = Binder.getCallingUid(); + // Only the system server can kill an application + if (callerUid == Process.SYSTEM_UID) { + uninstallPackageLocked(pkg, uid, false); + } else { + throw new SecurityException(callerUid + " cannot kill pkg: " + + pkg); + } + } + + public void closeSystemDialogs(String reason) { + Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); + if (reason != null) { + intent.putExtra("reason", reason); + } + + final int uid = Binder.getCallingUid(); + final long origId = Binder.clearCallingIdentity(); + synchronized (this) { + int i = mWatchers.beginBroadcast(); + while (i > 0) { + i--; + IActivityWatcher w = mWatchers.getBroadcastItem(i); + if (w != null) { + try { + w.closingSystemDialogs(reason); + } catch (RemoteException e) { + } + } + } + mWatchers.finishBroadcast(); + + broadcastIntentLocked(null, null, intent, null, + null, 0, null, null, null, false, false, -1, uid); + } + Binder.restoreCallingIdentity(origId); + } private void restartPackageLocked(final String packageName, int uid) { uninstallPackageLocked(packageName, uid, false); @@ -11847,6 +11905,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) { config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD; } + config.reqGlEsVersion = GL_ES_VERSION; } return config; } diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index 890f930c337b6..82539fb7132ba 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -40,7 +40,6 @@ import java.util.List; /** * Manages SMS operations such as sending data, text, and pdu SMS messages. * Get this object by calling the static method SmsManager.getDefault(). - * @hide */ public final class SmsManager { private static SmsManager sInstance; @@ -202,6 +201,8 @@ public final class SmsManager { /** * Send a raw SMS PDU. + * A PDU is a protocol data unit. It contains the message and the + * associated meta information. * * @param smsc the SMSC to send the message through, or NULL for the * default SMSC @@ -219,8 +220,6 @@ public final class SmsManager { * @param deliveryIntent if not NULL this PendingIntent is * broadcast when the message is delivered to the recipient. The * raw pdu of the status report is in the extended data ("pdu"). - * - * @hide */ private void sendRawPdu(byte[] smsc, byte[] pdu, PendingIntent sentIntent, PendingIntent deliveryIntent) { @@ -252,6 +251,8 @@ public final class SmsManager { /** * Copy a raw SMS PDU to the ICC. + * ICC (Integrated Circuit Card) is the card of the device. + * For example, this can be the SIM or USIM for GSM. * * @param smsc the SMSC for this message, or NULL for the default SMSC * @param pdu the raw PDU to store @@ -278,6 +279,8 @@ public final class SmsManager { /** * Delete the specified message from the ICC. + * ICC (Integrated Circuit Card) is the card of the device. + * For example, this can be the SIM or USIM for GSM. * * @param messageIndex is the record index of the message on ICC * @return true for success @@ -304,6 +307,8 @@ public final class SmsManager { /** * Update the specified message on the ICC. + * ICC (Integrated Circuit Card) is the card of the device. + * For example, this can be the SIM or USIM for GSM. * * @param messageIndex record index of message to update * @param newStatus new message status (STATUS_ON_ICC_READ, @@ -331,6 +336,8 @@ public final class SmsManager { /** * Retrieves all messages currently stored on ICC. + * ICC (Integrated Circuit Card) is the card of the device. + * For example, this can be the SIM or USIM for GSM. * * @return ArrayList of SmsMessage objects * @@ -359,12 +366,12 @@ public final class SmsManager { * getAllMessagesFromIcc * @return ArrayList of SmsMessage objects. */ - private ArrayList createMessageListFromRawRecords(List records) { + private ArrayList createMessageListFromRawRecords(List records) { ArrayList messages = new ArrayList(); if (records != null) { int count = records.size(); for (int i = 0; i < count; i++) { - SmsRawData data = (SmsRawData)records.get(i); + SmsRawData data = records.get(i); // List contains all records, including "free" records (null) if (data != null) { SmsMessage sms = SmsMessage.createFromEfRecord(i+1, data.getBytes()); diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java index 775b0343b751c..0617dada43e61 100644 --- a/telephony/java/android/telephony/SmsMessage.java +++ b/telephony/java/android/telephony/SmsMessage.java @@ -28,13 +28,13 @@ import com.android.internal.telephony.SmsMessageBase.TextEncodingDetails; import java.lang.Math; import java.util.ArrayList; +import java.util.Arrays; import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA; /** * A Short Message Service message. - * @hide */ public class SmsMessage { private static final boolean LOCAL_DEBUG = true; @@ -49,18 +49,6 @@ public class SmsMessage { UNKNOWN, CLASS_0, CLASS_1, CLASS_2, CLASS_3; } - /** - * 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; public static final int ENCODING_7BIT = 1; @@ -70,25 +58,10 @@ public class SmsMessage { /** 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. - * - * @hide pending API Council approval to extend the public API */ public static final int MAX_USER_DATA_BYTES_WITH_HEADER = 134; @@ -103,17 +76,26 @@ public class SmsMessage { public static final int MAX_USER_DATA_SEPTETS_WITH_HEADER = 153; /** Contains actual SmsMessage. Only public for debugging and for framework layer. - * {@hide} - */ + * + * @hide + */ public SmsMessageBase mWrappedSmsMessage; - public static class SubmitPdu extends SubmitPduBase { + public static class SubmitPdu { - //Constructor - public SubmitPdu() { + public byte[] encodedScAddress; // Null if not applicable. + public byte[] encodedMessage; + + public String toString() { + return "SubmitPdu: encodedScAddress = " + + Arrays.toString(encodedScAddress) + + ", encodedMessage = " + + Arrays.toString(encodedMessage); } - /* {@hide} */ + /** + * @hide + */ protected SubmitPdu(SubmitPduBase spb) { this.encodedMessage = spb.encodedMessage; this.encodedScAddress = spb.encodedScAddress; @@ -121,7 +103,11 @@ public class SmsMessage { } - // Constructor + /** + * Constructor + * + * @hide + */ public SmsMessage() { this(getSmsFacility()); } @@ -278,8 +264,8 @@ public class SmsMessage { 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); + com.android.internal.telephony.cdma.SmsMessage.calculateLength(msgBody, use7bitOnly) : + com.android.internal.telephony.gsm.SmsMessage.calculateLength(msgBody, use7bitOnly); int ret[] = new int[4]; ret[0] = ted.msgCount; ret[1] = ted.codeUnitCount; @@ -295,12 +281,14 @@ public class SmsMessage { * @param text text, must not be null. * @return an ArrayList of strings that, in order, * comprise the original msg text + * + * @hide */ public static ArrayList 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); + com.android.internal.telephony.cdma.SmsMessage.calculateLength(text, false) : + com.android.internal.telephony.gsm.SmsMessage.calculateLength(text, false); // TODO(cleanup): The code here could be rolled into the logic // below cleanly if these MAX_* constants were defined more @@ -321,11 +309,8 @@ public class SmsMessage { 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); - } + // For multi-segment messages, CDMA 7bit equals GSM 7bit encoding (EMS mode). + nextPos = GsmAlphabet.findGsmSeptetLimitIndex(text, pos, limit); } else { // Assume unicode. nextPos = pos + Math.min(limit / 2, textLen - pos); } @@ -346,10 +331,11 @@ public class SmsMessage { * current encoding. * * @param messageBody the message to encode - * @param use7bitOnly if true, characters that are not part of the GSM - * alphabet are counted as a single space char. If false, a - * messageBody containing non-GSM alphabet characters is calculated - * for 16-bit encoding. + * @param use7bitOnly if true, characters that are not part of the radio + * specific (GSM / CDMA) alphabet encoding are converted to as a + * single space characters. If false, a messageBody containing + * non-GSM or non-CDMA alphabet characters are encoded using + * 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 @@ -691,6 +677,8 @@ public class SmsMessage { /** This method returns the reference to a specific * SmsMessage object, which is used for accessing its static methods. * @return Specific SmsMessage. + * + * @hide */ private static final SmsMessageBase getSmsFacility(){ int activePhone = TelephonyManager.getDefault().getPhoneType(); diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index ba5c6e73680ab..ed9af663c682a 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -256,7 +256,7 @@ public class TelephonyManager { * No phone module * */ - public static final int PHONE_TYPE_NONE = 0; + public static final int PHONE_TYPE_NONE = RILConstants.NO_PHONE; /** * GSM phone diff --git a/telephony/java/android/telephony/gsm/SmsManager.java b/telephony/java/android/telephony/gsm/SmsManager.java index cdd707e629a22..241c4852c4eb1 100644 --- a/telephony/java/android/telephony/gsm/SmsManager.java +++ b/telephony/java/android/telephony/gsm/SmsManager.java @@ -43,6 +43,7 @@ import java.util.ArrayList; return sInstance; } + @Deprecated private SmsManager() { mSmsMgrProxy = android.telephony.SmsManager.getDefault(); } diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java index 7834018246215..0763e63e7c9a5 100644 --- a/telephony/java/com/android/internal/telephony/RILConstants.java +++ b/telephony/java/com/android/internal/telephony/RILConstants.java @@ -68,8 +68,9 @@ public interface RILConstants { int CDMA_CELL_BROADCAST_SMS_DISABLED = 1; int CDMA_CELL_BROADCAST_SMS_ENABLED = 0; - int CDMA_PHONE = 0; + int NO_PHONE = 0; int GSM_PHONE = 1; + int CDMA_PHONE = 2; int CDM_TTY_MODE_DISABLED = 0; int CDM_TTY_MODE_ENABLED = 1; @@ -85,14 +86,6 @@ cat include/telephony/ril.h | \ >>java/android/com.android.internal.telephony/gsm/RILConstants.java */ - - int RIL_SIM_ABSENT = 0; - int RIL_SIM_NOT_READY = 1; - int RIL_SIM_READY = 2; - int RIL_SIM_PIN = 3; - int RIL_SIM_PUK = 4; - int RIL_SIM_NETWORK_PERSONALIZATION = 5; - /** * No restriction at all including voice/SMS/USSD/SS/AV64 * and packet data. diff --git a/telephony/java/com/android/internal/telephony/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java index 3c7dd458f94bf..8b9ccb4c636d8 100644 --- a/telephony/java/com/android/internal/telephony/SmsMessageBase.java +++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java @@ -118,6 +118,7 @@ public abstract class SmsMessageBase { public int codeUnitSize; } + // TODO(): This class is duplicated in SmsMessage.java. Refactor accordingly. public static abstract class SubmitPduBase { public byte[] encodedScAddress; // Null if not applicable. public byte[] encodedMessage; diff --git a/test-runner/android/test/IsolatedContext.java b/test-runner/android/test/IsolatedContext.java index 286666684b887..859b2e5901783 100644 --- a/test-runner/android/test/IsolatedContext.java +++ b/test-runner/android/test/IsolatedContext.java @@ -13,6 +13,7 @@ import android.content.pm.PackageManager; import android.net.Uri; import java.util.List; +import java.io.File; /** * A mock context which prevents its users from talking to the rest of the device while @@ -82,4 +83,8 @@ public class IsolatedContext extends ContextWrapper { return null; } + @Override + public File getFilesDir() { + return new File("/dev/null"); + } } diff --git a/test-runner/android/test/mock/MockContext.java b/test-runner/android/test/mock/MockContext.java index b83a44d6ac000..9fb1e612f9144 100644 --- a/test-runner/android/test/mock/MockContext.java +++ b/test-runner/android/test/mock/MockContext.java @@ -110,6 +110,7 @@ public class MockContext extends Context { throw new UnsupportedOperationException(); } + /** @hide */ @Override public File getSharedPrefsFile(String name) { throw new UnsupportedOperationException(); diff --git a/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java b/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java index 4c5fefc43b6f9..e48a57bdb7e0c 100644 --- a/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java +++ b/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java @@ -23,14 +23,11 @@ import android.app.ISearchManager; import android.app.SearchManager; import android.content.ComponentName; import android.content.Context; -import android.os.Bundle; -import android.os.RemoteException; import android.os.ServiceManager; import android.server.search.SearchableInfo; import android.test.ActivityInstrumentationTestCase2; import android.test.suitebuilder.annotation.LargeTest; import android.test.suitebuilder.annotation.MediumTest; -import android.util.AndroidRuntimeException; /** * To launch this test from the command line: @@ -98,22 +95,6 @@ public class SearchManagerTest extends ActivityInstrumentationTestCase2 0); + } + + @SmallTest + public void testGetTypeFromManager() { + VpnManager m = new VpnManager(getContext()); + VpnType[] types = VpnManager.getSupportedVpnTypes(); + for (VpnType t : types) { + assertEquals(t, m.createVpnProfile(t).getType()); + } + } + + @SmallTest + public void testParcelable() { + VpnProfile p = createTestProfile(VpnState.CONNECTED); + Parcel parcel = Parcel.obtain(); + p.writeToParcel(parcel, 0); + parcel.setDataPosition(0); + + // VpnState is transient and not saved in the parcel + testVpnProfile(VpnProfile.CREATOR.createFromParcel(parcel), null); + } + + @SmallTest + public void testReceiver() { + final String profileName = "whatever"; + final VpnState state = VpnState.DISCONNECTING; + final ConditionVariable cv = new ConditionVariable(); + cv.close(); + BroadcastReceiver r = new BroadcastReceiver() { + public void onReceive(Context c, Intent i) { + assertEquals(profileName, + i.getStringExtra(VpnManager.BROADCAST_PROFILE_NAME)); + assertEquals(state, i.getSerializableExtra( + VpnManager.BROADCAST_CONNECTION_STATE)); + cv.open(); + } + }; + + VpnManager m = new VpnManager(getContext()); + m.registerConnectivityReceiver(r); + m.broadcastConnectivity(profileName, state); + + // fail it if onReceive() doesn't get executed in 5 sec + assertTrue(cv.block(5000)); + } + + private void testVpnType(VpnType type) { + assertFalse(TextUtils.isEmpty(type.getDisplayName())); + assertNotNull(type.getDescription()); + assertNotNull(type.getProfileClass()); + } + + private VpnProfile createTestProfile(VpnState state) { + VpnProfile p = new L2tpProfile(); + p.setName(NAME); + p.setServerName(SERVER_NAME); + p.setId(ID); + p.setDomainSuffices(SUFFICES); + p.setRouteList(ROUTES); + p.setSavedUsername(SAVED_NAME); + p.setState(state); + return p; + } + + private void testVpnProfile(VpnProfile p, VpnState state) { + assertEquals(NAME, p.getName()); + assertEquals(SERVER_NAME, p.getServerName()); + assertEquals(ID, p.getId()); + assertEquals(SUFFICES, p.getDomainSuffices()); + assertEquals(ROUTES, p.getRouteList()); + assertEquals(SAVED_NAME, p.getSavedUsername()); + if (state != null) assertEquals(state, p.getState()); } } diff --git a/tests/CoreTests/android/AndroidManifest.xml b/tests/CoreTests/android/AndroidManifest.xml index 4809f84499e51..98cc9e501ad17 100644 --- a/tests/CoreTests/android/AndroidManifest.xml +++ b/tests/CoreTests/android/AndroidManifest.xml @@ -30,6 +30,7 @@ + diff --git a/tests/CoreTests/android/core/CryptoTest.java b/tests/CoreTests/android/core/CryptoTest.java index f00d49ff0f219..e6e50ecc4ab63 100644 --- a/tests/CoreTests/android/core/CryptoTest.java +++ b/tests/CoreTests/android/core/CryptoTest.java @@ -22,7 +22,6 @@ import junit.framework.TestCase; import org.apache.harmony.xnet.provider.jsse.OpenSSLMessageDigest; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.ExtendedDigest; -import org.bouncycastle.crypto.digests.MD2Digest; import org.bouncycastle.crypto.digests.MD4Digest; import org.bouncycastle.crypto.digests.MD5Digest; import org.bouncycastle.crypto.digests.SHA1Digest; @@ -93,16 +92,6 @@ public class CryptoTest extends TestCase { // Assert.assertTrue("New hash should be faster", newTime < oldTime); } - - /** - * Tests the MD2 implementation. - */ - @LargeTest - public void testMD2() { - Digest oldDigest = new MD2Digest(); - Digest newDigest = OpenSSLMessageDigest.getInstance("MD2"); - doTestMessageDigest(oldDigest, newDigest); - } /** * Tests the MD4 implementation. diff --git a/tests/CoreTests/android/database/MatrixCursorTest.java b/tests/CoreTests/android/database/MatrixCursorTest.java index fb8a12f444bf5..cddc6c41ed2c3 100644 --- a/tests/CoreTests/android/database/MatrixCursorTest.java +++ b/tests/CoreTests/android/database/MatrixCursorTest.java @@ -32,6 +32,12 @@ public class MatrixCursorTest extends TestCase { cursor.newRow().add(null); cursor.moveToNext(); assertTrue(cursor.isNull(0)); + assertNull(cursor.getString(0)); + assertEquals(0, cursor.getShort(0)); + assertEquals(0, cursor.getInt(0)); + assertEquals(0L, cursor.getLong(0)); + assertEquals(0.0f, cursor.getFloat(0)); + assertEquals(0.0d, cursor.getDouble(0)); } public void testMatrixCursor() { diff --git a/tests/DpiTest/res/drawable-hdpi/npatch240dpi.9.png b/tests/DpiTest/res/drawable-hdpi/npatch240dpi.9.png new file mode 100644 index 0000000000000000000000000000000000000000..a362b0ffe281996d2eb324e48df56ccc0031d7cb GIT binary patch literal 17331 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 U$N{&z)Bpeg07*qoM6N<$f`>4}{r~^~ literal 0 HcmV?d00001 diff --git a/tests/DpiTest/res/drawable-hdpi/stylogo240dpi.png b/tests/DpiTest/res/drawable-hdpi/stylogo240dpi.png new file mode 100644 index 0000000000000000000000000000000000000000..4d717a86143dd680bbdd9f6f54c6623d5a33b03b GIT binary patch literal 13388 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 RfP?@5002ovPDHLkV1kkjBE0|r literal 0 HcmV?d00001 diff --git a/tests/DpiTest/res/drawable-ldpi/reslogo120dpi.png b/tests/DpiTest/res/drawable-ldpi/reslogo120dpi.png new file mode 100644 index 0000000000000000000000000000000000000000..46bbd5bd3d485ba132f14fd5b04a7c6b69004d0c GIT binary patch literal 5178 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 Eg4ZI2KmY&$ literal 0 HcmV?d00001 diff --git a/tests/DpiTest/res/drawable/reslogo160dpi.png b/tests/DpiTest/res/drawable/reslogo160dpi.png new file mode 100644 index 0000000000000000000000000000000000000000..c23b2ce83b43d984173a16be7fc25b46bf4fbd50 GIT binary patch literal 8114 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 literal 0 HcmV?d00001 diff --git a/tests/DpiTest/res/drawable/stylogo160dpi.png b/tests/DpiTest/res/drawable/stylogo160dpi.png new file mode 100644 index 0000000000000000000000000000000000000000..c23b2ce83b43d984173a16be7fc25b46bf4fbd50 GIT binary patch literal 8114 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 + + + + + + + + + + + diff --git a/packages/SettingsProvider/res/values-zh-rTW/defaults.xml b/tests/DpiTest/res/layout/styled_image_views.xml similarity index 60% rename from packages/SettingsProvider/res/values-zh-rTW/defaults.xml rename to tests/DpiTest/res/layout/styled_image_views.xml index fdbba8827e843..86c63bf23c39b 100644 --- a/packages/SettingsProvider/res/values-zh-rTW/defaults.xml +++ b/tests/DpiTest/res/layout/styled_image_views.xml @@ -1,4 +1,4 @@ - + - - "手機,藍牙,wifi" - "gps" - - - + + + + + + + + diff --git a/tests/DpiTest/res/values/styles.xml b/tests/DpiTest/res/values/styles.xml new file mode 100644 index 0000000000000..bb4b13c6c5e7a --- /dev/null +++ b/tests/DpiTest/res/values/styles.xml @@ -0,0 +1,35 @@ + + + + + + + + + + diff --git a/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java index 49fff57ba0fe1..ae53b76669603 100644 --- a/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java +++ b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java @@ -28,12 +28,14 @@ import android.graphics.drawable.Drawable; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.ScrollView; +import android.view.LayoutInflater; import android.view.View; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.CompatibilityInfo; import android.util.DisplayMetrics; +import android.util.Log; public class DpiTestActivity extends Activity { public DpiTestActivity() { @@ -52,14 +54,13 @@ public class DpiTestActivity extends Activity { // be doing it. Application app = ActivityThread.currentActivityThread().getApplication(); ApplicationInfo ai = app.getPackageManager().getApplicationInfo( - "com.google.android.test.dpi", - PackageManager.GET_SUPPORTS_DENSITIES); + "com.google.android.test.dpi", 0); if (noCompat) { ai.flags |= ApplicationInfo.FLAG_SUPPORTS_LARGE_SCREENS | ApplicationInfo.FLAG_SUPPORTS_NORMAL_SCREENS | ApplicationInfo.FLAG_SUPPORTS_SMALL_SCREENS - | ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS; - ai.supportsDensities = new int[] { ApplicationInfo.ANY_DENSITY }; + | ApplicationInfo.FLAG_RESIZEABLE_FOR_SCREENS + | ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES; app.getResources().setCompatibilityInfo(new CompatibilityInfo(ai)); } } catch (PackageManager.NameNotFoundException e) { @@ -71,6 +72,9 @@ public class DpiTestActivity extends Activity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + final LayoutInflater li = (LayoutInflater)getSystemService( + LAYOUT_INFLATER_SERVICE); + this.setTitle(R.string.act_title); LinearLayout root = new LinearLayout(this); root.setOrientation(LinearLayout.VERTICAL); @@ -96,6 +100,14 @@ public class DpiTestActivity extends Activity { addLabelToRoot(root, "Prescaled resource drawable"); addChildToRoot(root, layout); + layout = (LinearLayout)li.inflate(R.layout.image_views, null); + addLabelToRoot(root, "Inflated layout"); + addChildToRoot(root, layout); + + layout = (LinearLayout)li.inflate(R.layout.styled_image_views, null); + addLabelToRoot(root, "Inflated styled layout"); + addChildToRoot(root, layout); + layout = new LinearLayout(this); addCanvasBitmap(layout, R.drawable.logo120dpi, true); addCanvasBitmap(layout, R.drawable.logo160dpi, true); @@ -117,6 +129,13 @@ public class DpiTestActivity extends Activity { addLabelToRoot(root, "No-dpi resource drawable"); addChildToRoot(root, layout); + layout = new LinearLayout(this); + addNinePatchResourceDrawable(layout, R.drawable.smlnpatch120dpi); + addNinePatchResourceDrawable(layout, R.drawable.smlnpatch160dpi); + addNinePatchResourceDrawable(layout, R.drawable.smlnpatch240dpi); + addLabelToRoot(root, "Prescaled 9-patch resource drawable"); + addChildToRoot(root, layout); + setContentView(scrollWrap(root)); } @@ -145,8 +164,8 @@ public class DpiTestActivity extends Activity { View view = new View(this); - final BitmapDrawable d = new BitmapDrawable(bitmap); - if (!scale) d.setDensityScale(getResources().getDisplayMetrics()); + final BitmapDrawable d = new BitmapDrawable(getResources(), bitmap); + if (!scale) d.setTargetDensity(getResources().getDisplayMetrics()); view.setBackgroundDrawable(d); view.setLayoutParams(new LinearLayout.LayoutParams(d.getIntrinsicWidth(), @@ -176,6 +195,19 @@ public class DpiTestActivity extends Activity { layout.addView(view); } + private void addNinePatchResourceDrawable(LinearLayout layout, int resource) { + View view = new View(this); + + final Drawable d = getResources().getDrawable(resource); + view.setBackgroundDrawable(d); + + Log.i("foo", "9-patch #" + Integer.toHexString(resource) + + " w=" + d.getIntrinsicWidth() + " h=" + d.getIntrinsicHeight()); + view.setLayoutParams(new LinearLayout.LayoutParams( + d.getIntrinsicWidth()*2, d.getIntrinsicHeight()*2)); + layout.addView(view); + } + private Bitmap loadAndPrintDpi(int id, boolean scale) { Bitmap bitmap; if (scale) { diff --git a/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewCallbacks.java b/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewCallbacks.java index 93cb84aeacf33..515ddba6dbaef 100644 --- a/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewCallbacks.java +++ b/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewCallbacks.java @@ -27,8 +27,10 @@ public class AutoCompleteTextViewCallbacks super("com.android.frameworktest", AutoCompleteTextViewSimple.class); } - /** Test that the initial popup of the suggestions does not select anything */ - @MediumTest + /** Test that the initial popup of the suggestions does not select anything. + * + * TODO: test currently fails. Add back MediumTest annotation when fixed. + */ public void testPopupNoSelection() { AutoCompleteTextViewSimple theActivity = getActivity(); AutoCompleteTextView textView = theActivity.getTextView(); diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeTypedArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeTypedArray.java index 48998dbafe46f..10421de9a0cff 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeTypedArray.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeTypedArray.java @@ -39,7 +39,7 @@ import java.util.Map; * TODO: describe. */ public final class BridgeTypedArray extends TypedArray { - + @SuppressWarnings("hiding") private BridgeResources mResources; private BridgeContext mContext; @@ -47,7 +47,7 @@ public final class BridgeTypedArray extends TypedArray { private IResourceValue[] mData; private String[] mNames; private final boolean mPlatformFile; - + public BridgeTypedArray(BridgeResources resources, BridgeContext context, int len, boolean platformFile) { super(null, null, null, 0); @@ -58,12 +58,12 @@ public final class BridgeTypedArray extends TypedArray { mNames = new String[len]; } - /** A bridge-specific method that sets a value in the type array */ + /** A bridge-specific method that sets a value in the type array */ public void bridgeSetValue(int index, String name, IResourceValue value) { mData[index] = value; mNames[index] = name; } - + /** * Seals the array after all calls to {@link #bridgeSetValue(int, String, IResourceValue)} have * been done. @@ -79,11 +79,11 @@ public final class BridgeTypedArray extends TypedArray { count++; } } - + // allocate the table with an extra to store the size mIndices = new int[count+1]; mIndices[0] = count; - + // fill the array with the indices. int index = 1; for (int i = 0 ; i < mData.length ; i++) { @@ -100,7 +100,7 @@ public final class BridgeTypedArray extends TypedArray { public int length() { return mData.length; } - + /** * Return the Resources object this array was loaded from. */ @@ -108,13 +108,13 @@ public final class BridgeTypedArray extends TypedArray { public Resources getResources() { return mResources; } - + /** * Retrieve the styled string value for the attribute at index. - * + * * @param index Index of attribute to retrieve. - * - * @return CharSequence holding string data. May be styled. Returns + * + * @return CharSequence holding string data. May be styled. Returns * null if the attribute is not defined. */ @Override @@ -129,9 +129,9 @@ public final class BridgeTypedArray extends TypedArray { /** * Retrieve the string value for the attribute at index. - * + * * @param index Index of attribute to retrieve. - * + * * @return String holding string data. Any styling information is * removed. Returns null if the attribute is not defined. */ @@ -140,16 +140,16 @@ public final class BridgeTypedArray extends TypedArray { if (mData[index] != null) { return mData[index].getValue(); } - + return null; } /** * Retrieve the boolean value for the attribute at index. - * + * * @param index Index of attribute to retrieve. * @param defValue Value to return if the attribute is not defined. - * + * * @return Attribute boolean value, or defValue if not defined. */ @Override @@ -162,16 +162,16 @@ public final class BridgeTypedArray extends TypedArray { if (s != null) { return XmlUtils.convertValueToBoolean(s, defValue); } - + return defValue; } /** * Retrieve the integer value for the attribute at index. - * + * * @param index Index of attribute to retrieve. * @param defValue Value to return if the attribute is not defined. - * + * * @return Attribute int value, or defValue if not defined. */ @Override @@ -181,7 +181,7 @@ public final class BridgeTypedArray extends TypedArray { } String s = mData[index].getValue(); - + try { return (s == null) ? defValue : XmlUtils.convertValueToInt(s, defValue); } catch (NumberFormatException e) { @@ -192,11 +192,11 @@ public final class BridgeTypedArray extends TypedArray { // Check for possible constants and try to find them. // Get the map of attribute-constant -> IntegerValue Map map = Bridge.getEnumValues(mNames[index]); - + if (map != null) { // accumulator to store the value of the 1+ constants. int result = 0; - + // split the value in case this is a mix of several flags. String[] keywords = s.split("\\|"); for (String keyword : keywords) { @@ -217,9 +217,9 @@ public final class BridgeTypedArray extends TypedArray { /** * Retrieve the float value for the attribute at index. - * + * * @param index Index of attribute to retrieve. - * + * * @return Attribute float value, or defValue if not defined.. */ @Override @@ -237,23 +237,23 @@ public final class BridgeTypedArray extends TypedArray { mContext.getLogger().warning(String.format( "Unable to convert \"%s\" into a float in attribute \"%2$s\"", s, mNames[index])); - + // we'll return the default value below. } } return defValue; } - + /** * Retrieve the color value for the attribute at index. If * the attribute references a color resource holding a complex * {@link android.content.res.ColorStateList}, then the default color from * the set is returned. - * + * * @param index Index of attribute to retrieve. * @param defValue Value to return if the attribute is not defined or * not a resource. - * + * * @return Attribute color value, or defValue if not defined. */ @Override @@ -261,7 +261,7 @@ public final class BridgeTypedArray extends TypedArray { if (mData[index] == null) { return defValue; } - + String s = mData[index].getValue(); try { return ResourceHelper.getColor(s); @@ -280,9 +280,9 @@ public final class BridgeTypedArray extends TypedArray { * Retrieve the ColorStateList for the attribute at index. * The value may be either a single solid color or a reference to * a color or complex {@link android.content.res.ColorStateList} description. - * + * * @param index Index of attribute to retrieve. - * + * * @return ColorStateList for the attribute, or null if not defined. */ @Override @@ -296,14 +296,14 @@ public final class BridgeTypedArray extends TypedArray { if (value == null) { return null; } - + try { int color = ResourceHelper.getColor(value); return ColorStateList.valueOf(color); } catch (NumberFormatException e) { // if it's not a color value, we'll attempt to read the xml based color below. } - + // let the framework inflate the ColorStateList from the XML file. try { File f = new File(value); @@ -311,7 +311,7 @@ public final class BridgeTypedArray extends TypedArray { KXmlParser parser = new KXmlParser(); parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); parser.setInput(new FileReader(f)); - + ColorStateList colorStateList = ColorStateList.createFromXml( mContext.getResources(), // FIXME: we need to know if this resource is platform or not @@ -325,22 +325,22 @@ public final class BridgeTypedArray extends TypedArray { // return null below. } - + // looks like were unable to resolve the color value. mContext.getLogger().warning(String.format( "Unable to resolve color value \"%1$s\" in attribute \"%2$s\"", value, mNames[index])); - + return null; } - + /** * Retrieve the integer value for the attribute at index. - * + * * @param index Index of attribute to retrieve. * @param defValue Value to return if the attribute is not defined or * not a resource. - * + * * @return Attribute integer value, or defValue if not defined. */ @Override @@ -362,23 +362,23 @@ public final class BridgeTypedArray extends TypedArray { // The default value is returned below. } } - + return defValue; } /** - * Retrieve a dimensional unit attribute at index. Unit - * conversions are based on the current {@link DisplayMetrics} - * associated with the resources this {@link TypedArray} object - * came from. - * + * Retrieve a dimensional unit attribute at index. Unit + * conversions are based on the current {@link DisplayMetrics} + * associated with the resources this {@link TypedArray} object + * came from. + * * @param index Index of attribute to retrieve. * @param defValue Value to return if the attribute is not defined or * not a resource. - * - * @return Attribute dimension value multiplied by the appropriate + * + * @return Attribute dimension value multiplied by the appropriate * metric, or defValue if not defined. - * + * * @see #getDimensionPixelOffset * @see #getDimensionPixelSize */ @@ -397,11 +397,11 @@ public final class BridgeTypedArray extends TypedArray { } else if (s.equals(BridgeConstants.WRAP_CONTENT)) { return LayoutParams.WRAP_CONTENT; } - + if (ResourceHelper.stringToFloat(s, mValue)) { return mValue.getDimension(mResources.mMetrics); } - + // looks like we were unable to resolve the dimension value mContext.getLogger().warning(String.format( "Unable to resolve dimension value \"%1$s\" in attribute \"%2$s\"", @@ -416,14 +416,14 @@ public final class BridgeTypedArray extends TypedArray { * {@link #getDimension}, except the returned value is converted to * integer pixels for you. An offset conversion involves simply * truncating the base value to an integer. - * + * * @param index Index of attribute to retrieve. * @param defValue Value to return if the attribute is not defined or * not a resource. - * - * @return Attribute dimension value multiplied by the appropriate + * + * @return Attribute dimension value multiplied by the appropriate * metric and truncated to integer pixels, or defValue if not defined. - * + * * @see #getDimension * @see #getDimensionPixelSize */ @@ -439,14 +439,14 @@ public final class BridgeTypedArray extends TypedArray { * integer pixels for use as a size. A size conversion involves * rounding the base value, and ensuring that a non-zero base value * is at least one pixel in size. - * + * * @param index Index of attribute to retrieve. * @param defValue Value to return if the attribute is not defined or * not a resource. - * - * @return Attribute dimension value multiplied by the appropriate + * + * @return Attribute dimension value multiplied by the appropriate * metric and truncated to integer pixels, or defValue if not defined. - * + * * @see #getDimension * @see #getDimensionPixelOffset */ @@ -465,7 +465,7 @@ public final class BridgeTypedArray extends TypedArray { } else if (s.equals(BridgeConstants.WRAP_CONTENT)) { return LayoutParams.WRAP_CONTENT; } - + // FIXME huh? float f = getDimension(index, defValue); @@ -483,11 +483,11 @@ public final class BridgeTypedArray extends TypedArray { * {@link android.view.ViewGroup}'s layout_width and layout_height * attributes. This is only here for performance reasons; applications * should use {@link #getDimensionPixelSize}. - * + * * @param index Index of the attribute to retrieve. * @param name Textual name of attribute for error reporting. - * - * @return Attribute dimension value multiplied by the appropriate + * + * @return Attribute dimension value multiplied by the appropriate * metric and truncated to integer pixels. */ @Override @@ -495,20 +495,25 @@ public final class BridgeTypedArray extends TypedArray { return getDimensionPixelSize(index, 0); } + @Override + public int getLayoutDimension(int index, int defValue) { + return getDimensionPixelSize(index, defValue); + } + /** * Retrieve a fractional unit attribute at index. - * - * @param index Index of attribute to retrieve. - * @param base The base value of this fraction. In other words, a + * + * @param index Index of attribute to retrieve. + * @param base The base value of this fraction. In other words, a * standard fraction is multiplied by this value. - * @param pbase The parent base value of this fraction. In other + * @param pbase The parent base value of this fraction. In other * words, a parent fraction (nn%p) is multiplied by this * value. * @param defValue Value to return if the attribute is not defined or * not a resource. - * - * @return Attribute fractional value multiplied by the appropriate - * base value, or defValue if not defined. + * + * @return Attribute fractional value multiplied by the appropriate + * base value, or defValue if not defined. */ @Override public float getFraction(int index, int base, int pbase, float defValue) { @@ -520,7 +525,7 @@ public final class BridgeTypedArray extends TypedArray { if (value == null) { return defValue; } - + if (ResourceHelper.stringToFloat(value, mValue)) { return mValue.getFraction(base, pbase); } @@ -529,29 +534,29 @@ public final class BridgeTypedArray extends TypedArray { mContext.getLogger().warning(String.format( "Unable to resolve fraction value \"%1$s\" in attribute \"%2$s\"", value, mNames[index])); - + return defValue; } /** * Retrieve the resource identifier for the attribute at - * index. Note that attribute resource as resolved when - * the overall {@link TypedArray} object is retrieved. As a - * result, this function will return the resource identifier of the - * final resource value that was found, not necessarily the - * original resource that was specified by the attribute. - * + * index. Note that attribute resource as resolved when + * the overall {@link TypedArray} object is retrieved. As a + * result, this function will return the resource identifier of the + * final resource value that was found, not necessarily the + * original resource that was specified by the attribute. + * * @param index Index of attribute to retrieve. * @param defValue Value to return if the attribute is not defined or * not a resource. - * + * * @return Attribute resource identifier, or defValue if not defined. */ @Override public int getResourceId(int index, int defValue) { // get the IResource for this index IResourceValue resValue = mData[index]; - + // no data, return the default value. if (resValue == null) { return defValue; @@ -562,7 +567,7 @@ public final class BridgeTypedArray extends TypedArray { // get the id that will represent this style. return mContext.getDynamicIdByStyle((IStyleResourceValue)resValue); } - + // if the attribute was a reference to an id, and not a declaration of an id (@+id), then // the xml attribute value was "resolved" which leads us to a IResourceValue with // getType() returning "id" and getName() returning the id name @@ -583,7 +588,7 @@ public final class BridgeTypedArray extends TypedArray { if (value == null) { return defValue; } - + // if the value is just an integer, return it. try { int i = Integer.parseInt(value); @@ -601,14 +606,14 @@ public final class BridgeTypedArray extends TypedArray { // fact in the android.R and com.android.internal.R classes. // The field mPlatformFile will indicate that all IDs are to be looked up in the android R // classes exclusively. - + // if this is a reference to an id, find it. if (value.startsWith("@id/") || value.startsWith("@+") || value.startsWith("@android:id/")) { - + int pos = value.indexOf('/'); String idName = value.substring(pos + 1); - + // if this is a framework id if (mPlatformFile || value.startsWith("@android") || value.startsWith("@+android")) { // look for idName in the android R classes @@ -621,7 +626,7 @@ public final class BridgeTypedArray extends TypedArray { // not a direct id valid reference? resolve it Integer idValue = null; - + if (resValue.isFramework()) { idValue = Bridge.getResourceValue(resValue.getType(), resValue.getName()); } else { @@ -632,7 +637,7 @@ public final class BridgeTypedArray extends TypedArray { if (idValue != null) { return idValue.intValue(); } - + mContext.getLogger().warning(String.format( "Unable to resolve id \"%1$s\" for attribute \"%2$s\"", value, mNames[index])); return defValue; @@ -643,9 +648,9 @@ public final class BridgeTypedArray extends TypedArray { * gets the resource ID of the selected attribute, and uses * {@link Resources#getDrawable Resources.getDrawable} of the owning * Resources object to retrieve its Drawable. - * + * * @param index Index of attribute to retrieve. - * + * * @return Drawable for the attribute, or null if not defined. */ @Override @@ -658,13 +663,13 @@ public final class BridgeTypedArray extends TypedArray { if (value == null || BridgeConstants.REFERENCE_NULL.equals(value)) { return null; } - + Drawable d = ResourceHelper.getDrawable(value, mContext, mData[index].isFramework()); - + if (d != null) { return d; } - + // looks like we were unable to resolve the drawable mContext.getLogger().warning(String.format( "Unable to resolve drawable \"%1$s\" in attribute \"%2$s\"", value, mNames[index])); @@ -678,9 +683,9 @@ public final class BridgeTypedArray extends TypedArray { * This gets the resource ID of the selected attribute, and uses * {@link Resources#getTextArray Resources.getTextArray} of the owning * Resources object to retrieve its String[]. - * + * * @param index Index of attribute to retrieve. - * + * * @return CharSequence[] for the attribute, or null if not defined. */ @Override @@ -693,7 +698,7 @@ public final class BridgeTypedArray extends TypedArray { if (value != null) { return new CharSequence[] { value }; } - + mContext.getLogger().warning(String.format( String.format("Unknown value for getTextArray(%d) => %s", //DEBUG index, mData[index].getName()))); @@ -703,44 +708,44 @@ public final class BridgeTypedArray extends TypedArray { /** * Retrieve the raw TypedValue for the attribute at index. - * + * * @param index Index of attribute to retrieve. * @param outValue TypedValue object in which to place the attribute's * data. - * - * @return Returns true if the value was retrieved, else false. + * + * @return Returns true if the value was retrieved, else false. */ @Override public boolean getValue(int index, TypedValue outValue) { if (mData[index] == null) { return false; } - + String s = mData[index].getValue(); - + return ResourceHelper.stringToFloat(s, outValue); } /** * Determines whether there is an attribute at index. - * + * * @param index Index of attribute to retrieve. - * + * * @return True if the attribute has a value, false otherwise. */ @Override public boolean hasValue(int index) { return mData[index] != null; } - + /** - * Retrieve the raw TypedValue for the attribute at index - * and return a temporary object holding its data. This object is only - * valid until the next call on to {@link TypedArray}. - * + * Retrieve the raw TypedValue for the attribute at index + * and return a temporary object holding its data. This object is only + * valid until the next call on to {@link TypedArray}. + * * @param index Index of attribute to retrieve. - * - * @return Returns a TypedValue object if the attribute is defined, + * + * @return Returns a TypedValue object if the attribute is defined, * containing its data; otherwise returns null. (You will not * receive a TypedValue whose type is TYPE_NULL.) */ @@ -749,7 +754,7 @@ public final class BridgeTypedArray extends TypedArray { if (getValue(index, mValue)) { return mValue; } - + return null; } diff --git a/vpn/java/android/net/vpn/PptpProfile.java b/vpn/java/android/net/vpn/PptpProfile.java index c68bb71f1a4e8..b4b7be5ccdb1d 100644 --- a/vpn/java/android/net/vpn/PptpProfile.java +++ b/vpn/java/android/net/vpn/PptpProfile.java @@ -16,15 +16,41 @@ package android.net.vpn; +import android.os.Parcel; + /** * The profile for PPTP type of VPN. * {@hide} */ public class PptpProfile extends VpnProfile { private static final long serialVersionUID = 1L; + private boolean mEncryption = true; @Override public VpnType getType() { return VpnType.PPTP; } + + /** + * Enables/disables the encryption for PPTP tunnel. + */ + public void setEncryptionEnabled(boolean enabled) { + mEncryption = enabled; + } + + public boolean isEncryptionEnabled() { + return mEncryption; + } + + @Override + protected void readFromParcel(Parcel in) { + super.readFromParcel(in); + mEncryption = in.readInt() > 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + super.writeToParcel(parcel, flags); + parcel.writeInt(mEncryption ? 1 : 0); + } } diff --git a/vpn/java/android/net/vpn/VpnManager.java b/vpn/java/android/net/vpn/VpnManager.java index 0bf2346798353..e448e5a58bce0 100644 --- a/vpn/java/android/net/vpn/VpnManager.java +++ b/vpn/java/android/net/vpn/VpnManager.java @@ -50,6 +50,10 @@ public class VpnManager { public static final int VPN_ERROR_CONNECTION_FAILED = 2; /** Error code to indicate the server is not known. */ public static final int VPN_ERROR_UNKNOWN_SERVER = 3; + /** Error code to indicate an error from challenge response. */ + public static final int VPN_ERROR_CHALLENGE = 4; + /** Error code to indicate an error of remote server hanging up. */ + public static final int VPN_ERROR_REMOTE_HUNG_UP = 5; private static final int VPN_ERROR_NO_ERROR = 0; public static final String PROFILES_PATH = "/data/misc/vpn/profiles"; diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index eda2f2d49672e..f85aadd27cfd4 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -45,6 +45,8 @@ public class WifiConfiguration implements Parcelable { /** {@hide} */ public static final String eapVarName = "eap"; /** {@hide} */ + public static final String phase2VarName = "phase2"; + /** {@hide} */ public static final String identityVarName = "identity"; /** {@hide} */ public static final String anonymousIdentityVarName = "anonymous_identity"; @@ -272,6 +274,11 @@ public class WifiConfiguration implements Parcelable { * {@hide} */ public String eap; + /** + * The phase2 authenication could be PAP, MSCHAP, MSCHAP2, GTC. + * {@hide} + */ + public String phase2; /** * The identity of the user in string, * which is used for the authentication. @@ -314,6 +321,7 @@ public class WifiConfiguration implements Parcelable { for (int i = 0; i < wepKeys.length; i++) wepKeys[i] = null; eap = null; + phase2 = null; identity = null; anonymousIdentity = null; password = null; @@ -399,6 +407,10 @@ public class WifiConfiguration implements Parcelable { if (this.eap != null) { sbuf.append(eap); } + sbuf.append('\n').append(" phase2: "); + if (this.phase2 != null) { + sbuf.append(phase2); + } sbuf.append('\n').append(" Identity: "); if (this.identity != null) { sbuf.append(identity); @@ -486,6 +498,7 @@ public class WifiConfiguration implements Parcelable { writeBitSet(dest, allowedPairwiseCiphers); writeBitSet(dest, allowedGroupCiphers); dest.writeString(eap); + dest.writeString(phase2); dest.writeString(identity); dest.writeString(anonymousIdentity); dest.writeString(password); @@ -516,6 +529,7 @@ public class WifiConfiguration implements Parcelable { config.allowedPairwiseCiphers = readBitSet(in); config.allowedGroupCiphers = readBitSet(in); config.eap = in.readString(); + config.phase2 = in.readString(); config.identity = in.readString(); config.anonymousIdentity = in.readString(); config.password = in.readString(); diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 1f73bec989845..74f428451f546 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -870,7 +870,10 @@ public class WifiManager { * Create a new MulticastLock * * @param tag a tag for the MulticastLock to identify it in debugging - * messages. + * messages. This string is never shown to the user under + * normal conditions, but should be descriptive enough to + * identify your application and the specific MulticastLock + * within it, if it holds multiple MulticastLocks. * * @return a new, unacquired MulticastLock with the given tag. * @@ -886,26 +889,36 @@ public class WifiManager { * addressed to this device. Acquring a MulticastLock will * cause the stack to receive packets addressed to multicast * addresses. Processing these extra packets can cause a noticable - * battery drain and should be disabled when not needed + * battery drain and should be disabled when not needed. */ public class MulticastLock { private String mTag; private final IBinder mBinder; + private int mRefCount; + private boolean mRefCounted; private boolean mHeld; private MulticastLock(String tag) { mTag = tag; mBinder = new Binder(); + mRefCount = 0; + mRefCounted = true; mHeld = false; } /** * Locks Wifi Multicast on until {@link #release} is called. * - * The first call to {@code acquire} will lock the Multicast on - * but subsequent calls will be ignored. Only one call to - * {@link #release} will be required, regardless of the number of - * times that {@code acquire} is called. + * If this MulticastLock is reference-counted each call to + * {@code acquire} will increment the reference count, and the + * wifi interface will receive multicast packets as long as the + * reference count is above zero. + * + * If this MulticastLock is not reference-counted, the first call to + * {@code acquire} will turn on the multicast packets, but subsequent + * calls will be ignored. Only one call to {@link #release} will + * be required, regardless of the number of times that {@code acquire} + * is called. * * Note that other applications may also lock Wifi Multicast on. * Only they can relinquish their lock. @@ -915,7 +928,7 @@ public class WifiManager { */ public void acquire() { synchronized (mBinder) { - if (!mHeld) { + if (mRefCounted ? (++mRefCount > 0) : (!mHeld)) { try { mService.acquireMulticastLock(mBinder, mTag); synchronized (WifiManager.this) { @@ -926,9 +939,9 @@ public class WifiManager { } mActiveLockCount++; } - mHeld = true; } catch (RemoteException ignore) { } + mHeld = true; } } } @@ -937,6 +950,18 @@ public class WifiManager { * Unlocks Wifi Multicast, restoring the filter of packets * not addressed specifically to this device and saving power. * + * If this MulticastLock is reference-counted, each call to + * {@code release} will decrement the reference count, and the + * multicast packets will only stop being received when the reference + * count reaches zero. If the reference count goes below zero (that + * is, if {@code release} is called a greater number of times than + * {@link #acquire}), an exception is thrown. + * + * If this MulticastLock is not reference-counted, the first call to + * {@code release} (after the radio was multicast locked using + * {@linke #acquire}) will unlock the multicast, and subsequent calls + * will be ignored. + * * Note that if any other Wifi Multicast Locks are still outstanding * this {@code release} call will not have an immediate effect. Only * when all applications have released all their Multicast Locks will @@ -947,19 +972,42 @@ public class WifiManager { */ public void release() { synchronized (mBinder) { - if (mHeld) { + if (mRefCounted ? (--mRefCount == 0) : (mHeld)) { try { mService.releaseMulticastLock(); synchronized (WifiManager.this) { mActiveLockCount--; } - mHeld = false; } catch (RemoteException ignore) { } + mHeld = false; + } + if (mRefCount < 0) { + throw new RuntimeException("MulticastLock under-locked " + + mTag); } } } + /** + * Controls whether this is a reference-counted or non-reference- + * counted MulticastLock. + * + * Reference-counted MulticastLocks keep track of the number of calls + * to {@link #acquire} and {@link #release}, and only stop the + * reception of multicast packets when every call to {@link #acquire} + * has been balanced with a call to {@link #release}. Non-reference- + * counted MulticastLocks allow the reception of multicast packets + * whenever {@link #acquire} is called and stop accepting multicast + * packets whenever {@link #release} is called. + * + * @param refCounted true if this MulticastLock should keep a reference + * count + */ + public void setReferenceCounted(boolean refCounted) { + mRefCounted = refCounted; + } + /** * Checks whether this MulticastLock is currently held. * @@ -972,17 +1020,23 @@ public class WifiManager { } public String toString() { - String s1, s2; + String s1, s2, s3; synchronized (mBinder) { s1 = Integer.toHexString(System.identityHashCode(this)); s2 = mHeld ? "held; " : ""; - return "MulticastLock{ " + s1 + "; " + s2 + " }"; + if (mRefCounted) { + s3 = "refcounted: refcount = " + mRefCount; + } else { + s3 = "not refcounted"; + } + return "MulticastLock{ " + s1 + "; " + s2 + s3 + " }"; } } @Override protected void finalize() throws Throwable { super.finalize(); + setReferenceCounted(false); release(); } }