summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk13
-rw-r--r--api/current.xml142
-rw-r--r--cmds/rawbu/backup.cpp1
-rwxr-xr-xcore/java/android/animation/ValueAnimator.java5
-rw-r--r--core/java/android/app/ActivityThread.java6
-rw-r--r--core/java/android/app/TimePickerDialog.java32
-rw-r--r--core/java/android/content/res/Configuration.java16
-rw-r--r--core/java/android/database/sqlite/SQLiteDatabase.java57
-rw-r--r--core/java/android/database/sqlite/SQLiteDebug.java16
-rw-r--r--core/java/android/preference/PreferenceFrameLayout.java113
-rw-r--r--core/java/android/text/method/QwertyKeyListener.java52
-rw-r--r--core/java/android/text/method/TextKeyListener.java7
-rw-r--r--core/java/android/view/KeyCharacterMap.java12
-rwxr-xr-xcore/java/android/view/KeyEvent.java74
-rw-r--r--core/java/android/view/MotionEvent.java12
-rw-r--r--core/java/android/view/View.java91
-rw-r--r--core/java/android/view/ViewRoot.java76
-rw-r--r--core/java/android/view/WindowManagerPolicy.java29
-rw-r--r--core/java/android/view/inputmethod/InputMethodSubtype.java23
-rw-r--r--core/java/android/webkit/SelectActionModeCallback.java4
-rw-r--r--core/java/android/webkit/WebView.java86
-rw-r--r--core/java/android/webkit/WebViewCore.java2
-rw-r--r--core/java/android/webkit/ZoomManager.java28
-rw-r--r--core/java/android/widget/NumberPicker.java1380
-rw-r--r--core/java/android/widget/NumberPickerButton.java96
-rw-r--r--core/java/android/widget/Switch.java631
-rw-r--r--core/java/android/widget/TextView.java268
-rw-r--r--core/java/android/widget/TimePicker.java94
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java21
-rw-r--r--core/jni/android_app_NativeActivity.cpp33
-rw-r--r--core/jni/android_database_CursorWindow.cpp14
-rw-r--r--core/jni/android_util_AssetManager.cpp2
-rw-r--r--core/jni/android_view_KeyEvent.cpp43
-rw-r--r--core/jni/android_view_KeyEvent.h16
-rw-r--r--core/jni/android_view_MotionEvent.cpp28
-rw-r--r--core/jni/android_view_MotionEvent.h14
-rw-r--r--core/jni/android_view_Surface.cpp84
-rw-r--r--core/res/res/drawable-hdpi/switch_bg_disabled_holo_dark.9.pngbin0 -> 235 bytes
-rw-r--r--core/res/res/drawable-hdpi/switch_bg_disabled_holo_light.9.pngbin0 -> 235 bytes
-rw-r--r--core/res/res/drawable-hdpi/switch_bg_focused_holo_dark.9.pngbin0 -> 273 bytes
-rw-r--r--core/res/res/drawable-hdpi/switch_bg_focused_holo_light.9.pngbin0 -> 275 bytes
-rw-r--r--core/res/res/drawable-hdpi/switch_bg_holo_dark.9.pngbin0 -> 211 bytes
-rw-r--r--core/res/res/drawable-hdpi/switch_bg_holo_light.9.pngbin0 -> 211 bytes
-rw-r--r--core/res/res/drawable-hdpi/switch_thumb_disabled_holo_dark.9.pngbin0 -> 387 bytes
-rw-r--r--core/res/res/drawable-hdpi/switch_thumb_disabled_holo_light.9.pngbin0 -> 408 bytes
-rw-r--r--core/res/res/drawable-hdpi/switch_thumb_holo_dark.9.pngbin0 -> 416 bytes
-rw-r--r--core/res/res/drawable-hdpi/switch_thumb_holo_light.9.pngbin0 -> 415 bytes
-rw-r--r--core/res/res/drawable-hdpi/switch_thumb_pressed_holo_dark.9.pngbin0 -> 652 bytes
-rw-r--r--core/res/res/drawable-hdpi/switch_thumb_pressed_holo_light.9.pngbin0 -> 664 bytes
-rw-r--r--core/res/res/drawable-mdpi/switch_bg_disabled_holo_dark.9.pngbin0 -> 210 bytes
-rw-r--r--core/res/res/drawable-mdpi/switch_bg_disabled_holo_light.9.pngbin0 -> 211 bytes
-rw-r--r--core/res/res/drawable-mdpi/switch_bg_focused_holo_dark.9.pngbin0 -> 215 bytes
-rw-r--r--core/res/res/drawable-mdpi/switch_bg_focused_holo_light.9.pngbin0 -> 217 bytes
-rw-r--r--core/res/res/drawable-mdpi/switch_bg_holo_dark.9.pngbin0 -> 186 bytes
-rw-r--r--core/res/res/drawable-mdpi/switch_bg_holo_light.9.pngbin0 -> 186 bytes
-rw-r--r--core/res/res/drawable-mdpi/switch_thumb_disabled_holo_dark.9.pngbin0 -> 303 bytes
-rw-r--r--core/res/res/drawable-mdpi/switch_thumb_disabled_holo_light.9.pngbin0 -> 318 bytes
-rw-r--r--core/res/res/drawable-mdpi/switch_thumb_holo_dark.9.pngbin0 -> 322 bytes
-rw-r--r--core/res/res/drawable-mdpi/switch_thumb_holo_light.9.pngbin0 -> 317 bytes
-rw-r--r--core/res/res/drawable-mdpi/switch_thumb_pressed_holo_dark.9.pngbin0 -> 453 bytes
-rw-r--r--core/res/res/drawable-mdpi/switch_thumb_pressed_holo_light.9.pngbin0 -> 517 bytes
-rw-r--r--core/res/res/drawable/switch_inner_holo_dark.xml21
-rw-r--r--core/res/res/drawable/switch_inner_holo_light.xml21
-rw-r--r--core/res/res/drawable/switch_track_holo_dark.xml21
-rw-r--r--core/res/res/drawable/switch_track_holo_light.xml21
-rw-r--r--core/res/res/drawable/timepicker_down_btn.xml31
-rw-r--r--core/res/res/drawable/timepicker_down_btn_holo_dark.xml43
-rw-r--r--core/res/res/drawable/timepicker_down_btn_holo_light.xml43
-rw-r--r--core/res/res/drawable/timepicker_input.xml31
-rw-r--r--core/res/res/drawable/timepicker_up_btn.xml31
-rw-r--r--core/res/res/drawable/timepicker_up_btn_holo_dark.xml43
-rw-r--r--core/res/res/drawable/timepicker_up_btn_holo_light.xml43
-rw-r--r--core/res/res/layout-xlarge/alert_dialog.xml4
-rw-r--r--core/res/res/layout-xlarge/alert_dialog_holo.xml4
-rw-r--r--core/res/res/layout/alert_dialog.xml3
-rw-r--r--core/res/res/layout/number_picker.xml21
-rw-r--r--core/res/res/layout/preference_list_content.xml2
-rw-r--r--core/res/res/layout/preference_list_fragment.xml6
-rw-r--r--core/res/res/layout/time_picker.xml40
-rw-r--r--core/res/res/values-ar/strings.xml5
-rw-r--r--core/res/res/values-bg/strings.xml5
-rw-r--r--core/res/res/values-ca/strings.xml5
-rw-r--r--core/res/res/values-cs/strings.xml5
-rw-r--r--core/res/res/values-da/strings.xml5
-rw-r--r--core/res/res/values-de/strings.xml5
-rw-r--r--core/res/res/values-el/strings.xml5
-rw-r--r--core/res/res/values-en-rGB/strings.xml5
-rw-r--r--core/res/res/values-es-rUS/strings.xml5
-rw-r--r--core/res/res/values-es/strings.xml5
-rw-r--r--core/res/res/values-fa/strings.xml5
-rw-r--r--core/res/res/values-fi/strings.xml5
-rw-r--r--core/res/res/values-fr/strings.xml5
-rw-r--r--core/res/res/values-he/strings.xml5
-rw-r--r--core/res/res/values-hr/strings.xml5
-rw-r--r--core/res/res/values-hu/strings.xml5
-rw-r--r--core/res/res/values-id/strings.xml5
-rw-r--r--core/res/res/values-it/strings.xml5
-rw-r--r--core/res/res/values-ja/strings.xml5
-rw-r--r--core/res/res/values-ko/strings.xml5
-rw-r--r--core/res/res/values-large/config.xml25
-rw-r--r--core/res/res/values-lt/strings.xml5
-rw-r--r--core/res/res/values-lv/strings.xml5
-rw-r--r--core/res/res/values-nb/strings.xml5
-rw-r--r--core/res/res/values-nl/strings.xml5
-rw-r--r--core/res/res/values-pl/strings.xml5
-rw-r--r--core/res/res/values-pt-rPT/strings.xml5
-rw-r--r--core/res/res/values-pt/strings.xml5
-rw-r--r--core/res/res/values-rm/strings.xml5
-rw-r--r--core/res/res/values-ro/strings.xml5
-rw-r--r--core/res/res/values-ru/strings.xml7
-rw-r--r--core/res/res/values-sk/strings.xml5
-rw-r--r--core/res/res/values-sl/strings.xml5
-rw-r--r--core/res/res/values-sr/strings.xml5
-rw-r--r--core/res/res/values-sv/strings.xml5
-rw-r--r--core/res/res/values-th/strings.xml5
-rw-r--r--core/res/res/values-tl/strings.xml5
-rw-r--r--core/res/res/values-tr/strings.xml5
-rw-r--r--core/res/res/values-uk/strings.xml5
-rw-r--r--core/res/res/values-vi/strings.xml5
-rw-r--r--core/res/res/values-xlarge/config.xml3
-rw-r--r--core/res/res/values-zh-rCN/strings.xml5
-rw-r--r--core/res/res/values-zh-rTW/strings.xml5
-rwxr-xr-xcore/res/res/values/attrs.xml86
-rw-r--r--core/res/res/values/config.xml5
-rw-r--r--core/res/res/values/donottranslate.xml2
-rw-r--r--core/res/res/values/public.xml10
-rwxr-xr-xcore/res/res/values/strings.xml4
-rw-r--r--core/res/res/values/styles.xml90
-rw-r--r--core/res/res/values/themes.xml21
-rw-r--r--data/keyboards/Apple_Wireless_Keyboard.kl119
-rw-r--r--data/keyboards/Generic.kl12
-rw-r--r--data/keyboards/Logitech_USB_Receiver.kl133
-rw-r--r--data/keyboards/Motorola_Bluetooth_Wireless_Keyboard.kcm370
-rw-r--r--data/keyboards/Motorola_Bluetooth_Wireless_Keyboard.kl6
-rw-r--r--data/keyboards/common.mk7
-rw-r--r--data/keyboards/qwerty.kcm4
-rw-r--r--data/sounds/notifications/alert01.oggbin0 -> 16012 bytes
-rw-r--r--data/sounds/notifications/alert02.oggbin0 -> 23206 bytes
-rw-r--r--data/sounds/notifications/alert03.oggbin0 -> 14067 bytes
-rw-r--r--data/sounds/notifications/alert04.oggbin0 -> 18321 bytes
-rw-r--r--data/sounds/notifications/alert05.oggbin0 -> 18810 bytes
-rw-r--r--data/sounds/notifications/alert06.oggbin0 -> 12620 bytes
-rw-r--r--data/sounds/notifications/alert07.oggbin0 -> 9508 bytes
-rw-r--r--data/sounds/notifications/alert08.oggbin0 -> 14648 bytes
-rw-r--r--data/sounds/notifications/alert09.oggbin0 -> 16418 bytes
-rw-r--r--data/sounds/notifications/alert10.oggbin0 -> 15763 bytes
-rw-r--r--data/sounds/notifications/alert11.oggbin0 -> 10444 bytes
-rw-r--r--data/sounds/notifications/alert12.oggbin0 -> 19290 bytes
-rw-r--r--data/sounds/notifications/alert13.oggbin0 -> 19913 bytes
-rw-r--r--data/sounds/notifications/alert14.oggbin0 -> 34378 bytes
-rw-r--r--data/sounds/notifications/alert15.oggbin0 -> 18239 bytes
-rw-r--r--data/sounds/ringtones/ringtone18.oggbin0 -> 214887 bytes
-rw-r--r--data/sounds/ringtones/ringtone19.oggbin0 -> 118444 bytes
-rw-r--r--data/sounds/ringtones/ringtone20.oggbin0 -> 53191 bytes
-rw-r--r--data/sounds/ringtones/ringtone21.oggbin0 -> 75013 bytes
-rw-r--r--data/sounds/ringtones/ringtone22.oggbin0 -> 102024 bytes
-rw-r--r--data/sounds/ringtones/ringtone23.oggbin0 -> 80588 bytes
-rw-r--r--data/sounds/ringtones/ringtone24.oggbin0 -> 104820 bytes
-rw-r--r--data/sounds/ringtones/ringtone25.oggbin0 -> 131029 bytes
-rw-r--r--data/sounds/ringtones/ringtone26.oggbin0 -> 97565 bytes
-rw-r--r--data/sounds/ringtones/ringtone27.oggbin0 -> 88468 bytes
-rw-r--r--data/sounds/ringtones/ringtone28.oggbin0 -> 121949 bytes
-rw-r--r--data/sounds/ringtones/ringtone29.oggbin0 -> 110062 bytes
-rw-r--r--data/sounds/ringtones/ringtone30.oggbin0 -> 113368 bytes
-rw-r--r--data/sounds/ringtones/ringtone31.oggbin0 -> 97936 bytes
-rw-r--r--data/sounds/ringtones/ringtone32.oggbin0 -> 175983 bytes
-rw-r--r--data/sounds/ringtones/ringtone33.oggbin0 -> 63250 bytes
-rw-r--r--data/sounds/ringtones/ringtone34.oggbin0 -> 60727 bytes
-rw-r--r--data/sounds/ringtones/ringtone35.oggbin0 -> 163844 bytes
-rw-r--r--data/sounds/ringtones/ringtone36.oggbin0 -> 40589 bytes
-rw-r--r--data/sounds/ringtones/ringtone37.oggbin0 -> 145806 bytes
-rw-r--r--data/sounds/ringtones/ringtone38.oggbin0 -> 126162 bytes
-rw-r--r--docs/html/guide/topics/ui/actionbar.jd363
-rw-r--r--docs/html/images/preview_hc/actionbar.pngbin0 -> 29116 bytes
-rw-r--r--docs/html/images/preview_hc/fragments_layout.pngbin0 -> 118190 bytes
-rw-r--r--docs/html/images/ui/actionbar-actionview.pngbin0 -> 2503 bytes
-rw-r--r--docs/html/sdk/index.jd2
-rw-r--r--docs/html/sdk/preview/features.jd185
-rw-r--r--docs/html/sdk/preview/installing.jd61
-rw-r--r--docs/html/sdk/sdk_toc.cs11
-rw-r--r--include/ui/EventHub.h8
-rw-r--r--include/ui/Input.h16
-rw-r--r--include/ui/InputDispatcher.h7
-rw-r--r--include/ui/InputReader.h72
-rw-r--r--include/ui/Keyboard.h9
-rw-r--r--include/utils/PropertyMap.h100
-rw-r--r--libs/binder/CursorWindow.cpp6
-rw-r--r--libs/hwui/Line.h5
-rw-r--r--libs/hwui/OpenGLRenderer.cpp3
-rw-r--r--libs/hwui/Patch.cpp105
-rw-r--r--libs/hwui/Patch.h74
-rw-r--r--libs/hwui/PatchCache.cpp8
-rw-r--r--libs/hwui/PatchCache.h57
-rw-r--r--libs/rs/rsScriptC.h6
-rw-r--r--libs/ui/EventHub.cpp47
-rw-r--r--libs/ui/Input.cpp79
-rw-r--r--libs/ui/InputDispatcher.cpp49
-rw-r--r--libs/ui/InputReader.cpp231
-rw-r--r--libs/ui/Keyboard.cpp137
-rw-r--r--libs/ui/tests/InputDispatcher_test.cpp4
-rw-r--r--libs/ui/tests/InputReader_test.cpp213
-rw-r--r--libs/utils/Android.mk1
-rw-r--r--libs/utils/PropertyMap.cpp212
-rw-r--r--media/java/android/media/MtpDatabase.java7
-rw-r--r--media/libmedia/Visualizer.cpp8
-rw-r--r--media/mtp/MtpDataPacket.cpp1
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java33
-rw-r--r--opengl/tests/hwc/Android.mk27
-rw-r--r--opengl/tests/hwc/hwc_stress.cpp1193
-rw-r--r--packages/SystemUI/res/layout-xlarge/status_bar.xml16
-rw-r--r--packages/SystemUI/res/layout-xlarge/status_bar_notification_panel.xml14
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml11
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml11
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml11
-rw-r--r--packages/SystemUI/res/values-cs-xlarge/strings.xml31
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml11
-rw-r--r--packages/SystemUI/res/values-da-xlarge/strings.xml31
-rw-r--r--packages/SystemUI/res/values-da/strings.xml11
-rw-r--r--packages/SystemUI/res/values-de-xlarge/strings.xml31
-rw-r--r--packages/SystemUI/res/values-de/strings.xml11
-rw-r--r--packages/SystemUI/res/values-el-xlarge/strings.xml31
-rw-r--r--packages/SystemUI/res/values-el/strings.xml11
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml11
-rw-r--r--packages/SystemUI/res/values-es-rUS-xlarge/strings.xml31
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml12
-rw-r--r--packages/SystemUI/res/values-es-xlarge/strings.xml31
-rw-r--r--packages/SystemUI/res/values-es/strings.xml11
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml11
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml11
-rw-r--r--packages/SystemUI/res/values-fr-xlarge/strings.xml31
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml11
-rw-r--r--packages/SystemUI/res/values-he/strings.xml11
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml11
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml11
-rw-r--r--packages/SystemUI/res/values-id/strings.xml11
-rw-r--r--packages/SystemUI/res/values-it-xlarge/strings.xml31
-rw-r--r--packages/SystemUI/res/values-it/strings.xml11
-rw-r--r--packages/SystemUI/res/values-ja-xlarge/strings.xml31
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml11
-rw-r--r--packages/SystemUI/res/values-ko-xlarge/strings.xml31
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml11
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml11
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml11
-rw-r--r--packages/SystemUI/res/values-nb-xlarge/strings.xml31
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml11
-rw-r--r--packages/SystemUI/res/values-nl-xlarge/strings.xml31
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml11
-rw-r--r--packages/SystemUI/res/values-pl-xlarge/strings.xml31
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml11
-rw-r--r--packages/SystemUI/res/values-pt-rPT-xlarge/strings.xml31
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml11
-rw-r--r--packages/SystemUI/res/values-pt-xlarge/strings.xml31
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml11
-rw-r--r--packages/SystemUI/res/values-rm/strings.xml11
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml11
-rw-r--r--packages/SystemUI/res/values-ru-xlarge/strings.xml31
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml11
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml11
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml11
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml11
-rw-r--r--packages/SystemUI/res/values-sv-xlarge/strings.xml31
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml11
-rw-r--r--packages/SystemUI/res/values-th/strings.xml11
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml11
-rw-r--r--packages/SystemUI/res/values-tr-xlarge/strings.xml31
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml11
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml11
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml11
-rw-r--r--packages/SystemUI/res/values-zh-rCN-xlarge/strings.xml31
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml11
-rw-r--r--packages/SystemUI/res/values-zh-rTW-xlarge/strings.xml31
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/DoNotDisturb.java60
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/DoNotDisturbController.java77
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java36
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java22
-rw-r--r--policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java9
-rw-r--r--policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java7
-rwxr-xr-xpolicy/src/com/android/internal/policy/impl/PhoneWindowManager.java40
-rw-r--r--policy/src/com/android/internal/policy/impl/ShortcutManager.java14
-rw-r--r--services/camera/libcameraservice/CameraService.cpp4
-rw-r--r--services/java/com/android/server/BackupManagerService.java39
-rw-r--r--services/java/com/android/server/DevicePolicyManagerService.java53
-rw-r--r--services/java/com/android/server/InputManager.java57
-rw-r--r--services/java/com/android/server/InputMethodManagerService.java36
-rwxr-xr-xservices/java/com/android/server/NotificationManagerService.java5
-rw-r--r--services/java/com/android/server/WindowManagerService.java23
-rw-r--r--services/jni/com_android_server_InputManager.cpp180
-rw-r--r--telephony/java/com/android/internal/telephony/DataConnectionTracker.java37
-rw-r--r--telephony/java/com/android/internal/telephony/Phone.java30
-rw-r--r--telephony/java/com/android/internal/telephony/PhoneBase.java4
-rw-r--r--telephony/java/com/android/internal/telephony/PhoneProxy.java12
-rwxr-xr-xtelephony/java/com/android/internal/telephony/cdma/CDMAPhone.java21
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java5
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java4
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GSMPhone.java8
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java4
-rwxr-xr-xtelephony/java/com/android/internal/telephony/sip/SipPhone.java3
-rw-r--r--tests/DumpRenderTree2/src/com/android/dumprendertree2/FsUtils.java37
-rw-r--r--tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecutor.java12
-rw-r--r--tests/DumpRenderTree2/src/com/android/dumprendertree2/TestsListActivity.java13
-rw-r--r--tests/StatusBar/res/layout/progress_notification.xml22
-rw-r--r--tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java48
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java54
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java22
-rw-r--r--tools/layoutlib/bridge/src/android/os/Handler_Delegate.java54
-rw-r--r--tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java66
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java81
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeLayoutScene.java38
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java35
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/AnimationThread.java121
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java252
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java2
-rw-r--r--voip/java/android/net/sip/SipManager.java18
-rw-r--r--voip/java/com/android/server/sip/SipService.java24
-rw-r--r--voip/java/com/android/server/sip/SipSessionGroup.java1
-rw-r--r--voip/jni/rtp/EchoSuppressor.cpp21
319 files changed, 8296 insertions, 3020 deletions
diff --git a/Android.mk b/Android.mk
index 4c135da..4e286db 100644
--- a/Android.mk
+++ b/Android.mk
@@ -395,6 +395,8 @@ web_docs_sample_code_flags := \
resources/samples/AccessibilityService "Accessibility Service" \
-samplecode $(sample_dir)/ApiDemos \
resources/samples/ApiDemos "API Demos" \
+ -samplecode $(sample_dir)/AccelerometerPlay \
+ resources/samples/AccelerometerPlay "Accelerometer Play" \
-samplecode $(sample_dir)/BackupRestore \
resources/samples/BackupRestore "Backup and Restore" \
-samplecode $(sample_dir)/BluetoothChat \
@@ -407,8 +409,6 @@ web_docs_sample_code_flags := \
resources/samples/CubeLiveWallpaper "Live Wallpaper" \
-samplecode $(sample_dir)/Home \
resources/samples/Home "Home" \
- -samplecode $(sample_dir)/HeavyWeight \
- resources/samples/HeavyWeight "Heavy Weight App" \
-samplecode $(sample_dir)/JetBoy \
resources/samples/JetBoy "JetBoy" \
-samplecode $(sample_dir)/LunarLander \
@@ -449,12 +449,12 @@ web_docs_sample_code_flags := \
framework_docs_SDK_VERSION:=2.3
# release version (ie "Release x") (full releases only)
framework_docs_SDK_REL_ID:=1
- # flag to build offline docs for a preview release
-framework_docs_SDK_PREVIEW:=0
framework_docs_LOCAL_DROIDDOC_OPTIONS += \
-hdf sdk.version $(framework_docs_SDK_VERSION) \
- -hdf sdk.rel.id $(framework_docs_SDK_REL_ID)
+ -hdf sdk.rel.id $(framework_docs_SDK_REL_ID) \
+ -hdf sdk.preview true \
+ -hdf sdk.preview.version Honeycomb
# ==== the api stubs and current.xml ===========================
include $(CLEAR_VARS)
@@ -540,9 +540,6 @@ LOCAL_DROIDDOC_OPTIONS:=\
-sdkvalues $(OUT_DOCS) \
-hdf android.whichdoc offline
-ifeq ($(framework_docs_SDK_PREVIEW),true)
- LOCAL_DROIDDOC_OPTIONS += -hdf sdk.preview true
-endif
LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
diff --git a/api/current.xml b/api/current.xml
index b62c689..87394ce 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -2176,6 +2176,17 @@
visibility="public"
>
</field>
+<field name="alpha"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843568"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="alphabeticShortcut"
type="int"
transient="false"
@@ -7720,6 +7731,39 @@
visibility="public"
>
</field>
+<field name="rotation"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843575"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="rotationX"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843576"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="rotationY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843577"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="rowDelay"
type="int"
transient="false"
@@ -7808,6 +7852,28 @@
visibility="public"
>
</field>
+<field name="scaleX"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843573"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="scaleY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843574"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="scheme"
type="int"
transient="false"
@@ -9953,6 +10019,50 @@
visibility="public"
>
</field>
+<field name="transformPivotX"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843569"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="transformPivotY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843570"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="translationX"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843571"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="translationY"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843572"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="type"
type="int"
transient="false"
@@ -61579,6 +61689,19 @@
<parameter name="that" type="android.content.res.Configuration">
</parameter>
</method>
+<method name="isLayoutSizeAtLeast"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="size" type="int">
+</parameter>
+</method>
<method name="needNewResources"
return="boolean"
abstract="false"
@@ -185487,7 +185610,7 @@
>
<parameter name="cap" type="android.text.method.TextKeyListener.Capitalize">
</parameter>
-<parameter name="autotext" type="boolean">
+<parameter name="autoText" type="boolean">
</parameter>
</constructor>
<method name="getInputType"
@@ -185511,11 +185634,22 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="autotext" type="boolean">
+<parameter name="autoText" type="boolean">
</parameter>
<parameter name="cap" type="android.text.method.TextKeyListener.Capitalize">
</parameter>
</method>
+<method name="getInstanceForFullKeyboard"
+ return="android.text.method.QwertyKeyListener"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="markAsReplaced"
return="void"
abstract="false"
@@ -196541,7 +196675,7 @@
value="0"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -249201,7 +249335,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="t" type="T">
+<parameter name="arg0" type="T">
</parameter>
</method>
</interface>
diff --git a/cmds/rawbu/backup.cpp b/cmds/rawbu/backup.cpp
index c4fa765..9ea046d 100644
--- a/cmds/rawbu/backup.cpp
+++ b/cmds/rawbu/backup.cpp
@@ -14,6 +14,7 @@
#include <utime.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <stdint.h>
#include <cutils/properties.h>
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index e192067..8e541c2 100755
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -1072,12 +1072,11 @@ public class ValueAnimator extends Animator {
mListeners.get(i).onAnimationRepeat(this);
}
}
- ++mCurrentIteration;
if (mRepeatMode == REVERSE) {
mPlayingBackwards = mPlayingBackwards ? false : true;
}
- // TODO: doesn't account for fraction going Wayyyyy over 1, like 2+
- fraction = fraction - 1f;
+ mCurrentIteration += (int)fraction;
+ fraction = fraction % 1f;
mStartTime += mDuration;
} else {
done = true;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 5c4f57a..c0714e3 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -870,12 +870,6 @@ public final class ActivityThread {
(dbStats.dbSize > 0) ? String.valueOf(dbStats.dbSize) : " ",
(dbStats.lookaside > 0) ? String.valueOf(dbStats.lookaside) : " ",
dbStats.cache, dbStats.dbName);
- if (dbStats.dataDump != null) {
- int size = dbStats.dataDump.size();
- for (int dumpIndex = 0; dumpIndex < size; dumpIndex++) {
- printRow(pw, "%s", dbStats.dataDump.get(dumpIndex));
- }
- }
}
}
diff --git a/core/java/android/app/TimePickerDialog.java b/core/java/android/app/TimePickerDialog.java
index 381143c..26af4eb 100644
--- a/core/java/android/app/TimePickerDialog.java
+++ b/core/java/android/app/TimePickerDialog.java
@@ -16,29 +16,26 @@
package android.app;
+import com.android.internal.R;
+
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.os.Build;
import android.os.Bundle;
-import android.text.format.DateFormat;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TimePicker;
import android.widget.TimePicker.OnTimeChangedListener;
-import com.android.internal.R;
-
-import java.util.Calendar;
-
/**
* A dialog that prompts the user for the time of day using a {@link TimePicker}.
*
* <p>See the <a href="{@docRoot}resources/tutorials/views/hello-timepicker.html">Time Picker
* tutorial</a>.</p>
*/
-public class TimePickerDialog extends AlertDialog implements OnClickListener,
- OnTimeChangedListener {
+public class TimePickerDialog extends AlertDialog
+ implements OnClickListener, OnTimeChangedListener {
/**
* The callback interface used to indicate the user is done filling in
@@ -60,8 +57,6 @@ public class TimePickerDialog extends AlertDialog implements OnClickListener,
private final TimePicker mTimePicker;
private final OnTimeSetListener mCallback;
- private final Calendar mCalendar;
- private final java.text.DateFormat mDateFormat;
int mInitialHourOfDay;
int mInitialMinute;
@@ -102,14 +97,13 @@ public class TimePickerDialog extends AlertDialog implements OnClickListener,
mInitialMinute = minute;
mIs24HourView = is24HourView;
- mDateFormat = DateFormat.getTimeFormat(context);
- mCalendar = Calendar.getInstance();
- updateTitle(mInitialHourOfDay, mInitialMinute);
+ setCanceledOnTouchOutside(false);
+ setIcon(0);
+ setTitle(R.string.time_picker_dialog_title);
setButton(BUTTON_POSITIVE, context.getText(R.string.date_time_set), this);
setButton(BUTTON_NEGATIVE, context.getText(R.string.cancel),
(OnClickListener) null);
- setIcon(R.drawable.ic_dialog_time);
LayoutInflater inflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
@@ -132,19 +126,13 @@ public class TimePickerDialog extends AlertDialog implements OnClickListener,
}
}
- public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
- updateTitle(hourOfDay, minute);
- }
-
public void updateTime(int hourOfDay, int minutOfHour) {
mTimePicker.setCurrentHour(hourOfDay);
mTimePicker.setCurrentMinute(minutOfHour);
}
- private void updateTitle(int hour, int minute) {
- mCalendar.set(Calendar.HOUR_OF_DAY, hour);
- mCalendar.set(Calendar.MINUTE, minute);
- setTitle(mDateFormat.format(mCalendar.getTime()));
+ public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
+ /* do nothing */
}
@Override
@@ -164,7 +152,5 @@ public class TimePickerDialog extends AlertDialog implements OnClickListener,
mTimePicker.setCurrentHour(hour);
mTimePicker.setCurrentMinute(minute);
mTimePicker.setIs24HourView(savedInstanceState.getBoolean(IS_24_HOUR));
- mTimePicker.setOnTimeChangedListener(this);
- updateTitle(hour, minute);
}
}
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index 2f110f0..31119d7 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -91,6 +91,22 @@ public final class Configuration implements Parcelable, Comparable<Configuration
*/
public int screenLayout;
+ /**
+ * Check if the Configuration's current {@link #screenLayout} is at
+ * least the given size.
+ *
+ * @param size The desired size, either {@link #SCREENLAYOUT_SIZE_SMALL},
+ * {@link #SCREENLAYOUT_SIZE_NORMAL}, {@link #SCREENLAYOUT_SIZE_LARGE}, or
+ * {@link #SCREENLAYOUT_SIZE_XLARGE}.
+ * @return Returns true if the current screen layout size is at least
+ * the given size.
+ */
+ public boolean isLayoutSizeAtLeast(int size) {
+ int cur = screenLayout&SCREENLAYOUT_SIZE_MASK;
+ if (cur == SCREENLAYOUT_SIZE_UNDEFINED) return false;
+ return cur >= size;
+ }
+
public static final int TOUCHSCREEN_UNDEFINED = 0;
public static final int TOUCHSCREEN_NOTOUCH = 1;
public static final int TOUCHSCREEN_STYLUS = 2;
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index 87f55d2..184988b 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -1122,11 +1122,11 @@ public class SQLiteDatabase extends SQLiteClosable {
Map.Entry<SQLiteClosable, Object> entry = iter.next();
SQLiteClosable program = entry.getKey();
if (program != null && program instanceof SQLiteProgram) {
- SQLiteCompiledSql compiledSql = ((SQLiteProgram)program).mCompiledSql;
- if (compiledSql.nStatement == stmtId) {
- msg = compiledSql.toString();
- found = true;
- }
+ SQLiteCompiledSql compiledSql = ((SQLiteProgram)program).mCompiledSql;
+ if (compiledSql.nStatement == stmtId) {
+ msg = compiledSql.toString();
+ found = true;
+ }
}
}
if (!found) {
@@ -1140,8 +1140,9 @@ public class SQLiteDatabase extends SQLiteClosable {
}
} else {
// the statement is not yet closed. most probably programming error in the app.
- Log.w(TAG, "dbclose failed due to un-close()d SQL statements: " + msg);
- throw e;
+ throw new SQLiteUnfinalizedObjectsException(
+ "close() on database: " + getPath() +
+ " failed due to un-close()d SQL statements: " + msg);
}
}
}
@@ -2507,7 +2508,7 @@ public class SQLiteDatabase extends SQLiteClosable {
if (pageCount > 0) {
dbStatsList.add(new DbStats(dbName, pageCount, db.getPageSize(),
lookasideUsed, db.getCacheHitNum(), db.getCacheMissNum(),
- db.getCachesize(), getDataDump(db)));
+ db.getCachesize()));
}
}
// if there are pooled connections, return the cache stats for them also.
@@ -2518,7 +2519,7 @@ public class SQLiteDatabase extends SQLiteClosable {
for (SQLiteDatabase pDb : connPool.getConnectionList()) {
dbStatsList.add(new DbStats("(pooled # " + pDb.mConnectionNum + ") "
+ lastnode, 0, 0, 0, pDb.getCacheHitNum(),
- pDb.getCacheMissNum(), pDb.getCachesize(), null));
+ pDb.getCacheMissNum(), pDb.getCachesize()));
}
}
} catch (SQLiteException e) {
@@ -2529,44 +2530,6 @@ public class SQLiteDatabase extends SQLiteClosable {
return dbStatsList;
}
- private static ArrayList<String> getDataDump(SQLiteDatabase db) {
- // create database dump of certain data from certain databases for debugging purposes
- if (db.getPath().equalsIgnoreCase(
- "/data/data/com.android.providers.downloads/databases/downloads.db")) {
- String sql =
- "select * from downloads " +
- " where notificationpackage = 'com.google.android.gsf'" +
- " or status >= 400";
- Cursor cursor = db.rawQuery(sql, null);
- try {
- int count = cursor.getCount();
- if (count == 0) {
- return null;
- }
- ArrayList<String> buff = new ArrayList<String>();
- buff.add(" Data from downloads.db");
- int columnCount = cursor.getColumnCount();
- for (int i =0; i < count && cursor.moveToNext(); i++) {
- buff.add(" Row#" + i + "");
- for (int j = 0; j < columnCount; j++) {
- String colName = cursor.getColumnName(j);
- String value = cursor.getString(j);
- buff.add(" " + colName + " = " + value);
- }
- }
- for (String s : buff) Log.i("vnoritag", s);
- return buff;
- } catch (SQLiteException e) {
- Log.w(TAG, "exception in executing the sql: " + sql, e);
- } finally {
- if (cursor != null) {
- cursor.close();
- }
- }
- }
- return null;
- }
-
/**
* Returns list of full pathnames of all attached databases including the main database
* by executing 'pragma database_list' on the database.
diff --git a/core/java/android/database/sqlite/SQLiteDebug.java b/core/java/android/database/sqlite/SQLiteDebug.java
index 72377f0..9496079 100644
--- a/core/java/android/database/sqlite/SQLiteDebug.java
+++ b/core/java/android/database/sqlite/SQLiteDebug.java
@@ -121,31 +121,27 @@ public final class SQLiteDebug {
*/
public static class DbStats {
/** name of the database */
- public final String dbName;
+ public String dbName;
/** the page size for the database */
- public final long pageSize;
+ public long pageSize;
/** the database size */
- public final long dbSize;
+ public long dbSize;
/** documented here http://www.sqlite.org/c3ref/c_dbstatus_lookaside_used.html */
- public final int lookaside;
+ public int lookaside;
/** statement cache stats: hits/misses/cachesize */
- public final String cache;
-
- /** database dump of 'useful info for debugging only */
- public final ArrayList<String> dataDump;
+ public String cache;
public DbStats(String dbName, long pageCount, long pageSize, int lookaside,
- int hits, int misses, int cachesize, ArrayList<String> data) {
+ int hits, int misses, int cachesize) {
this.dbName = dbName;
this.pageSize = pageSize / 1024;
dbSize = (pageCount * pageSize) / 1024;
this.lookaside = lookaside;
this.cache = hits + "/" + misses + "/" + cachesize;
- this.dataDump = data;
}
}
diff --git a/core/java/android/preference/PreferenceFrameLayout.java b/core/java/android/preference/PreferenceFrameLayout.java
index 481859e..f6d01d3 100644
--- a/core/java/android/preference/PreferenceFrameLayout.java
+++ b/core/java/android/preference/PreferenceFrameLayout.java
@@ -20,16 +20,22 @@ import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
+import android.view.ViewGroup.MarginLayoutParams;
import android.widget.FrameLayout;
+import android.widget.FrameLayout.LayoutParams;
/**
* @hide
*/
public class PreferenceFrameLayout extends FrameLayout {
- private static final int DEFAULT_TOP_PADDING = 0;
- private static final int DEFAULT_BOTTOM_PADDING = 0;
- private final int mTopPadding;
- private final int mBottomPadding;
+ private static final int DEFAULT_BORDER_TOP = 0;
+ private static final int DEFAULT_BORDER_BOTTOM = 0;
+ private static final int DEFAULT_BORDER_LEFT = 0;
+ private static final int DEFAULT_BORDER_RIGHT = 0;
+ private final int mBorderTop;
+ private final int mBorderBottom;
+ private final int mBorderLeft;
+ private final int mBorderRight;
private boolean mPaddingApplied = false;
public PreferenceFrameLayout(Context context) {
@@ -46,45 +52,98 @@ public class PreferenceFrameLayout extends FrameLayout {
com.android.internal.R.styleable.PreferenceFrameLayout, defStyle, 0);
float density = context.getResources().getDisplayMetrics().density;
- int defaultTopPadding = (int) (density * DEFAULT_TOP_PADDING + 0.5f);
- int defaultBottomPadding = (int) (density * DEFAULT_BOTTOM_PADDING + 0.5f);
-
- mTopPadding = a.getDimensionPixelSize(
- com.android.internal.R.styleable.PreferenceFrameLayout_topPadding,
- defaultTopPadding);
- mBottomPadding = a.getDimensionPixelSize(
- com.android.internal.R.styleable.PreferenceFrameLayout_bottomPadding,
- defaultBottomPadding);
+ int defaultBorderTop = (int) (density * DEFAULT_BORDER_TOP + 0.5f);
+ int defaultBottomPadding = (int) (density * DEFAULT_BORDER_BOTTOM + 0.5f);
+ int defaultLeftPadding = (int) (density * DEFAULT_BORDER_LEFT + 0.5f);
+ int defaultRightPadding = (int) (density * DEFAULT_BORDER_RIGHT + 0.5f);
+ mBorderTop = a.getDimensionPixelSize(
+ com.android.internal.R.styleable.PreferenceFrameLayout_borderTop,
+ defaultBorderTop);
+ mBorderBottom = a.getDimensionPixelSize(
+ com.android.internal.R.styleable.PreferenceFrameLayout_borderBottom,
+ defaultBottomPadding);
+ mBorderLeft = a.getDimensionPixelSize(
+ com.android.internal.R.styleable.PreferenceFrameLayout_borderLeft,
+ defaultLeftPadding);
+ mBorderRight = a.getDimensionPixelSize(
+ com.android.internal.R.styleable.PreferenceFrameLayout_borderRight,
+ defaultRightPadding);
a.recycle();
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public LayoutParams generateLayoutParams(AttributeSet attrs) {
+ return new LayoutParams(getContext(), attrs);
+ }
+
@Override
public void addView(View child) {
- int topPadding = getPaddingTop();
- int bottomPadding = getPaddingBottom();
+ int borderTop = getPaddingTop();
+ int borderBottom = getPaddingBottom();
+ int borderLeft = getPaddingLeft();
+ int borderRight = getPaddingRight();
+
+ LayoutParams layoutParams = (PreferenceFrameLayout.LayoutParams) child.getLayoutParams();
// Check on the id of the child before adding it.
- if (child != null && child.getId() != com.android.internal.R.id.default_preference_layout) {
- // Add the padding to the view group after determining if the padding already exists.
- if (!mPaddingApplied) {
- topPadding += mTopPadding;
- bottomPadding += mBottomPadding;
- mPaddingApplied = true;
- }
- } else {
+ if (layoutParams != null && layoutParams.removeBorders) {
if (mPaddingApplied) {
- topPadding -= mTopPadding;
- bottomPadding -= mBottomPadding;
+ borderTop -= mBorderTop;
+ borderBottom -= mBorderBottom;
+ borderLeft -= mBorderLeft;
+ borderRight -= mBorderRight;
mPaddingApplied = false;
}
+ } else {
+ // Add the padding to the view group after determining if the
+ // padding already exists.
+ if (!mPaddingApplied) {
+ borderTop += mBorderTop;
+ borderBottom += mBorderBottom;
+ borderLeft += mBorderLeft;
+ borderRight += mBorderRight;
+ mPaddingApplied = true;
+ }
}
+
int previousTop = getPaddingTop();
int previousBottom = getPaddingBottom();
- if (previousTop != topPadding || previousBottom != bottomPadding) {
- setPadding(getPaddingLeft(), topPadding, getPaddingRight(), bottomPadding);
+ int previousLeft = getPaddingLeft();
+ int previousRight = getPaddingRight();
+ if (previousTop != borderTop || previousBottom != borderBottom
+ || previousLeft != borderLeft || previousRight != borderRight) {
+ setPadding(borderLeft, borderTop, borderRight, borderBottom);
}
+
super.addView(child);
}
+
+ public static class LayoutParams extends FrameLayout.LayoutParams {
+ public boolean removeBorders = false;
+ /**
+ * {@inheritDoc}
+ */
+ public LayoutParams(Context c, AttributeSet attrs) {
+ super(c, attrs);
+
+ TypedArray a = c.obtainStyledAttributes(attrs,
+ com.android.internal.R.styleable.PreferenceFrameLayout_Layout);
+ removeBorders = a.getBoolean(
+ com.android.internal.R.styleable.PreferenceFrameLayout_Layout_layout_removeBorders,
+ false);
+ a.recycle();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public LayoutParams(int width, int height) {
+ super(width, height);
+ }
+ }
} \ No newline at end of file
diff --git a/core/java/android/text/method/QwertyKeyListener.java b/core/java/android/text/method/QwertyKeyListener.java
index 3308172..09388c0 100644
--- a/core/java/android/text/method/QwertyKeyListener.java
+++ b/core/java/android/text/method/QwertyKeyListener.java
@@ -31,27 +31,48 @@ import android.view.View;
public class QwertyKeyListener extends BaseKeyListener {
private static QwertyKeyListener[] sInstance =
new QwertyKeyListener[Capitalize.values().length * 2];
+ private static QwertyKeyListener sFullKeyboardInstance;
- public QwertyKeyListener(Capitalize cap, boolean autotext) {
+ private Capitalize mAutoCap;
+ private boolean mAutoText;
+ private boolean mFullKeyboard;
+
+ private QwertyKeyListener(Capitalize cap, boolean autoText, boolean fullKeyboard) {
mAutoCap = cap;
- mAutoText = autotext;
+ mAutoText = autoText;
+ mFullKeyboard = fullKeyboard;
+ }
+
+ public QwertyKeyListener(Capitalize cap, boolean autoText) {
+ this(cap, autoText, false);
}
/**
* Returns a new or existing instance with the specified capitalization
* and correction properties.
*/
- public static QwertyKeyListener getInstance(boolean autotext,
- Capitalize cap) {
- int off = cap.ordinal() * 2 + (autotext ? 1 : 0);
+ public static QwertyKeyListener getInstance(boolean autoText, Capitalize cap) {
+ int off = cap.ordinal() * 2 + (autoText ? 1 : 0);
if (sInstance[off] == null) {
- sInstance[off] = new QwertyKeyListener(cap, autotext);
+ sInstance[off] = new QwertyKeyListener(cap, autoText);
}
return sInstance[off];
}
+ /**
+ * Gets an instance of the listener suitable for use with full keyboards.
+ * Disables auto-capitalization, auto-text and long-press initiated on-screen
+ * character pickers.
+ */
+ public static QwertyKeyListener getInstanceForFullKeyboard() {
+ if (sFullKeyboardInstance == null) {
+ sFullKeyboardInstance = new QwertyKeyListener(Capitalize.NONE, false, true);
+ }
+ return sFullKeyboardInstance;
+ }
+
public int getInputType() {
return makeTextContentType(mAutoCap, mAutoText);
}
@@ -85,14 +106,16 @@ public class QwertyKeyListener extends BaseKeyListener {
int i = event.getUnicodeChar(event.getMetaState() | getMetaState(content));
- int count = event.getRepeatCount();
- if (count > 0 && selStart == selEnd && selStart > 0) {
- char c = content.charAt(selStart - 1);
+ if (!mFullKeyboard) {
+ int count = event.getRepeatCount();
+ if (count > 0 && selStart == selEnd && selStart > 0) {
+ char c = content.charAt(selStart - 1);
- if (c == i || c == Character.toUpperCase(i) && view != null) {
- if (showCharacterPicker(view, content, c, false, count)) {
- resetMetaState(content);
- return true;
+ if (c == i || c == Character.toUpperCase(i) && view != null) {
+ if (showCharacterPicker(view, content, c, false, count)) {
+ resetMetaState(content);
+ return true;
+ }
}
}
}
@@ -490,8 +513,5 @@ public class QwertyKeyListener extends BaseKeyListener {
private char[] mText;
}
-
- private Capitalize mAutoCap;
- private boolean mAutoText;
}
diff --git a/core/java/android/text/method/TextKeyListener.java b/core/java/android/text/method/TextKeyListener.java
index 8ad6f50..8312fe1 100644
--- a/core/java/android/text/method/TextKeyListener.java
+++ b/core/java/android/text/method/TextKeyListener.java
@@ -189,7 +189,12 @@ public class TextKeyListener extends BaseKeyListener implements SpanWatcher {
return MultiTapKeyListener.getInstance(mAutoText, mAutoCap);
} else if (kind == KeyCharacterMap.FULL
|| kind == KeyCharacterMap.SPECIAL_FUNCTION) {
- return QwertyKeyListener.getInstance(false, Capitalize.NONE);
+ // We consider special function keyboards full keyboards as a workaround for
+ // devices that do not have built-in keyboards. Applications may try to inject
+ // key events using the built-in keyboard device id which may be configured as
+ // a special function keyboard using a default key map. Ideally, as of Honeycomb,
+ // these applications should be modified to use KeyCharacterMap.VIRTUAL_KEYBOARD.
+ return QwertyKeyListener.getInstanceForFullKeyboard();
}
return NullKeyListener.getInstance();
diff --git a/core/java/android/view/KeyCharacterMap.java b/core/java/android/view/KeyCharacterMap.java
index fbd9eac..d330cca 100644
--- a/core/java/android/view/KeyCharacterMap.java
+++ b/core/java/android/view/KeyCharacterMap.java
@@ -31,7 +31,19 @@ import java.lang.Character;
public class KeyCharacterMap {
/**
* The id of the device's primary built in keyboard is always 0.
+ *
+ * @deprecated This constant should no longer be used because there is no
+ * guarantee that a device has a built-in keyboard that can be used for
+ * typing text. There might not be a built-in keyboard, the built-in keyboard
+ * might be a {@link #NUMERIC} or {@link #SPECIAL_FUNCTION} keyboard, or there
+ * might be multiple keyboards installed including external keyboards.
+ * When interpreting key presses received from the framework, applications should
+ * use the device id specified in the {@link #KeyEvent} received.
+ * When synthesizing key presses for delivery elsewhere or when translating key presses
+ * from unknown keyboards, applications should use the special {@link #VIRTUAL_KEYBOARD}
+ * device id.
*/
+ @Deprecated
public static final int BUILT_IN_KEYBOARD = 0;
/**
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index b3277e4..03407a3 100755
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -1081,7 +1081,15 @@ public class KeyEvent extends InputEvent implements Parcelable {
static final boolean DEBUG = false;
static final String TAG = "KeyEvent";
-
+
+ private static final int MAX_RECYCLED = 10;
+ private static final Object gRecyclerLock = new Object();
+ private static int gRecyclerUsed;
+ private static KeyEvent gRecyclerTop;
+
+ private KeyEvent mNext;
+ private boolean mRecycled;
+
private int mMetaState;
private int mAction;
private int mKeyCode;
@@ -1160,6 +1168,9 @@ public class KeyEvent extends InputEvent implements Parcelable {
}
}
+ private KeyEvent() {
+ }
+
/**
* Create a new key event.
*
@@ -1382,6 +1393,67 @@ public class KeyEvent extends InputEvent implements Parcelable {
mCharacters = origEvent.mCharacters;
}
+ private static KeyEvent obtain() {
+ final KeyEvent ev;
+ synchronized (gRecyclerLock) {
+ ev = gRecyclerTop;
+ if (ev == null) {
+ return new KeyEvent();
+ }
+ gRecyclerTop = ev.mNext;
+ gRecyclerUsed -= 1;
+ }
+ ev.mRecycled = false;
+ ev.mNext = null;
+ return ev;
+ }
+
+ /**
+ * Obtains a (potentially recycled) key event.
+ *
+ * @hide
+ */
+ public static KeyEvent obtain(long downTime, long eventTime, int action,
+ int code, int repeat, int metaState,
+ int deviceId, int scancode, int flags, int source, String characters) {
+ KeyEvent ev = obtain();
+ ev.mDownTime = downTime;
+ ev.mEventTime = eventTime;
+ ev.mAction = action;
+ ev.mKeyCode = code;
+ ev.mRepeatCount = repeat;
+ ev.mMetaState = metaState;
+ ev.mDeviceId = deviceId;
+ ev.mScanCode = scancode;
+ ev.mFlags = flags;
+ ev.mSource = source;
+ ev.mCharacters = characters;
+ return ev;
+ }
+
+ /**
+ * Recycles a key event.
+ * Key events should only be recycled if they are owned by the system since user
+ * code expects them to be essentially immutable, "tracking" notwithstanding.
+ *
+ * @hide
+ */
+ public final void recycle() {
+ if (mRecycled) {
+ throw new RuntimeException(toString() + " recycled twice!");
+ }
+ mRecycled = true;
+ mCharacters = null;
+
+ synchronized (gRecyclerLock) {
+ if (gRecyclerUsed < MAX_RECYCLED) {
+ gRecyclerUsed++;
+ mNext = gRecyclerTop;
+ gRecyclerTop = this;
+ }
+ }
+ }
+
/**
* Create a new key event that is the same as the given one, but whose
* event time and repeat count are replaced with the given value.
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 195d689..e81aa98 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -314,10 +314,10 @@ public final class MotionEvent extends InputEvent implements Parcelable {
*/
static private final int BASE_AVAIL_SAMPLES = 8;
- static private final int MAX_RECYCLED = 10;
- static private Object gRecyclerLock = new Object();
- static private int gRecyclerUsed = 0;
- static private MotionEvent gRecyclerTop = null;
+ private static final int MAX_RECYCLED = 10;
+ private static final Object gRecyclerLock = new Object();
+ private static int gRecyclerUsed;
+ private static MotionEvent gRecyclerTop;
private long mDownTimeNano;
private int mAction;
@@ -361,7 +361,8 @@ public final class MotionEvent extends InputEvent implements Parcelable {
static private MotionEvent obtain(int pointerCount, int sampleCount) {
final MotionEvent ev;
synchronized (gRecyclerLock) {
- if (gRecyclerTop == null) {
+ ev = gRecyclerTop;
+ if (ev == null) {
if (pointerCount < BASE_AVAIL_POINTERS) {
pointerCount = BASE_AVAIL_POINTERS;
}
@@ -370,7 +371,6 @@ public final class MotionEvent extends InputEvent implements Parcelable {
}
return new MotionEvent(pointerCount, sampleCount);
}
- ev = gRecyclerTop;
gRecyclerTop = ev.mNext;
gRecyclerUsed -= 1;
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 011ad77..f135fcc 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -595,6 +595,11 @@ import java.util.WeakHashMap;
* @attr ref android.R.styleable#View_paddingRight
* @attr ref android.R.styleable#View_paddingTop
* @attr ref android.R.styleable#View_saveEnabled
+ * @attr ref android.R.styleable#View_rotation
+ * @attr ref android.R.styleable#View_rotationX
+ * @attr ref android.R.styleable#View_rotationY
+ * @attr ref android.R.styleable#View_scaleX
+ * @attr ref android.R.styleable#View_scaleY
* @attr ref android.R.styleable#View_scrollX
* @attr ref android.R.styleable#View_scrollY
* @attr ref android.R.styleable#View_scrollbarSize
@@ -610,6 +615,10 @@ import java.util.WeakHashMap;
* @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack
* @attr ref android.R.styleable#View_soundEffectsEnabled
* @attr ref android.R.styleable#View_tag
+ * @attr ref android.R.styleable#View_transformPivotX
+ * @attr ref android.R.styleable#View_transformPivotY
+ * @attr ref android.R.styleable#View_translationX
+ * @attr ref android.R.styleable#View_translationY
* @attr ref android.R.styleable#View_visibility
*
* @see android.view.ViewGroup
@@ -2155,6 +2164,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
int x = 0;
int y = 0;
+ float tx = 0;
+ float ty = 0;
+ float rotation = 0;
+ float rotationX = 0;
+ float rotationY = 0;
+ float sx = 1f;
+ float sy = 1f;
+ boolean transformSet = false;
+
int scrollbarStyle = SCROLLBARS_INSIDE_OVERLAY;
int overScrollMode = mOverScrollMode;
@@ -2186,6 +2204,43 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
case com.android.internal.R.styleable.View_scrollY:
y = a.getDimensionPixelOffset(attr, 0);
break;
+ case com.android.internal.R.styleable.View_alpha:
+ setAlpha(a.getFloat(attr, 1f));
+ break;
+ case com.android.internal.R.styleable.View_transformPivotX:
+ setPivotX(a.getDimensionPixelOffset(attr, 0));
+ break;
+ case com.android.internal.R.styleable.View_transformPivotY:
+ setPivotY(a.getDimensionPixelOffset(attr, 0));
+ break;
+ case com.android.internal.R.styleable.View_translationX:
+ tx = a.getDimensionPixelOffset(attr, 0);
+ transformSet = true;
+ break;
+ case com.android.internal.R.styleable.View_translationY:
+ ty = a.getDimensionPixelOffset(attr, 0);
+ transformSet = true;
+ break;
+ case com.android.internal.R.styleable.View_rotation:
+ rotation = a.getFloat(attr, 0);
+ transformSet = true;
+ break;
+ case com.android.internal.R.styleable.View_rotationX:
+ rotationX = a.getFloat(attr, 0);
+ transformSet = true;
+ break;
+ case com.android.internal.R.styleable.View_rotationY:
+ rotationY = a.getFloat(attr, 0);
+ transformSet = true;
+ break;
+ case com.android.internal.R.styleable.View_scaleX:
+ sx = a.getFloat(attr, 1f);
+ transformSet = true;
+ break;
+ case com.android.internal.R.styleable.View_scaleY:
+ sy = a.getFloat(attr, 1f);
+ transformSet = true;
+ break;
case com.android.internal.R.styleable.View_id:
mID = a.getResourceId(attr, NO_ID);
break;
@@ -2404,6 +2459,16 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
scrollTo(x, y);
}
+ if (transformSet) {
+ setTranslationX(tx);
+ setTranslationY(ty);
+ setRotation(rotation);
+ setRotationX(rotationX);
+ setRotationY(rotationY);
+ setScaleX(sx);
+ setScaleY(sy);
+ }
+
if (!setScrollContainer && (viewFlagValues&SCROLLBARS_VERTICAL) != 0) {
setScrollContainer(true);
}
@@ -5286,6 +5351,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* @param rotation The degrees of rotation.
* @see #getPivotX()
* @see #getPivotY()
+ *
+ * @attr ref android.R.styleable#View_rotation
*/
public void setRotation(float rotation) {
if (mRotation != rotation) {
@@ -5317,6 +5384,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* @param rotationY The degrees of Y rotation.
* @see #getPivotX()
* @see #getPivotY()
+ *
+ * @attr ref android.R.styleable#View_rotationY
*/
public void setRotationY(float rotationY) {
if (mRotationY != rotationY) {
@@ -5348,6 +5417,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* @param rotationX The degrees of X rotation.
* @see #getPivotX()
* @see #getPivotY()
+ *
+ * @attr ref android.R.styleable#View_rotationX
*/
public void setRotationX(float rotationX) {
if (mRotationX != rotationX) {
@@ -5381,6 +5452,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* @param scaleX The scaling factor.
* @see #getPivotX()
* @see #getPivotY()
+ *
+ * @attr ref android.R.styleable#View_scaleX
*/
public void setScaleX(float scaleX) {
if (mScaleX != scaleX) {
@@ -5414,6 +5487,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* @param scaleY The scaling factor.
* @see #getPivotX()
* @see #getPivotY()
+ *
+ * @attr ref android.R.styleable#View_scaleY
*/
public void setScaleY(float scaleY) {
if (mScaleY != scaleY) {
@@ -5452,6 +5527,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* @see #getScaleX()
* @see #getScaleY()
* @see #getPivotY()
+ *
+ * @attr ref android.R.styleable#View_transformPivotX
*/
public void setPivotX(float pivotX) {
mPrivateFlags |= PIVOT_EXPLICITLY_SET;
@@ -5490,6 +5567,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* @see #getScaleX()
* @see #getScaleY()
* @see #getPivotY()
+ *
+ * @attr ref android.R.styleable#View_transformPivotY
*/
public void setPivotY(float pivotY) {
mPrivateFlags |= PIVOT_EXPLICITLY_SET;
@@ -5519,6 +5598,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* completely transparent and 1 means the view is completely opaque.
*
* @param alpha The opacity of the view.
+ *
+ * @attr ref android.R.styleable#View_alpha
*/
public void setAlpha(float alpha) {
mAlpha = alpha;
@@ -5810,6 +5891,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
*
* @param translationX The horizontal position of this view relative to its left position,
* in pixels.
+ *
+ * @attr ref android.R.styleable#View_translationX
*/
public void setTranslationX(float translationX) {
if (mTranslationX != translationX) {
@@ -5841,6 +5924,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
*
* @param translationY The vertical position of this view relative to its top position,
* in pixels.
+ *
+ * @attr ref android.R.styleable#View_translationY
*/
public void setTranslationY(float translationY) {
if (mTranslationY != translationY) {
@@ -6345,6 +6430,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
}
final AttachInfo ai = mAttachInfo;
final ViewParent p = mParent;
+ if (p != null && ai != null && ai.mHardwareAccelerated) {
+ // fast-track for GL-enabled applications; just invalidate the whole hierarchy
+ // with a null dirty rect, which tells the ViewRoot to redraw everything
+ p.invalidateChild(this, null);
+ return;
+ }
if (p != null && ai != null) {
final Rect r = ai.mTmpInvalRect;
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index 1972692..cb7d0e2 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -53,7 +53,7 @@ import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
-import android.view.InputQueue.FinishedCallback;
+import android.util.TypedValue;
import android.view.View.MeasureSpec;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -87,7 +87,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
/** @noinspection PointlessBooleanExpression*/
private static final boolean DEBUG_DRAW = false || LOCAL_LOGV;
private static final boolean DEBUG_LAYOUT = false || LOCAL_LOGV;
- private static final boolean DEBUG_INPUT = true || LOCAL_LOGV;
+ private static final boolean DEBUG_DIALOG = false || LOCAL_LOGV;
private static final boolean DEBUG_INPUT_RESIZE = false || LOCAL_LOGV;
private static final boolean DEBUG_ORIENTATION = false || LOCAL_LOGV;
private static final boolean DEBUG_TRACKBALL = false || LOCAL_LOGV;
@@ -125,6 +125,8 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
final int[] mTmpLocation = new int[2];
+ final TypedValue mTmpValue = new TypedValue();
+
final InputMethodCallback mInputMethodCallback;
final SparseArray<Object> mPendingEvents = new SparseArray<Object>();
int mPendingEventSeq = 0;
@@ -405,7 +407,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
}
mPendingContentInsets.set(mAttachInfo.mContentInsets);
mPendingVisibleInsets.set(0, 0, 0, 0);
- if (Config.LOGV) Log.v(TAG, "Added window " + mWindow);
+ if (DEBUG_LAYOUT) Log.v(TAG, "Added window " + mWindow);
if (res < WindowManagerImpl.ADD_OKAY) {
mView = null;
mAttachInfo.mRootView = null;
@@ -639,7 +641,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
mTraversalScheduled = false;
mWillDrawSoon = true;
- boolean windowResizesToFitContent = false;
+ boolean windowSizeMayChange = false;
boolean fullRedrawNeeded = mFullRedrawNeeded;
boolean newSurface = false;
boolean surfaceChanged = false;
@@ -696,7 +698,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
"View " + host + " resized to: " + frame);
fullRedrawNeeded = true;
mLayoutRequested = true;
- windowResizesToFitContent = true;
+ windowSizeMayChange = true;
}
}
@@ -722,6 +724,8 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
// enqueued an action after being detached
getRunQueue().executeActions(attachInfo.mHandler);
+ final Resources res = mView.getContext().getResources();
+
if (mFirst) {
host.fitSystemWindows(mAttachInfo.mContentInsets);
// make sure touch mode code executes by setting cached value
@@ -743,23 +747,69 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
}
if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
|| lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
- windowResizesToFitContent = true;
+ windowSizeMayChange = true;
- DisplayMetrics packageMetrics =
- mView.getContext().getResources().getDisplayMetrics();
+ DisplayMetrics packageMetrics = res.getDisplayMetrics();
desiredWindowWidth = packageMetrics.widthPixels;
desiredWindowHeight = packageMetrics.heightPixels;
}
}
- childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
- childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
-
// Ask host how big it wants to be
if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(TAG,
"Measuring " + host + " in display " + desiredWindowWidth
+ "x" + desiredWindowHeight + "...");
- host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+
+ boolean goodMeasure = false;
+ if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
+ || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
+ // On large screens, we don't want to allow dialogs to just
+ // stretch to fill the entire width of the screen to display
+ // one line of text. First try doing the layout at a smaller
+ // size to see if it will fit.
+ final DisplayMetrics packageMetrics = res.getDisplayMetrics();
+ res.getValue(com.android.internal.R.dimen.config_prefDialogWidth, mTmpValue, true);
+ int baseSize = 0;
+ if (mTmpValue.type == TypedValue.TYPE_DIMENSION) {
+ baseSize = (int)mTmpValue.getDimension(packageMetrics);
+ }
+ if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": baseSize=" + baseSize);
+ if (baseSize != 0 && desiredWindowWidth > baseSize) {
+ int maxHeight = (desiredWindowHeight*2)/3;
+ childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
+ childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
+ host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+ if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
+ + host.getWidth() + "," + host.getHeight() + ")");
+ // Note: for now we are not taking into account height, since we
+ // can't distinguish between places where it would be useful to
+ // increase the width (text) vs. where it would not (a list).
+ // Maybe we can just try the next size up, and see if that reduces
+ // the height?
+ if (host.getWidth() <= baseSize /*&& host.getHeight() <= maxHeight*/) {
+ Log.v(TAG, "Good!");
+ goodMeasure = true;
+ } else {
+ // Didn't fit in that size... try expanding a bit.
+ baseSize = (baseSize+desiredWindowWidth)/2;
+ if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": next baseSize="
+ + baseSize);
+ host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+ if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured ("
+ + host.getWidth() + "," + host.getHeight() + ")");
+ if (host.getWidth() <= baseSize /*&& host.getHeight() <= maxHeight*/) {
+ if (DEBUG_DIALOG) Log.v(TAG, "Good!");
+ goodMeasure = true;
+ }
+ }
+ }
+ }
+
+ if (!goodMeasure) {
+ childWidthMeasureSpec = getRootMeasureSpec(desiredWindowWidth, lp.width);
+ childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
+ host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+ }
if (DBG) {
System.out.println("======================================");
@@ -812,7 +862,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
}
}
- boolean windowShouldResize = mLayoutRequested && windowResizesToFitContent
+ boolean windowShouldResize = mLayoutRequested && windowSizeMayChange
&& ((mWidth != host.mMeasuredWidth || mHeight != host.mMeasuredHeight)
|| (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
frame.width() < desiredWindowWidth && frame.width() != mWidth)
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 5a9cd97..af36d80 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -551,19 +551,14 @@ public interface WindowManagerPolicy {
* affect the power state of the device, for example, the power keys.
* Generally, it's best to keep as little as possible in the queue thread
* because it's the most fragile.
- * @param whenNanos The event time in uptime nanoseconds.
- * @param action The key event action.
- * @param flags The key event flags.
- * @param keyCode The key code.
- * @param scanCode The key's scan code.
+ * @param event The key event.
* @param policyFlags The policy flags associated with the key.
* @param isScreenOn True if the screen is already on
*
* @return The bitwise or of the {@link #ACTION_PASS_TO_USER},
* {@link #ACTION_POKE_USER_ACTIVITY} and {@link #ACTION_GO_TO_SLEEP} flags.
*/
- public int interceptKeyBeforeQueueing(long whenNanos, int action, int flags,
- int keyCode, int scanCode, int policyFlags, boolean isScreenOn);
+ public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn);
/**
* Called from the input dispatcher thread before a key is dispatched to a window.
@@ -574,18 +569,12 @@ public interface WindowManagerPolicy {
*
* @param win The window that currently has focus. This is where the key
* event will normally go.
- * @param action The key event action.
- * @param flags The key event flags.
- * @param keyCode The key code.
- * @param scanCode The key's scan code.
- * @param metaState bit mask of meta keys that are held.
- * @param repeatCount Number of times a key down has repeated.
+ * @param event The key event.
* @param policyFlags The policy flags associated with the key.
* @return Returns true if the policy consumed the event and it should
* not be further dispatched.
*/
- public boolean interceptKeyBeforeDispatching(WindowState win, int action, int flags,
- int keyCode, int scanCode, int metaState, int repeatCount, int policyFlags);
+ public boolean interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags);
/**
* Called from the input dispatcher thread when an application did not handle
@@ -596,17 +585,11 @@ public interface WindowManagerPolicy {
*
* @param win The window that currently has focus. This is where the key
* event will normally go.
- * @param action The key event action.
- * @param flags The key event flags.
- * @param keyCode The key code.
- * @param scanCode The key's scan code.
- * @param metaState bit mask of meta keys that are held.
- * @param repeatCount Number of times a key down has repeated.
+ * @param event The key event.
* @param policyFlags The policy flags associated with the key.
* @return Returns true if the policy consumed the event.
*/
- public boolean dispatchUnhandledKey(WindowState win, int action, int flags,
- int keyCode, int scanCode, int metaState, int repeatCount, int policyFlags);
+ public boolean dispatchUnhandledKey(WindowState win, KeyEvent event, int policyFlags);
/**
* Called when layout of the windows is about to start.
diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java
index 0925940..39a0c19 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtype.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtype.java
@@ -49,19 +49,23 @@ public final class InputMethodSubtype implements Parcelable {
InputMethodSubtype(int nameId, int iconId, String locale, String mode, String extraValue) {
mSubtypeNameResId = nameId;
mSubtypeIconResId = iconId;
- mSubtypeLocale = locale;
- mSubtypeMode = mode;
- mSubtypeExtraValue = extraValue;
+ mSubtypeLocale = locale != null ? locale : "";
+ mSubtypeMode = mode != null ? mode : "";
+ mSubtypeExtraValue = extraValue != null ? extraValue : "";
mSubtypeHashCode = hashCodeInternal(mSubtypeNameResId, mSubtypeIconResId, mSubtypeLocale,
mSubtypeMode, mSubtypeExtraValue);
}
InputMethodSubtype(Parcel source) {
+ String s;
mSubtypeNameResId = source.readInt();
mSubtypeIconResId = source.readInt();
- mSubtypeLocale = source.readString();
- mSubtypeMode = source.readString();
- mSubtypeExtraValue = source.readString();
+ s = source.readString();
+ mSubtypeLocale = s != null ? s : "";
+ s = source.readString();
+ mSubtypeMode = s != null ? s : "";
+ s = source.readString();
+ mSubtypeExtraValue = s != null ? s : "";
mSubtypeHashCode = hashCodeInternal(mSubtypeNameResId, mSubtypeIconResId, mSubtypeLocale,
mSubtypeMode, mSubtypeExtraValue);
}
@@ -110,8 +114,9 @@ public final class InputMethodSubtype implements Parcelable {
public boolean equals(Object o) {
if (o instanceof InputMethodSubtype) {
InputMethodSubtype subtype = (InputMethodSubtype) o;
- return (subtype.getNameResId() == getNameResId())
- && (subtype.getMode() == getMode())
+ return (subtype.hashCode() == hashCode())
+ && (subtype.getNameResId() == getNameResId())
+ && (subtype.getMode().equals(getMode()))
&& (subtype.getIconResId() == getIconResId())
&& (subtype.getLocale().equals(getLocale()))
&& (subtype.getExtraValue().equals(getExtraValue()));
@@ -146,4 +151,4 @@ public final class InputMethodSubtype implements Parcelable {
String mode, String extraValue) {
return Arrays.hashCode(new Object[] {nameResId, iconResId, locale, mode, extraValue});
}
-} \ No newline at end of file
+}
diff --git a/core/java/android/webkit/SelectActionModeCallback.java b/core/java/android/webkit/SelectActionModeCallback.java
index cf91902..2f3dc7c 100644
--- a/core/java/android/webkit/SelectActionModeCallback.java
+++ b/core/java/android/webkit/SelectActionModeCallback.java
@@ -25,15 +25,12 @@ import android.view.View;
class SelectActionModeCallback implements ActionMode.Callback {
private WebView mWebView;
- private View mTitleBar;
private ActionMode mActionMode;
void setWebView(WebView webView) {
mWebView = webView;
}
- void setTitleBar(View v) { mTitleBar = v; }
-
void finish() {
mActionMode.finish();
}
@@ -86,7 +83,6 @@ class SelectActionModeCallback implements ActionMode.Callback {
@Override
public void onDestroyActionMode(ActionMode mode) {
- if (mTitleBar != null) mWebView.setEmbeddedTitleBar(mTitleBar);
mWebView.selectionDone();
}
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index a98c83a..6e27b7a 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -485,6 +485,8 @@ public class WebView extends AbsoluteLayout
// true if onPause has been called (and not onResume)
private boolean mIsPaused;
+ private HitTestResult mInitialHitTestResult;
+
/**
* Customizable constant
*/
@@ -588,9 +590,11 @@ public class WebView extends AbsoluteLayout
private static final int DRAG_HELD_MOTIONLESS = 8;
private static final int AWAKEN_SCROLL_BARS = 9;
private static final int PREVENT_DEFAULT_TIMEOUT = 10;
+ private static final int SCROLL_SELECT_TEXT = 11;
+
private static final int FIRST_PRIVATE_MSG_ID = REMEMBER_PASSWORD;
- private static final int LAST_PRIVATE_MSG_ID = PREVENT_DEFAULT_TIMEOUT;
+ private static final int LAST_PRIVATE_MSG_ID = SCROLL_SELECT_TEXT;
/*
* Package message ids
@@ -647,7 +651,8 @@ public class WebView extends AbsoluteLayout
"RESUME_WEBCORE_PRIORITY", // = 7;
"DRAG_HELD_MOTIONLESS", // = 8;
"AWAKEN_SCROLL_BARS", // = 9;
- "PREVENT_DEFAULT_TIMEOUT" // = 10;
+ "PREVENT_DEFAULT_TIMEOUT", // = 10;
+ "SCROLL_SELECT_TEXT" // = 11;
};
static final String[] HandlerPackageDebugString = {
@@ -787,6 +792,11 @@ public class WebView extends AbsoluteLayout
private int mBackgroundColor = Color.WHITE;
+ private static final long SELECT_SCROLL_INTERVAL = 1000 / 60; // 60 / second
+ private int mAutoScrollX = 0;
+ private int mAutoScrollY = 0;
+ private boolean mSentAutoScrollMessage = false;
+
// Used to notify listeners of a new picture.
private PictureListener mPictureListener;
/**
@@ -2094,6 +2104,10 @@ public class WebView extends AbsoluteLayout
* HitTestResult type is set to UNKNOWN_TYPE.
*/
public HitTestResult getHitTestResult() {
+ return hitTestResult(mInitialHitTestResult);
+ }
+
+ private HitTestResult hitTestResult(HitTestResult fallback) {
if (mNativeClass == 0) {
return null;
}
@@ -2121,6 +2135,16 @@ public class WebView extends AbsoluteLayout
}
}
}
+ } else if (fallback != null) {
+ /* If webkit causes a rebuild while the long press is in progress,
+ * the cursor node may be reset, even if it is still around. This
+ * uses the cursor node saved when the touch began. Since the
+ * nativeImageURI below only changes the result if it is successful,
+ * this uses the data beneath the touch if available or the original
+ * tap data otherwise.
+ */
+ Log.v(LOGTAG, "hitTestResult use fallback");
+ result = fallback;
}
int type = result.getType();
if (type == HitTestResult.UNKNOWN_TYPE
@@ -2233,9 +2257,6 @@ public class WebView extends AbsoluteLayout
if (null == v) {
// If one of our callbacks is holding onto the titlebar to replace
// it when its ActionMode ends, remove it.
- if (mSelectCallback != null) {
- mSelectCallback.setTitleBar(null);
- }
if (mFindCallback != null) {
mFindCallback.setTitleBar(null);
}
@@ -3873,13 +3894,6 @@ public class WebView extends AbsoluteLayout
// decide which adornments to draw
int extras = DRAW_EXTRAS_NONE;
- if (DebugFlags.WEB_VIEW) {
- Log.v(LOGTAG, "mFindIsUp=" + mFindIsUp
- + " mSelectingText=" + mSelectingText
- + " nativePageShouldHandleShiftAndArrows()="
- + nativePageShouldHandleShiftAndArrows()
- + " animateZoom=" + animateZoom);
- }
if (mFindIsUp) {
extras = DRAW_EXTRAS_FIND;
} else if (mSelectingText) {
@@ -3890,6 +3904,14 @@ public class WebView extends AbsoluteLayout
} else if (drawCursorRing) {
extras = DRAW_EXTRAS_CURSOR_RING;
}
+ if (DebugFlags.WEB_VIEW) {
+ Log.v(LOGTAG, "mFindIsUp=" + mFindIsUp
+ + " mSelectingText=" + mSelectingText
+ + " nativePageShouldHandleShiftAndArrows()="
+ + nativePageShouldHandleShiftAndArrows()
+ + " animateZoom=" + animateZoom
+ + " extras=" + extras);
+ }
if (canvas.isHardwareAccelerated()) {
try {
@@ -4601,12 +4623,6 @@ public class WebView extends AbsoluteLayout
nativeHideCursor();
mSelectCallback = new SelectActionModeCallback();
mSelectCallback.setWebView(this);
- View titleBar = mTitleBar;
- // We do not want to show the embedded title bar during find or
- // select, but keep track of it so that it can be replaced when the
- // mode is exited.
- setEmbeddedTitleBar(null);
- mSelectCallback.setTitleBar(titleBar);
startActionMode(mSelectCallback);
}
@@ -4644,6 +4660,9 @@ public class WebView extends AbsoluteLayout
WebViewCore.resumePriority();
WebViewCore.resumeUpdatePicture(mWebViewCore);
invalidate(); // redraw without selection
+ mAutoScrollX = 0;
+ mAutoScrollY = 0;
+ mSentAutoScrollMessage = false;
}
}
@@ -5129,6 +5148,7 @@ public class WebView extends AbsoluteLayout
case MotionEvent.ACTION_DOWN: {
mPreventDefault = PREVENT_DEFAULT_NO;
mConfirmMove = false;
+ mInitialHitTestResult = null;
if (!mScroller.isFinished()) {
// stop the current scroll animation, but if this is
// the start of a fling, allow it to add to the current
@@ -5289,6 +5309,22 @@ public class WebView extends AbsoluteLayout
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(true);
}
+ int layer = nativeScrollableLayer(contentX, contentY);
+ if (layer == 0) {
+ mAutoScrollX = x <= SELECT_SCROLL ? -SELECT_SCROLL
+ : x >= getViewWidth() - SELECT_SCROLL
+ ? SELECT_SCROLL : 0;
+ mAutoScrollY = y <= SELECT_SCROLL ? -SELECT_SCROLL
+ : y >= getViewHeightWithTitle() - SELECT_SCROLL
+ ? SELECT_SCROLL : 0;
+ if (!mSentAutoScrollMessage) {
+ mSentAutoScrollMessage = true;
+ mPrivateHandler.sendEmptyMessageDelayed(
+ SCROLL_SELECT_TEXT, SELECT_SCROLL_INTERVAL);
+ }
+ } else {
+ // TODO: allow scrollable overflow div to autoscroll
+ }
nativeExtendSelection(contentX, contentY);
invalidate();
break;
@@ -5713,6 +5749,7 @@ public class WebView extends AbsoluteLayout
private static final int TRACKBALL_MOVE_COUNT = 10;
private static final int TRACKBALL_MULTIPLIER = 3;
private static final int SELECT_CURSOR_OFFSET = 16;
+ private static final int SELECT_SCROLL = 5;
private int mSelectX = 0;
private int mSelectY = 0;
private boolean mFocusSizeChanged = false;
@@ -6188,6 +6225,7 @@ public class WebView extends AbsoluteLayout
Rect rect = new Rect(contentX - mNavSlop, contentY - mNavSlop,
contentX + mNavSlop, contentY + mNavSlop);
nativeSelectBestAt(rect);
+ mInitialHitTestResult = hitTestResult(null);
}
/**
@@ -6617,7 +6655,18 @@ public class WebView extends AbsoluteLayout
}
break;
}
+ case SCROLL_SELECT_TEXT: {
+ if (mAutoScrollX == 0 && mAutoScrollY == 0) {
+ mSentAutoScrollMessage = false;
+ break;
+ }
+ scrollBy(mAutoScrollX, mAutoScrollY);
+ sendEmptyMessageDelayed(
+ SCROLL_SELECT_TEXT, SELECT_SCROLL_INTERVAL);
+ break;
+ }
case SWITCH_TO_SHORTPRESS: {
+ mInitialHitTestResult = null; // set by updateSelection()
if (mTouchMode == TOUCH_INIT_MODE) {
if (!getSettings().supportTouchOnly()
&& mPreventDefault != PREVENT_DEFAULT_YES) {
@@ -7729,6 +7778,7 @@ public class WebView extends AbsoluteLayout
private native boolean nativeHitSelection(int x, int y);
private native String nativeImageURI(int x, int y);
private native void nativeInstrumentReport();
+ private native Rect nativeLayerBounds(int layer);
/* package */ native boolean nativeMoveCursorToNextTextInput();
// return true if the page has been scrolled
private native boolean nativeMotionUp(int x, int y, int slop);
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 17f0a97..b7d20b4 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -1884,6 +1884,7 @@ final class WebViewCore {
int mScrollX;
int mScrollY;
boolean mMobileSite;
+ boolean mIsRestored;
}
static class DrawData {
@@ -2285,6 +2286,7 @@ final class WebViewCore {
mInitialViewState.mScrollY = mRestoredY;
mInitialViewState.mMobileSite = (0 == mViewportWidth);
if (mRestoredScale > 0) {
+ mInitialViewState.mIsRestored = true;
mInitialViewState.mViewScale = mRestoredScale / 100.0f;
if (mRestoredTextWrapScale > 0) {
mInitialViewState.mTextWrapScale = mRestoredTextWrapScale / 100.0f;
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 69db6b2..b94dc3b 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -260,12 +260,7 @@ class ZoomManager {
public final float getReadingLevelScale() {
// The reading scale is at least 0.5f apart from the overview scale.
final float MIN_SCALE_DIFF = 0.5f;
- final float zoomOverviewScale = getZoomOverviewScale();
- if (zoomOverviewScale > DEFAULT_READING_LEVEL_SCALE) {
- return Math.min(DEFAULT_READING_LEVEL_SCALE,
- zoomOverviewScale - MIN_SCALE_DIFF);
- }
- return Math.max(zoomOverviewScale + MIN_SCALE_DIFF,
+ return Math.max(getZoomOverviewScale() + MIN_SCALE_DIFF,
DEFAULT_READING_LEVEL_SCALE);
}
@@ -864,32 +859,33 @@ class ZoomManager {
if (!mWebView.drawHistory()) {
float scale;
- final boolean reflowText;
- WebSettings settings = mWebView.getSettings();
+ final float overviewScale = getZoomOverviewScale();
if (mInitialScale > 0) {
scale = mInitialScale;
- reflowText = exceedsMinScaleIncrement(mTextWrapScale, scale);
} else if (viewState.mViewScale > 0) {
mTextWrapScale = viewState.mTextWrapScale;
scale = viewState.mViewScale;
- reflowText = false;
} else {
- scale = getZoomOverviewScale();
- if (settings.getUseWideViewPort()
- && settings.getLoadWithOverviewMode()) {
- mInitialZoomOverview = true;
- } else {
+ scale = overviewScale;
+ WebSettings settings = mWebView.getSettings();
+ if (!settings.getUseWideViewPort()
+ || !settings.getLoadWithOverviewMode()) {
scale = Math.max(viewState.mTextWrapScale, scale);
- mInitialZoomOverview = !exceedsMinScaleIncrement(scale, getZoomOverviewScale());
}
if (settings.isNarrowColumnLayout() && settings.getUseFixedViewport()) {
// When first layout, reflow using the reading level scale to avoid
// reflow when double tapped.
mTextWrapScale = getReadingLevelScale();
}
+ }
+ boolean reflowText = false;
+ if (!viewState.mIsRestored) {
+ scale = Math.max(scale, overviewScale);
+ mTextWrapScale = Math.max(mTextWrapScale, overviewScale);
reflowText = exceedsMinScaleIncrement(mTextWrapScale, scale);
}
+ mInitialZoomOverview = !exceedsMinScaleIncrement(scale, overviewScale);
setZoomScale(scale, reflowText);
// update the zoom buttons as the scale can be changed
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 4482b5b..0c298b0 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -18,80 +18,134 @@ package android.widget;
import com.android.internal.R;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
import android.annotation.Widget;
import android.content.Context;
-import android.os.Handler;
+import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.Paint.Align;
import android.text.InputFilter;
import android.text.InputType;
import android.text.Spanned;
+import android.text.TextUtils;
import android.text.method.NumberKeyListener;
import android.util.AttributeSet;
+import android.util.SparseArray;
+import android.view.KeyEvent;
import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.LayoutInflater.Filter;
+import android.view.animation.OvershootInterpolator;
+import android.view.inputmethod.InputMethodManager;
/**
- * A view for selecting a number
+ * A view for selecting a number For a dialog using this view, see
+ * {@link android.app.TimePickerDialog}.
*
- * For a dialog using this view, see {@link android.app.TimePickerDialog}.
* @hide
*/
@Widget
public class NumberPicker extends LinearLayout {
/**
- * The callback interface used to indicate the number value has been adjusted.
+ * The index of the middle selector item.
*/
- public interface OnChangedListener {
- /**
- * @param picker The NumberPicker associated with this listener.
- * @param oldVal The previous value.
- * @param newVal The new value.
- */
- void onChanged(NumberPicker picker, int oldVal, int newVal);
- }
+ private static final int SELECTOR_MIDDLE_ITEM_INDEX = 2;
/**
- * Interface used to format the number into a string for presentation
+ * The coefficient by which to adjust (divide) the max fling velocity.
*/
- public interface Formatter {
- String toString(int value);
- }
+ private static final int SELECTOR_MAX_FLING_VELOCITY_ADJUSTMENT = 8;
- /*
- * Use a custom NumberPicker formatting callback to use two-digit
- * minutes strings like "01". Keeping a static formatter etc. is the
- * most efficient way to do this; it avoids creating temporary objects
- * on every call to format().
- */
- public static final NumberPicker.Formatter TWO_DIGIT_FORMATTER =
- new NumberPicker.Formatter() {
- final StringBuilder mBuilder = new StringBuilder();
- final java.util.Formatter mFmt = new java.util.Formatter(mBuilder);
- final Object[] mArgs = new Object[1];
- public String toString(int value) {
- mArgs[0] = value;
- mBuilder.delete(0, mBuilder.length());
- mFmt.format("%02d", mArgs);
- return mFmt.toString();
- }
- };
+ /**
+ * The the duration for adjusting the selector wheel.
+ */
+ private static final int SELECTOR_ADJUSTMENT_DURATION_MILLIS = 800;
- private final Handler mHandler;
- private final Runnable mRunnable = new Runnable() {
- public void run() {
- if (mIncrement) {
- changeCurrent(mCurrent + 1);
- mHandler.postDelayed(this, mSpeed);
- } else if (mDecrement) {
- changeCurrent(mCurrent - 1);
- mHandler.postDelayed(this, mSpeed);
- }
+ /**
+ * The the delay for showing the input controls after a single tap on the
+ * input text.
+ */
+ private static final int SHOW_INPUT_CONTROLS_DELAY_MILLIS = ViewConfiguration
+ .getDoubleTapTimeout();
+
+ /**
+ * The update step for incrementing the current value.
+ */
+ private static final int UPDATE_STEP_INCREMENT = 1;
+
+ /**
+ * The update step for decrementing the current value.
+ */
+ private static final int UPDATE_STEP_DECREMENT = -1;
+
+ /**
+ * The strength of fading in the top and bottom while drawing the selector.
+ */
+ private static final float TOP_AND_BOTTOM_FADING_EDGE_STRENGTH = 0.9f;
+
+ /**
+ * The numbers accepted by the input text's {@link Filter}
+ */
+ private static final char[] DIGIT_CHARACTERS = new char[] {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
+ };
+
+ /**
+ * Use a custom NumberPicker formatting callback to use two-digit minutes
+ * strings like "01". Keeping a static formatter etc. is the most efficient
+ * way to do this; it avoids creating temporary objects on every call to
+ * format().
+ */
+ public static final NumberPicker.Formatter TWO_DIGIT_FORMATTER = new NumberPicker.Formatter() {
+ final StringBuilder mBuilder = new StringBuilder();
+
+ final java.util.Formatter mFmt = new java.util.Formatter(mBuilder);
+
+ final Object[] mArgs = new Object[1];
+
+ public String toString(int value) {
+ mArgs[0] = value;
+ mBuilder.delete(0, mBuilder.length());
+ mFmt.format("%02d", mArgs);
+ return mFmt.toString();
}
};
- private final EditText mText;
- private final InputFilter mNumberInputFilter;
+ /**
+ * The increment button.
+ */
+ private final ImageButton mIncrementButton;
+
+ /**
+ * The decrement button.
+ */
+ private final ImageButton mDecrementButton;
+
+ /**
+ * The text for showing the current value.
+ */
+ private final EditText mInputText;
+
+ /**
+ * The height of the text.
+ */
+ private final int mTextSize;
+ /**
+ * The values to be displayed instead the indices.
+ */
private String[] mDisplayedValues;
/**
@@ -110,104 +164,466 @@ public class NumberPicker extends LinearLayout {
private int mCurrent;
/**
- * Previous value of this NumberPicker.
+ * Listener to be notified upon current value change.
*/
- private int mPrevious;
private OnChangedListener mListener;
+
+ /**
+ * Formatter for for displaying the current value.
+ */
private Formatter mFormatter;
- private long mSpeed = 300;
- private boolean mIncrement;
- private boolean mDecrement;
+ /**
+ * The speed for updating the value form long press.
+ */
+ private long mLongPressUpdateSpeed = 300;
/**
- * Create a new number picker
- * @param context the application environment
+ * Cache for the string representation of selector indices.
+ */
+ private final SparseArray<String> mSelectorIndexToStringCache = new SparseArray<String>();
+
+ /**
+ * The selector indices whose value are show by the selector.
+ */
+ private final int[] mSelectorIndices = new int[] {
+ Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE,
+ Integer.MIN_VALUE
+ };
+
+ /**
+ * The {@link Paint} for drawing the selector.
+ */
+ private final Paint mSelectorPaint;
+
+ /**
+ * The height of a selector element (text + gap).
+ */
+ private int mSelectorElementHeight;
+
+ /**
+ * The initial offset of the scroll selector.
+ */
+ private int mInitialScrollOffset = Integer.MIN_VALUE;
+
+ /**
+ * The current offset of the scroll selector.
+ */
+ private int mCurrentScrollOffset;
+
+ /**
+ * The {@link Scroller} responsible for flinging the selector.
+ */
+ private final Scroller mFlingScroller;
+
+ /**
+ * The {@link Scroller} responsible for adjusting the selector.
+ */
+ private final Scroller mAdjustScroller;
+
+ /**
+ * The previous Y coordinate while scrolling the selector.
+ */
+ private int mPreviousScrollerY;
+
+ /**
+ * Handle to the reusable command for setting the input text selection.
+ */
+ private SetSelectionCommand mSetSelectionCommand;
+
+ /**
+ * Handle to the reusable command for adjusting the scroller.
+ */
+ private AdjustScrollerCommand mAdjustScrollerCommand;
+
+ /**
+ * Handle to the reusable command for updating the current value from long
+ * press.
+ */
+ private UpdateValueFromLongPressCommand mUpdateFromLongPressCommand;
+
+ /**
+ * {@link Animator} for showing the up/down arrows.
+ */
+ private final AnimatorSet mShowInputControlsAnimator;
+
+ /**
+ * The Y position of the last down event.
+ */
+ private float mLastDownEventY;
+
+ /**
+ * The Y position of the last motion event.
+ */
+ private float mLastMotionEventY;
+
+ /**
+ * Flag if to begin edit on next up event.
+ */
+ private boolean mBeginEditOnUpEvent;
+
+ /**
+ * Flag if to adjust the selector wheel on next up event.
+ */
+ private boolean mAdjustScrollerOnUpEvent;
+
+ /**
+ * Flag if to draw the selector wheel.
+ */
+ private boolean mDrawSelectorWheel;
+
+ /**
+ * Determines speed during touch scrolling.
+ */
+ private VelocityTracker mVelocityTracker;
+
+ /**
+ * @see ViewConfiguration#getScaledTouchSlop()
+ */
+ private int mTouchSlop;
+
+ /**
+ * @see ViewConfiguration#getScaledMinimumFlingVelocity()
+ */
+ private int mMinimumFlingVelocity;
+
+ /**
+ * @see ViewConfiguration#getScaledMaximumFlingVelocity()
+ */
+ private int mMaximumFlingVelocity;
+
+ /**
+ * Flag whether the selector should wrap around.
+ */
+ private boolean mWrapSelector;
+
+ /**
+ * The back ground color used to optimize scroller fading.
*/
- public NumberPicker(Context context) {
- this(context, null);
+ private final int mSolidColor;
+
+ /**
+ * Reusable {@link Rect} instance.
+ */
+ private final Rect mTempRect = new Rect();
+
+ /**
+ * The callback interface used to indicate the number value has changed.
+ */
+ public interface OnChangedListener {
+ /**
+ * @param picker The NumberPicker associated with this listener.
+ * @param oldVal The previous value.
+ * @param newVal The new value.
+ */
+ void onChanged(NumberPicker picker, int oldVal, int newVal);
+ }
+
+ /**
+ * Interface used to format the number into a string for presentation
+ */
+ public interface Formatter {
+ String toString(int value);
}
/**
* Create a new number picker
- * @param context the application environment
- * @param attrs a collection of attributes
+ *
+ * @param context The application environment.
+ * @param attrs A collection of attributes.
*/
public NumberPicker(Context context, AttributeSet attrs) {
- super(context, attrs);
- setOrientation(VERTICAL);
- LayoutInflater inflater =
- (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ this(context, attrs, R.attr.numberPickerStyle);
+ }
+
+ /**
+ * Create a new number picker
+ *
+ * @param context the application environment.
+ * @param attrs a collection of attributes.
+ * @param defStyle The default style to apply to this view.
+ */
+ public NumberPicker(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ // process style attributes
+ TypedArray attributesArray = context.obtainStyledAttributes(attrs,
+ R.styleable.NumberPicker, defStyle, 0);
+ int orientation = attributesArray.getInt(R.styleable.NumberPicker_orientation, VERTICAL);
+ setOrientation(orientation);
+ mSolidColor = attributesArray.getColor(R.styleable.NumberPicker_solidColor, 0);
+ attributesArray.recycle();
+
+ // By default Linearlayout that we extend is not drawn. This is
+ // its draw() method is not called but dispatchDraw() is called
+ // directly (see ViewGroup.drawChild()). However, this class uses
+ // the fading edge effect implemented by View and we need our
+ // draw() method to be called. Therefore, we declare we will draw.
+ setWillNotDraw(false);
+ setDrawSelectorWheel(false);
+
+ LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.number_picker, this, true);
- mHandler = new Handler();
- OnClickListener clickListener = new OnClickListener() {
+ OnClickListener onClickListener = new OnClickListener() {
public void onClick(View v) {
- validateInput(mText);
- if (!mText.hasFocus()) mText.requestFocus();
-
- // now perform the increment/decrement
- if (R.id.increment == v.getId()) {
+ mInputText.clearFocus();
+ if (v.getId() == R.id.increment) {
changeCurrent(mCurrent + 1);
- } else if (R.id.decrement == v.getId()) {
+ } else {
changeCurrent(mCurrent - 1);
}
}
};
- OnFocusChangeListener focusListener = new OnFocusChangeListener() {
- public void onFocusChange(View v, boolean hasFocus) {
+ OnLongClickListener onLongClickListener = new OnLongClickListener() {
+ public boolean onLongClick(View v) {
+ mInputText.clearFocus();
+ if (v.getId() == R.id.increment) {
+ postUpdateValueFromLongPress(UPDATE_STEP_INCREMENT);
+ } else {
+ postUpdateValueFromLongPress(UPDATE_STEP_DECREMENT);
+ }
+ return true;
+ }
+ };
- /* When focus is lost check that the text field
- * has valid values.
- */
+ // increment button
+ mIncrementButton = (ImageButton) findViewById(R.id.increment);
+ mIncrementButton.setOnClickListener(onClickListener);
+ mIncrementButton.setOnLongClickListener(onLongClickListener);
+
+ // decrement button
+ mDecrementButton = (ImageButton) findViewById(R.id.decrement);
+ mDecrementButton.setOnClickListener(onClickListener);
+ mDecrementButton.setOnLongClickListener(onLongClickListener);
+
+ // input text
+ mInputText = (EditText) findViewById(R.id.timepicker_input);
+ mInputText.setOnFocusChangeListener(new OnFocusChangeListener() {
+ public void onFocusChange(View v, boolean hasFocus) {
if (!hasFocus) {
- validateInput(v);
+ validateInputTextView(v);
}
}
- };
+ });
+ mInputText.setFilters(new InputFilter[] {
+ new InputTextFilter()
+ });
- OnLongClickListener longClickListener = new OnLongClickListener() {
- /**
- * We start the long click here but rely on the {@link NumberPickerButton}
- * to inform us when the long click has ended.
- */
- public boolean onLongClick(View v) {
- /* The text view may still have focus so clear it's focus which will
- * trigger the on focus changed and any typed values to be pulled.
- */
- mText.clearFocus();
-
- if (R.id.increment == v.getId()) {
- mIncrement = true;
- mHandler.post(mRunnable);
- } else if (R.id.decrement == v.getId()) {
- mDecrement = true;
- mHandler.post(mRunnable);
+ mInputText.setRawInputType(InputType.TYPE_CLASS_NUMBER);
+
+ // initialize constants
+ mTouchSlop = ViewConfiguration.getTapTimeout();
+ ViewConfiguration configuration = ViewConfiguration.get(context);
+ mTouchSlop = configuration.getScaledTouchSlop();
+ mMinimumFlingVelocity = configuration.getScaledMinimumFlingVelocity();
+ mMaximumFlingVelocity = configuration.getScaledMaximumFlingVelocity()
+ / SELECTOR_MAX_FLING_VELOCITY_ADJUSTMENT;
+ mTextSize = (int) mInputText.getTextSize();
+
+ // create the selector wheel paint
+ Paint paint = new Paint();
+ paint.setAntiAlias(true);
+ paint.setTextAlign(Align.CENTER);
+ paint.setTextSize(mTextSize);
+ paint.setTypeface(mInputText.getTypeface());
+ ColorStateList colors = mInputText.getTextColors();
+ int color = colors.getColorForState(ENABLED_STATE_SET, Color.WHITE);
+ paint.setColor(color);
+ mSelectorPaint = paint;
+
+ // create the animator for showing the input controls
+ final ValueAnimator fadeScroller = ObjectAnimator.ofInt(this, "selectorPaintAlpha", 255, 0);
+ final ObjectAnimator showIncrementButton = ObjectAnimator.ofFloat(mIncrementButton,
+ "alpha", 0, 1);
+ final ObjectAnimator showDecrementButton = ObjectAnimator.ofFloat(mDecrementButton,
+ "alpha", 0, 1);
+ mShowInputControlsAnimator = new AnimatorSet();
+ mShowInputControlsAnimator.playTogether(fadeScroller, showIncrementButton,
+ showDecrementButton);
+ mShowInputControlsAnimator.setDuration(getResources().getInteger(
+ R.integer.config_longAnimTime));
+ mShowInputControlsAnimator.addListener(new AnimatorListenerAdapter() {
+ private boolean mCanceled = false;
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (!mCanceled) {
+ // if canceled => we still want the wheel drawn
+ setDrawSelectorWheel(false);
}
- return true;
+ mCanceled = false;
+ mSelectorPaint.setAlpha(255);
+ invalidate();
}
- };
- InputFilter inputFilter = new NumberPickerInputFilter();
- mNumberInputFilter = new NumberRangeKeyListener();
- mIncrementButton = (NumberPickerButton) findViewById(R.id.increment);
- mIncrementButton.setOnClickListener(clickListener);
- mIncrementButton.setOnLongClickListener(longClickListener);
- mIncrementButton.setNumberPicker(this);
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ if (mShowInputControlsAnimator.isRunning()) {
+ mCanceled = true;
+ }
+ }
+ });
- mDecrementButton = (NumberPickerButton) findViewById(R.id.decrement);
- mDecrementButton.setOnClickListener(clickListener);
- mDecrementButton.setOnLongClickListener(longClickListener);
- mDecrementButton.setNumberPicker(this);
+ // create the fling and adjust scrollers
+ mFlingScroller = new Scroller(getContext());
+ mAdjustScroller = new Scroller(getContext(), new OvershootInterpolator());
- mText = (EditText) findViewById(R.id.timepicker_input);
- mText.setOnFocusChangeListener(focusListener);
- mText.setFilters(new InputFilter[] {inputFilter});
- mText.setRawInputType(InputType.TYPE_CLASS_NUMBER);
+ updateInputTextView();
+ updateIncrementAndDecrementButtonsVisibilityState();
+ }
+
+ @Override
+ public void onWindowFocusChanged(boolean hasWindowFocus) {
+ super.onWindowFocusChanged(hasWindowFocus);
+ if (!hasWindowFocus) {
+ removeAllCallbacks();
+ }
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent event) {
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_DOWN:
+ mLastMotionEventY = mLastDownEventY = event.getY();
+ removeAllCallbacks();
+ mBeginEditOnUpEvent = false;
+ mAdjustScrollerOnUpEvent = true;
+ if (mDrawSelectorWheel) {
+ mBeginEditOnUpEvent = mFlingScroller.isFinished()
+ && mAdjustScroller.isFinished();
+ mAdjustScrollerOnUpEvent = true;
+ mFlingScroller.forceFinished(true);
+ mAdjustScroller.forceFinished(true);
+ hideInputControls();
+ return true;
+ }
+ if (isEventInInputText(event)) {
+ mAdjustScrollerOnUpEvent = false;
+ setDrawSelectorWheel(true);
+ hideInputControls();
+ return true;
+ }
+ break;
+ case MotionEvent.ACTION_MOVE:
+ float currentMoveY = event.getY();
+ int deltaDownY = (int) Math.abs(currentMoveY - mLastDownEventY);
+ if (deltaDownY > mTouchSlop) {
+ mBeginEditOnUpEvent = false;
+ setDrawSelectorWheel(true);
+ hideInputControls();
+ return true;
+ }
+ break;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ if (mVelocityTracker == null) {
+ mVelocityTracker = VelocityTracker.obtain();
+ }
+ mVelocityTracker.addMovement(ev);
+ int action = ev.getActionMasked();
+ switch (action) {
+ case MotionEvent.ACTION_MOVE:
+ float currentMoveY = ev.getY();
+ if (mBeginEditOnUpEvent) {
+ int deltaDownY = (int) Math.abs(currentMoveY - mLastDownEventY);
+ if (deltaDownY > mTouchSlop) {
+ mBeginEditOnUpEvent = false;
+ }
+ }
+ int deltaMoveY = (int) (currentMoveY - mLastMotionEventY);
+ scrollBy(0, deltaMoveY);
+ invalidate();
+ mLastMotionEventY = currentMoveY;
+ break;
+ case MotionEvent.ACTION_UP:
+ if (mBeginEditOnUpEvent) {
+ setDrawSelectorWheel(false);
+ showInputControls();
+ mInputText.requestFocus();
+ InputMethodManager imm = (InputMethodManager) getContext().getSystemService(
+ Context.INPUT_METHOD_SERVICE);
+ imm.showSoftInput(mInputText, 0);
+ return true;
+ }
+ VelocityTracker velocityTracker = mVelocityTracker;
+ velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity);
+ int initialVelocity = (int) velocityTracker.getYVelocity();
+ if (Math.abs(initialVelocity) > mMinimumFlingVelocity) {
+ fling(initialVelocity);
+ } else {
+ if (mAdjustScrollerOnUpEvent) {
+ if (mFlingScroller.isFinished() && mAdjustScroller.isFinished()) {
+ postAdjustScrollerCommand(0);
+ }
+ } else {
+ postAdjustScrollerCommand(SHOW_INPUT_CONTROLS_DELAY_MILLIS);
+ }
+ }
+ mVelocityTracker.recycle();
+ mVelocityTracker = null;
+ break;
+ }
+ return true;
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent event) {
+ int action = event.getActionMasked();
+ if ((action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP)
+ && !isEventInInputText(event)) {
+ removeAllCallbacks();
+ }
+ return super.dispatchTouchEvent(event);
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ int keyCode = event.getKeyCode();
+ if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_ENTER) {
+ removeAllCallbacks();
+ }
+ return super.dispatchKeyEvent(event);
+ }
+
+ @Override
+ public boolean dispatchTrackballEvent(MotionEvent event) {
+ int action = event.getActionMasked();
+ if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
+ removeAllCallbacks();
+ }
+ return super.dispatchTrackballEvent(event);
+ }
- if (!isEnabled()) {
- setEnabled(false);
+ @Override
+ public void computeScroll() {
+ if (!mDrawSelectorWheel) {
+ return;
+ }
+ Scroller scroller = mFlingScroller;
+ if (scroller.isFinished()) {
+ scroller = mAdjustScroller;
+ if (scroller.isFinished()) {
+ return;
+ }
+ }
+ scroller.computeScrollOffset();
+ int currentScrollerY = scroller.getCurrY();
+ if (mPreviousScrollerY == 0) {
+ mPreviousScrollerY = scroller.getStartY();
+ }
+ scrollBy(0, currentScrollerY - mPreviousScrollerY);
+ mPreviousScrollerY = currentScrollerY;
+ if (scroller.isFinished()) {
+ onScrollerFinished(scroller);
+ } else {
+ invalidate();
}
}
@@ -222,11 +638,57 @@ public class NumberPicker extends LinearLayout {
super.setEnabled(enabled);
mIncrementButton.setEnabled(enabled);
mDecrementButton.setEnabled(enabled);
- mText.setEnabled(enabled);
+ mInputText.setEnabled(enabled);
+ }
+
+ /**
+ * Scrolls the selector with the given <code>vertical offset</code>.
+ */
+ @Override
+ public void scrollBy(int x, int y) {
+ int[] selectorIndices = getSelectorIndices();
+ if (mInitialScrollOffset == Integer.MIN_VALUE) {
+ int totalTextHeight = selectorIndices.length * mTextSize;
+ int totalTextGapHeight = (mBottom - mTop) - totalTextHeight;
+ int textGapCount = selectorIndices.length - 1;
+ int selectorTextGapHeight = totalTextGapHeight / textGapCount;
+ // compensate for integer division loss of the components used to
+ // calculate the text gap
+ int integerDivisionLoss = (mTextSize + mBottom - mTop) % textGapCount;
+ mInitialScrollOffset = mCurrentScrollOffset = mTextSize - integerDivisionLoss / 2;
+ mSelectorElementHeight = mTextSize + selectorTextGapHeight;
+ }
+
+ if (!mWrapSelector && y > 0 && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] <= mStart) {
+ mCurrentScrollOffset = mInitialScrollOffset;
+ return;
+ }
+ if (!mWrapSelector && y < 0 && selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] >= mEnd) {
+ mCurrentScrollOffset = mInitialScrollOffset;
+ return;
+ }
+ mCurrentScrollOffset += y;
+ while (mCurrentScrollOffset - mInitialScrollOffset > mSelectorElementHeight) {
+ mCurrentScrollOffset -= mSelectorElementHeight;
+ decrementSelectorIndices(selectorIndices);
+ changeCurrent(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX]);
+ if (selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] <= mStart) {
+ mCurrentScrollOffset = mInitialScrollOffset;
+ }
+ }
+ while (mCurrentScrollOffset - mInitialScrollOffset < -mSelectorElementHeight) {
+ mCurrentScrollOffset += mSelectorElementHeight;
+ incrementScrollSelectorIndices(selectorIndices);
+ changeCurrent(selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX]);
+ if (selectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] >= mEnd) {
+ mCurrentScrollOffset = mInitialScrollOffset;
+ }
+ }
}
/**
* Set the callback that indicates the number has been adjusted by the user.
+ *
* @param listener the callback, should not be null.
*/
public void setOnChangeListener(OnChangedListener listener) {
@@ -235,292 +697,678 @@ public class NumberPicker extends LinearLayout {
/**
* Set the formatter that will be used to format the number for presentation
- * @param formatter the formatter object. If formatter is null, String.valueOf()
- * will be used
+ *
+ * @param formatter the formatter object. If formatter is null,
+ * String.valueOf() will be used
*/
public void setFormatter(Formatter formatter) {
mFormatter = formatter;
}
/**
- * Set the range of numbers allowed for the number picker. The current
- * value will be automatically set to the start.
+ * Set the range of numbers allowed for the number picker. The current value
+ * will be automatically set to the start.
*
* @param start the start of the range (inclusive)
* @param end the end of the range (inclusive)
*/
public void setRange(int start, int end) {
- setRange(start, end, null/*displayedValues*/);
+ setRange(start, end, null);
}
/**
- * Set the range of numbers allowed for the number picker. The current
- * value will be automatically set to the start. Also provide a mapping
- * for values used to display to the user.
+ * Set the range of numbers allowed for the number picker. The current value
+ * will be automatically set to the start. Also provide a mapping for values
+ * used to display to the user.
*
* @param start the start of the range (inclusive)
* @param end the end of the range (inclusive)
* @param displayedValues the values displayed to the user.
*/
public void setRange(int start, int end, String[] displayedValues) {
+ boolean wrapSelector = (end - start) >= mSelectorIndices.length;
+ setRange(start, end, displayedValues, wrapSelector);
+ }
+
+ /**
+ * Set the range of numbers allowed for the number picker. The current value
+ * will be automatically set to the start. Also provide a mapping for values
+ * used to display to the user.
+ *
+ * @param start the start of the range (inclusive)
+ * @param end the end of the range (inclusive)
+ * @param displayedValues the values displayed to the user.
+ */
+ public void setRange(int start, int end, String[] displayedValues, boolean wrapSelector) {
+ if (start < 0 || end < 0) {
+ throw new IllegalArgumentException("start and end must be > 0");
+ }
+
mDisplayedValues = displayedValues;
mStart = start;
mEnd = end;
mCurrent = start;
- updateView();
+
+ setWrapSelector(wrapSelector);
+ updateInputTextView();
if (displayedValues != null) {
// Allow text entry rather than strictly numeric entry.
- mText.setRawInputType(InputType.TYPE_CLASS_TEXT |
- InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
+ mInputText.setRawInputType(InputType.TYPE_CLASS_TEXT
+ | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS);
+ } else {
+ mInputText.setRawInputType(InputType.TYPE_CLASS_NUMBER);
}
+
+ // make sure cached string representations are dropped
+ mSelectorIndexToStringCache.clear();
}
/**
* Set the current value for the number picker.
*
* @param current the current value the start of the range (inclusive)
- * @throws IllegalArgumentException when current is not within the range
- * of of the number picker
+ * @throws IllegalArgumentException when current is not within the range of
+ * of the number picker
*/
public void setCurrent(int current) {
if (current < mStart || current > mEnd) {
- throw new IllegalArgumentException(
- "current should be >= start and <= end");
+ throw new IllegalArgumentException("current should be >= start and <= end");
}
mCurrent = current;
- updateView();
+ updateInputTextView();
+ updateIncrementAndDecrementButtonsVisibilityState();
+ }
+
+ /**
+ * Sets whether the selector shown during flinging/scrolling should wrap
+ * around the beginning and end values.
+ *
+ * @param wrapSelector Whether to wrap.
+ */
+ public void setWrapSelector(boolean wrapSelector) {
+ if (wrapSelector && (mEnd - mStart) < mSelectorIndices.length) {
+ throw new IllegalStateException("Range less than selector items count.");
+ }
+ if (wrapSelector != mWrapSelector) {
+ // force the selector indices array to be reinitialized
+ mSelectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] = Integer.MAX_VALUE;
+ mWrapSelector = wrapSelector;
+ }
}
/**
- * Sets the speed at which the numbers will scroll when the +/-
- * buttons are longpressed
+ * Sets the speed at which the numbers will scroll when the +/- buttons are
+ * longpressed
*
* @param speed The speed (in milliseconds) at which the numbers will scroll
- * default 300ms
+ * default 300ms
*/
public void setSpeed(long speed) {
- mSpeed = speed;
+ mLongPressUpdateSpeed = speed;
}
- private String formatNumber(int value) {
- return (mFormatter != null)
- ? mFormatter.toString(value)
- : String.valueOf(value);
+ /**
+ * Returns the current value of the NumberPicker
+ *
+ * @return the current value.
+ */
+ public int getCurrent() {
+ return mCurrent;
+ }
+
+ @Override
+ public int getSolidColor() {
+ return mSolidColor;
+ }
+
+ @Override
+ protected float getTopFadingEdgeStrength() {
+ return TOP_AND_BOTTOM_FADING_EDGE_STRENGTH;
+ }
+
+ @Override
+ protected float getBottomFadingEdgeStrength() {
+ return TOP_AND_BOTTOM_FADING_EDGE_STRENGTH;
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ removeAllCallbacks();
+ }
+
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ // There is a good reason for doing this. See comments in draw().
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ // Dispatch draw to our children only if we are not currently running
+ // the animation for simultaneously fading out the scroll wheel and
+ // showing in the buttons. This class takes advantage of the View
+ // implementation of fading edges effect to draw the selector wheel.
+ // However, in View.draw(), the fading is applied after all the children
+ // have been drawn and we do not want this fading to be applied to the
+ // buttons which are currently showing in. Therefore, we draw our
+ // children
+ // after we have completed drawing ourselves.
+
+ // Draw the selector wheel if needed
+ if (mDrawSelectorWheel) {
+ super.draw(canvas);
+ }
+
+ // Draw our children if we are not showing the selector wheel of fading
+ // it out
+ if (mShowInputControlsAnimator.isRunning() || !mDrawSelectorWheel) {
+ long drawTime = getDrawingTime();
+ for (int i = 0, count = getChildCount(); i < count; i++) {
+ View child = getChildAt(i);
+ if (!child.isShown()) {
+ continue;
+ }
+ drawChild(canvas, getChildAt(i), drawTime);
+ }
+ }
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ // we only draw the selector wheel
+ if (!mDrawSelectorWheel) {
+ return;
+ }
+ float x = (mRight - mLeft) / 2;
+ float y = mCurrentScrollOffset;
+
+ int[] selectorIndices = getSelectorIndices();
+ for (int i = 0; i < selectorIndices.length; i++) {
+ int selectorIndex = selectorIndices[i];
+ String scrollSelectorValue = mSelectorIndexToStringCache.get(selectorIndex);
+ canvas.drawText(scrollSelectorValue, x, y, mSelectorPaint);
+ y += mSelectorElementHeight;
+ }
}
/**
- * Sets the current value of this NumberPicker, and sets mPrevious to the previous
- * value. If current is greater than mEnd less than mStart, the value of mCurrent
- * is wrapped around.
+ * Returns the upper value of the range of the NumberPicker
*
- * Subclasses can override this to change the wrapping behavior
+ * @return the uppper number of the range.
+ */
+ protected int getEndRange() {
+ return mEnd;
+ }
+
+ /**
+ * Returns the lower value of the range of the NumberPicker
+ *
+ * @return the lower number of the range.
+ */
+ protected int getBeginRange() {
+ return mStart;
+ }
+
+ /**
+ * Sets the current value of this NumberPicker, and sets mPrevious to the
+ * previous value. If current is greater than mEnd less than mStart, the
+ * value of mCurrent is wrapped around. Subclasses can override this to
+ * change the wrapping behavior
*
* @param current the new value of the NumberPicker
*/
- protected void changeCurrent(int current) {
+ private void changeCurrent(int current) {
+ if (mCurrent == current) {
+ return;
+ }
// Wrap around the values if we go past the start or end
- if (current > mEnd) {
- current = mStart;
- } else if (current < mStart) {
- current = mEnd;
+ if (mWrapSelector) {
+ current = getWrappedSelectorIndex(current);
}
- mPrevious = mCurrent;
- mCurrent = current;
- notifyChange();
- updateView();
+ int previous = mCurrent;
+ setCurrent(current);
+ notifyChange(previous, current);
}
/**
- * Notifies the listener, if registered, of a change of the value of this
- * NumberPicker.
+ * Sets the <code>alpha</code> of the {@link Paint} for drawing the selector
+ * wheel.
*/
- private void notifyChange() {
- if (mListener != null) {
- mListener.onChanged(this, mPrevious, mCurrent);
+ @SuppressWarnings("unused")
+ // Called by ShowInputControlsAnimator via reflection
+ private void setSelectorPaintAlpha(int alpha) {
+ mSelectorPaint.setAlpha(alpha);
+ if (mDrawSelectorWheel) {
+ invalidate();
}
}
/**
- * Updates the view of this NumberPicker. If displayValues were specified
- * in {@link #setRange}, the string corresponding to the index specified by
- * the current value will be returned. Otherwise, the formatter specified
- * in {@link setFormatter} will be used to format the number.
+ * @return If the <code>event</code> is in the input text.
*/
- private void updateView() {
- /* If we don't have displayed values then use the
- * current number else find the correct value in the
- * displayed values for the current number.
- */
- if (mDisplayedValues == null) {
- mText.setText(formatNumber(mCurrent));
+ private boolean isEventInInputText(MotionEvent event) {
+ mInputText.getHitRect(mTempRect);
+ return mTempRect.contains((int) event.getX(), (int) event.getY());
+ }
+
+ /**
+ * Sets if to <code>drawSelectionWheel</code>.
+ */
+ private void setDrawSelectorWheel(boolean drawSelectorWheel) {
+ mDrawSelectorWheel = drawSelectorWheel;
+ // do not fade if the selector wheel not shown
+ setVerticalFadingEdgeEnabled(drawSelectorWheel);
+ }
+
+ /**
+ * Callback invoked upon completion of a given <code>scroller</code>.
+ */
+ private void onScrollerFinished(Scroller scroller) {
+ if (scroller == mFlingScroller) {
+ postAdjustScrollerCommand(0);
} else {
- mText.setText(mDisplayedValues[mCurrent - mStart]);
+ showInputControls();
+ updateInputTextView();
}
- mText.setSelection(mText.getText().length());
}
- private void validateCurrentView(CharSequence str) {
- int val = getSelectedPos(str.toString());
- if ((val >= mStart) && (val <= mEnd)) {
- if (mCurrent != val) {
- mPrevious = mCurrent;
- mCurrent = val;
- notifyChange();
+ /**
+ * Flings the selector with the given <code>velocityY</code>.
+ */
+ private void fling(int velocityY) {
+ mPreviousScrollerY = 0;
+ Scroller flingScroller = mFlingScroller;
+
+ if (mWrapSelector) {
+ if (velocityY > 0) {
+ flingScroller.fling(0, 0, 0, velocityY, 0, 0, 0, Integer.MAX_VALUE);
+ } else {
+ flingScroller.fling(0, Integer.MAX_VALUE, 0, velocityY, 0, 0, 0, Integer.MAX_VALUE);
+ }
+ } else {
+ if (velocityY > 0) {
+ int maxY = mTextSize * (mCurrent - mStart);
+ flingScroller.fling(0, 0, 0, velocityY, 0, 0, 0, maxY);
+ } else {
+ int startY = mTextSize * (mEnd - mCurrent);
+ int maxY = startY;
+ flingScroller.fling(0, startY, 0, velocityY, 0, 0, 0, maxY);
}
}
- updateView();
+
+ postAdjustScrollerCommand(flingScroller.getDuration());
+ invalidate();
}
- private void validateInput(View v) {
- String str = String.valueOf(((TextView) v).getText());
- if ("".equals(str)) {
+ /**
+ * Hides the input controls which is the up/down arrows and the text field.
+ */
+ private void hideInputControls() {
+ mShowInputControlsAnimator.cancel();
+ mIncrementButton.setVisibility(INVISIBLE);
+ mDecrementButton.setVisibility(INVISIBLE);
+ mInputText.setVisibility(INVISIBLE);
+ }
- // Restore to the old value as we don't allow empty values
- updateView();
- } else {
+ /**
+ * Show the input controls by making them visible and animating the alpha
+ * property up/down arrows.
+ */
+ private void showInputControls() {
+ updateIncrementAndDecrementButtonsVisibilityState();
+ mInputText.setVisibility(VISIBLE);
+ mShowInputControlsAnimator.start();
+ }
- // Check the new value and ensure it's in range
- validateCurrentView(str);
+ /**
+ * Updates the visibility state of the increment and decrement buttons.
+ */
+ private void updateIncrementAndDecrementButtonsVisibilityState() {
+ if (mWrapSelector || mCurrent < mEnd) {
+ mIncrementButton.setVisibility(VISIBLE);
+ } else {
+ mIncrementButton.setVisibility(INVISIBLE);
+ }
+ if (mWrapSelector || mCurrent > mStart) {
+ mDecrementButton.setVisibility(VISIBLE);
+ } else {
+ mDecrementButton.setVisibility(INVISIBLE);
}
}
/**
- * @hide
+ * @return The selector indices array with proper values with the current as
+ * the middle one.
*/
- public void cancelIncrement() {
- mIncrement = false;
+ private int[] getSelectorIndices() {
+ int current = getCurrent();
+ if (mSelectorIndices[SELECTOR_MIDDLE_ITEM_INDEX] != current) {
+ for (int i = 0; i < mSelectorIndices.length; i++) {
+ int selectorIndex = current + (i - SELECTOR_MIDDLE_ITEM_INDEX);
+ if (mWrapSelector) {
+ selectorIndex = getWrappedSelectorIndex(selectorIndex);
+ }
+ mSelectorIndices[i] = selectorIndex;
+ ensureCachedScrollSelectorValue(mSelectorIndices[i]);
+ }
+ }
+ return mSelectorIndices;
}
/**
- * @hide
+ * @return The wrapped index <code>selectorIndex</code> value.
+ * <p>
+ * Note: The absolute value of the argument is never larger than
+ * mEnd - mStart.
+ * </p>
*/
- public void cancelDecrement() {
- mDecrement = false;
+ private int getWrappedSelectorIndex(int selectorIndex) {
+ if (selectorIndex > mEnd) {
+ return (Math.abs(selectorIndex) - mEnd);
+ } else if (selectorIndex < mStart) {
+ return (mEnd - Math.abs(selectorIndex));
+ }
+ return selectorIndex;
}
- private static final char[] DIGIT_CHARACTERS = new char[] {
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
- };
+ /**
+ * Increments the <code>selectorIndices</code> whose string representations
+ * will be displayed in the selector.
+ */
+ private void incrementScrollSelectorIndices(int[] selectorIndices) {
+ for (int i = 0; i < selectorIndices.length - 1; i++) {
+ selectorIndices[i] = selectorIndices[i + 1];
+ }
+ int nextScrollSelectorIndex = selectorIndices[selectorIndices.length - 2] + 1;
+ if (mWrapSelector && nextScrollSelectorIndex > mEnd) {
+ nextScrollSelectorIndex = mStart;
+ }
+ selectorIndices[selectorIndices.length - 1] = nextScrollSelectorIndex;
+ ensureCachedScrollSelectorValue(nextScrollSelectorIndex);
+ }
- private NumberPickerButton mIncrementButton;
- private NumberPickerButton mDecrementButton;
+ /**
+ * Decrements the <code>selectorIndices</code> whose string representations
+ * will be displayed in the selector.
+ */
+ private void decrementSelectorIndices(int[] selectorIndices) {
+ for (int i = selectorIndices.length - 1; i > 0; i--) {
+ selectorIndices[i] = selectorIndices[i - 1];
+ }
+ int nextScrollSelectorIndex = selectorIndices[1] - 1;
+ if (mWrapSelector && nextScrollSelectorIndex < mStart) {
+ nextScrollSelectorIndex = mEnd;
+ }
+ selectorIndices[0] = nextScrollSelectorIndex;
+ ensureCachedScrollSelectorValue(nextScrollSelectorIndex);
+ }
- private class NumberPickerInputFilter implements InputFilter {
- public CharSequence filter(CharSequence source, int start, int end,
- Spanned dest, int dstart, int dend) {
- if (mDisplayedValues == null) {
- return mNumberInputFilter.filter(source, start, end, dest, dstart, dend);
- }
- CharSequence filtered = String.valueOf(source.subSequence(start, end));
- String result = String.valueOf(dest.subSequence(0, dstart))
- + filtered
- + dest.subSequence(dend, dest.length());
- String str = String.valueOf(result).toLowerCase();
- for (String val : mDisplayedValues) {
- val = val.toLowerCase();
- if (val.startsWith(str)) {
- return filtered;
- }
+ /**
+ * Ensures we have a cached string representation of the given <code>
+ * selectorIndex</code>
+ * to avoid multiple instantiations of the same string.
+ */
+ private void ensureCachedScrollSelectorValue(int selectorIndex) {
+ SparseArray<String> cache = mSelectorIndexToStringCache;
+ String scrollSelectorValue = cache.get(selectorIndex);
+ if (scrollSelectorValue != null) {
+ return;
+ }
+ if (selectorIndex < mStart || selectorIndex > mEnd) {
+ scrollSelectorValue = "";
+ } else {
+ if (mDisplayedValues != null) {
+ scrollSelectorValue = mDisplayedValues[selectorIndex];
+ } else {
+ scrollSelectorValue = formatNumber(selectorIndex);
}
- return "";
}
+ cache.put(selectorIndex, scrollSelectorValue);
}
- private class NumberRangeKeyListener extends NumberKeyListener {
+ private String formatNumber(int value) {
+ return (mFormatter != null) ? mFormatter.toString(value) : String.valueOf(value);
+ }
- // XXX This doesn't allow for range limits when controlled by a
- // soft input method!
- public int getInputType() {
- return InputType.TYPE_CLASS_NUMBER;
+ private void validateInputTextView(View v) {
+ String str = String.valueOf(((TextView) v).getText());
+ if (TextUtils.isEmpty(str)) {
+ // Restore to the old value as we don't allow empty values
+ updateInputTextView();
+ } else {
+ // Check the new value and ensure it's in range
+ int current = getSelectedPos(str.toString());
+ changeCurrent(current);
}
+ }
- @Override
- protected char[] getAcceptedChars() {
- return DIGIT_CHARACTERS;
+ /**
+ * Updates the view of this NumberPicker. If displayValues were specified in
+ * {@link #setRange}, the string corresponding to the index specified by the
+ * current value will be returned. Otherwise, the formatter specified in
+ * {@link #setFormatter} will be used to format the number.
+ */
+ private void updateInputTextView() {
+ /*
+ * If we don't have displayed values then use the current number else
+ * find the correct value in the displayed values for the current
+ * number.
+ */
+ if (mDisplayedValues == null) {
+ mInputText.setText(formatNumber(mCurrent));
+ } else {
+ mInputText.setText(mDisplayedValues[mCurrent - mStart]);
}
+ mInputText.setSelection(mInputText.getText().length());
+ }
- @Override
- public CharSequence filter(CharSequence source, int start, int end,
- Spanned dest, int dstart, int dend) {
-
- CharSequence filtered = super.filter(source, start, end, dest, dstart, dend);
- if (filtered == null) {
- filtered = source.subSequence(start, end);
- }
-
- String result = String.valueOf(dest.subSequence(0, dstart))
- + filtered
- + dest.subSequence(dend, dest.length());
+ /**
+ * Notifies the listener, if registered, of a change of the value of this
+ * NumberPicker.
+ */
+ private void notifyChange(int previous, int current) {
+ if (mListener != null) {
+ mListener.onChanged(this, previous, mCurrent);
+ }
+ }
- if ("".equals(result)) {
- return result;
- }
- int val = getSelectedPos(result);
+ /**
+ * Posts a command for updating the current value every <code>updateMillis
+ * </code>.
+ */
+ private void postUpdateValueFromLongPress(int updateMillis) {
+ mInputText.clearFocus();
+ removeAllCallbacks();
+ if (mUpdateFromLongPressCommand == null) {
+ mUpdateFromLongPressCommand = new UpdateValueFromLongPressCommand();
+ }
+ mUpdateFromLongPressCommand.setUpdateStep(updateMillis);
+ post(mUpdateFromLongPressCommand);
+ }
- /* Ensure the user can't type in a value greater
- * than the max allowed. We have to allow less than min
- * as the user might want to delete some numbers
- * and then type a new number.
- */
- if (val > mEnd) {
- return "";
- } else {
- return filtered;
- }
+ /**
+ * Removes all pending callback from the message queue.
+ */
+ private void removeAllCallbacks() {
+ if (mUpdateFromLongPressCommand != null) {
+ removeCallbacks(mUpdateFromLongPressCommand);
+ }
+ if (mAdjustScrollerCommand != null) {
+ removeCallbacks(mAdjustScrollerCommand);
+ }
+ if (mSetSelectionCommand != null) {
+ removeCallbacks(mSetSelectionCommand);
}
}
- private int getSelectedPos(String str) {
+ /**
+ * @return The selected index given its displayed <code>value</code>.
+ */
+ private int getSelectedPos(String value) {
if (mDisplayedValues == null) {
try {
- return Integer.parseInt(str);
+ return Integer.parseInt(value);
} catch (NumberFormatException e) {
- /* Ignore as if it's not a number we don't care */
+ // Ignore as if it's not a number we don't care
}
} else {
for (int i = 0; i < mDisplayedValues.length; i++) {
- /* Don't force the user to type in jan when ja will do */
- str = str.toLowerCase();
- if (mDisplayedValues[i].toLowerCase().startsWith(str)) {
+ // Don't force the user to type in jan when ja will do
+ value = value.toLowerCase();
+ if (mDisplayedValues[i].toLowerCase().startsWith(value)) {
return mStart + i;
}
}
- /* The user might have typed in a number into the month field i.e.
+ /*
+ * The user might have typed in a number into the month field i.e.
* 10 instead of OCT so support that too.
*/
try {
- return Integer.parseInt(str);
+ return Integer.parseInt(value);
} catch (NumberFormatException e) {
- /* Ignore as if it's not a number we don't care */
+ // Ignore as if it's not a number we don't care
}
}
return mStart;
}
/**
- * Returns the current value of the NumberPicker
- * @return the current value.
+ * Posts an {@link SetSelectionCommand} from the given <code>selectionStart
+ * </code> to
+ * <code>selectionEnd</code>.
*/
- public int getCurrent() {
- return mCurrent;
+ private void postSetSelectionCommand(int selectionStart, int selectionEnd) {
+ if (mSetSelectionCommand == null) {
+ mSetSelectionCommand = new SetSelectionCommand();
+ } else {
+ removeCallbacks(mSetSelectionCommand);
+ }
+ mSetSelectionCommand.mSelectionStart = selectionStart;
+ mSetSelectionCommand.mSelectionEnd = selectionEnd;
+ post(mSetSelectionCommand);
}
/**
- * Returns the upper value of the range of the NumberPicker
- * @return the uppper number of the range.
+ * Posts an {@link AdjustScrollerCommand} within the given <code>
+ * delayMillis</code>
+ * .
*/
- protected int getEndRange() {
- return mEnd;
+ private void postAdjustScrollerCommand(int delayMillis) {
+ if (mAdjustScrollerCommand == null) {
+ mAdjustScrollerCommand = new AdjustScrollerCommand();
+ } else {
+ removeCallbacks(mAdjustScrollerCommand);
+ }
+ postDelayed(mAdjustScrollerCommand, delayMillis);
}
/**
- * Returns the lower value of the range of the NumberPicker
- * @return the lower number of the range.
+ * Filter for accepting only valid indices or prefixes of the string
+ * representation of valid indices.
*/
- protected int getBeginRange() {
- return mStart;
+ class InputTextFilter extends NumberKeyListener {
+
+ // XXX This doesn't allow for range limits when controlled by a
+ // soft input method!
+ public int getInputType() {
+ return InputType.TYPE_CLASS_TEXT;
+ }
+
+ @Override
+ protected char[] getAcceptedChars() {
+ return DIGIT_CHARACTERS;
+ }
+
+ @Override
+ public CharSequence filter(CharSequence source, int start, int end, Spanned dest,
+ int dstart, int dend) {
+ if (mDisplayedValues == null) {
+ CharSequence filtered = super.filter(source, start, end, dest, dstart, dend);
+ if (filtered == null) {
+ filtered = source.subSequence(start, end);
+ }
+
+ String result = String.valueOf(dest.subSequence(0, dstart)) + filtered
+ + dest.subSequence(dend, dest.length());
+
+ if ("".equals(result)) {
+ return result;
+ }
+ int val = getSelectedPos(result);
+
+ /*
+ * Ensure the user can't type in a value greater than the max
+ * allowed. We have to allow less than min as the user might
+ * want to delete some numbers and then type a new number.
+ */
+ if (val > mEnd) {
+ return "";
+ } else {
+ return filtered;
+ }
+ } else {
+ CharSequence filtered = String.valueOf(source.subSequence(start, end));
+ if (TextUtils.isEmpty(filtered)) {
+ return "";
+ }
+ String result = String.valueOf(dest.subSequence(0, dstart)) + filtered
+ + dest.subSequence(dend, dest.length());
+ String str = String.valueOf(result).toLowerCase();
+ for (String val : mDisplayedValues) {
+ String valLowerCase = val.toLowerCase();
+ if (valLowerCase.startsWith(str)) {
+ postSetSelectionCommand(result.length(), val.length());
+ return val.subSequence(dstart, val.length());
+ }
+ }
+ return "";
+ }
+ }
+ }
+
+ /**
+ * Command for setting the input text selection.
+ */
+ class SetSelectionCommand implements Runnable {
+ private int mSelectionStart;
+
+ private int mSelectionEnd;
+
+ public void run() {
+ mInputText.setSelection(mSelectionStart, mSelectionEnd);
+ }
+ }
+
+ /**
+ * Command for adjusting the scroller to show in its center the closest of
+ * the displayed items.
+ */
+ class AdjustScrollerCommand implements Runnable {
+ public void run() {
+ mPreviousScrollerY = 0;
+ int deltaY = mInitialScrollOffset - mCurrentScrollOffset;
+ float delayCoef = (float) Math.abs(deltaY) / (float) mTextSize;
+ int duration = (int) (delayCoef * SELECTOR_ADJUSTMENT_DURATION_MILLIS);
+ mAdjustScroller.startScroll(0, 0, 0, deltaY, duration);
+ invalidate();
+ }
+ }
+
+ /**
+ * Command for updating the current value from a long press.
+ */
+ class UpdateValueFromLongPressCommand implements Runnable {
+ private int mUpdateStep = 0;
+
+ private void setUpdateStep(int updateStep) {
+ mUpdateStep = updateStep;
+ }
+
+ public void run() {
+ changeCurrent(mCurrent + mUpdateStep);
+ postDelayed(this, mLongPressUpdateSpeed);
+ }
}
}
diff --git a/core/java/android/widget/NumberPickerButton.java b/core/java/android/widget/NumberPickerButton.java
deleted file mode 100644
index 292b668..0000000
--- a/core/java/android/widget/NumberPickerButton.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.widget;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.widget.ImageButton;
-import android.widget.NumberPicker;
-
-import com.android.internal.R;
-
-/**
- * This class exists purely to cancel long click events, that got
- * started in NumberPicker
- */
-class NumberPickerButton extends ImageButton {
-
- private NumberPicker mNumberPicker;
-
- public NumberPickerButton(Context context, AttributeSet attrs,
- int defStyle) {
- super(context, attrs, defStyle);
- }
-
- public NumberPickerButton(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public NumberPickerButton(Context context) {
- super(context);
- }
-
- public void setNumberPicker(NumberPicker picker) {
- mNumberPicker = picker;
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- cancelLongpressIfRequired(event);
- return super.onTouchEvent(event);
- }
-
- @Override
- public boolean onTrackballEvent(MotionEvent event) {
- cancelLongpressIfRequired(event);
- return super.onTrackballEvent(event);
- }
-
- @Override
- public boolean onKeyUp(int keyCode, KeyEvent event) {
- if ((keyCode == KeyEvent.KEYCODE_DPAD_CENTER)
- || (keyCode == KeyEvent.KEYCODE_ENTER)) {
- cancelLongpress();
- }
- return super.onKeyUp(keyCode, event);
- }
-
- private void cancelLongpressIfRequired(MotionEvent event) {
- if ((event.getAction() == MotionEvent.ACTION_CANCEL)
- || (event.getAction() == MotionEvent.ACTION_UP)) {
- cancelLongpress();
- }
- }
-
- private void cancelLongpress() {
- if (R.id.increment == getId()) {
- mNumberPicker.cancelIncrement();
- } else if (R.id.decrement == getId()) {
- mNumberPicker.cancelDecrement();
- }
- }
-
- public void onWindowFocusChanged(boolean hasWindowFocus) {
- super.onWindowFocusChanged(hasWindowFocus);
- if (!hasWindowFocus) {
- cancelLongpress();
- }
- }
-
-}
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
new file mode 100644
index 0000000..73a8c66
--- /dev/null
+++ b/core/java/android/widget/Switch.java
@@ -0,0 +1,631 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+import com.android.internal.R;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.Typeface;
+import android.graphics.drawable.Drawable;
+import android.text.Layout;
+import android.text.StaticLayout;
+import android.text.TextPaint;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+import android.view.ViewConfiguration;
+
+/**
+ * A Switch is a two-state toggle switch widget that can select between two
+ * options. The user may drag the "thumb" back and forth to choose the selected option,
+ * or simply tap to toggle as if it were a checkbox.
+ *
+ * @hide
+ */
+public class Switch extends CompoundButton {
+ private static final int TOUCH_MODE_IDLE = 0;
+ private static final int TOUCH_MODE_DOWN = 1;
+ private static final int TOUCH_MODE_DRAGGING = 2;
+
+ // Enum for the "typeface" XML parameter.
+ private static final int SANS = 1;
+ private static final int SERIF = 2;
+ private static final int MONOSPACE = 3;
+
+ private Drawable mThumbDrawable;
+ private Drawable mTrackDrawable;
+ private int mThumbTextPadding;
+ private int mSwitchMinWidth;
+ private int mSwitchPadding;
+ private CharSequence mTextOn;
+ private CharSequence mTextOff;
+
+ private int mTouchMode;
+ private int mTouchSlop;
+ private float mTouchX;
+ private float mTouchY;
+ private VelocityTracker mVelocityTracker = VelocityTracker.obtain();
+ private int mMinFlingVelocity;
+
+ private float mThumbPosition;
+ private int mSwitchWidth;
+ private int mSwitchHeight;
+ private int mThumbWidth; // Does not include padding
+
+ private int mSwitchLeft;
+ private int mSwitchTop;
+ private int mSwitchRight;
+ private int mSwitchBottom;
+
+ private TextPaint mTextPaint;
+ private ColorStateList mTextColors;
+ private Layout mOnLayout;
+ private Layout mOffLayout;
+
+ private final Rect mTempRect = new Rect();
+
+ private static final int[] CHECKED_STATE_SET = {
+ R.attr.state_checked
+ };
+
+ /**
+ * Construct a new Switch with default styling.
+ *
+ * @param context The Context that will determine this widget's theming.
+ */
+ public Switch(Context context) {
+ this(context, null);
+ }
+
+ /**
+ * Construct a new Switch with default styling, overriding specific style
+ * attributes as requested.
+ *
+ * @param context The Context that will determine this widget's theming.
+ * @param attrs Specification of attributes that should deviate from default styling.
+ */
+ public Switch(Context context, AttributeSet attrs) {
+ this(context, attrs, com.android.internal.R.attr.switchStyle);
+ }
+
+ /**
+ * Construct a new Switch with a default style determined by the given theme attribute,
+ * overriding specific style attributes as requested.
+ *
+ * @param context The Context that will determine this widget's theming.
+ * @param attrs Specification of attributes that should deviate from the default styling.
+ * @param defStyle An attribute ID within the active theme containing a reference to the
+ * default style for this widget. e.g. android.R.attr.switchStyle.
+ */
+ public Switch(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ mTextPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
+ Resources res = getResources();
+ mTextPaint.density = res.getDisplayMetrics().density;
+ mTextPaint.setCompatibilityScaling(res.getCompatibilityInfo().applicationScale);
+
+ TypedArray a = context.obtainStyledAttributes(attrs,
+ com.android.internal.R.styleable.Switch, defStyle, 0);
+
+ mThumbDrawable = a.getDrawable(com.android.internal.R.styleable.Switch_switchThumb);
+ mTrackDrawable = a.getDrawable(com.android.internal.R.styleable.Switch_switchTrack);
+ mTextOn = a.getText(com.android.internal.R.styleable.Switch_textOn);
+ mTextOff = a.getText(com.android.internal.R.styleable.Switch_textOff);
+ mThumbTextPadding = a.getDimensionPixelSize(
+ com.android.internal.R.styleable.Switch_thumbTextPadding, 0);
+ mSwitchMinWidth = a.getDimensionPixelSize(
+ com.android.internal.R.styleable.Switch_switchMinWidth, 0);
+ mSwitchPadding = a.getDimensionPixelSize(
+ com.android.internal.R.styleable.Switch_switchPadding, 0);
+
+ int appearance = a.getResourceId(
+ com.android.internal.R.styleable.Switch_switchTextAppearance, 0);
+ if (appearance != 0) {
+ setSwitchTextAppearance(appearance);
+ }
+ a.recycle();
+
+ ViewConfiguration config = ViewConfiguration.get(context);
+ mTouchSlop = config.getScaledTouchSlop();
+ mMinFlingVelocity = config.getScaledMinimumFlingVelocity();
+
+ // Refresh display with current params
+ setChecked(isChecked());
+ }
+
+ /**
+ * Sets the switch text color, size, style, hint color, and highlight color
+ * from the specified TextAppearance resource.
+ */
+ public void setSwitchTextAppearance(int resid) {
+ TypedArray appearance =
+ getContext().obtainStyledAttributes(resid,
+ com.android.internal.R.styleable.TextAppearance);
+
+ ColorStateList colors;
+ int ts;
+
+ colors = appearance.getColorStateList(com.android.internal.R.styleable.
+ TextAppearance_textColor);
+ if (colors != null) {
+ mTextColors = colors;
+ }
+
+ ts = appearance.getDimensionPixelSize(com.android.internal.R.styleable.
+ TextAppearance_textSize, 0);
+ if (ts != 0) {
+ if (ts != mTextPaint.getTextSize()) {
+ mTextPaint.setTextSize(ts);
+ requestLayout();
+ }
+ }
+
+ int typefaceIndex, styleIndex;
+
+ typefaceIndex = appearance.getInt(com.android.internal.R.styleable.
+ TextAppearance_typeface, -1);
+ styleIndex = appearance.getInt(com.android.internal.R.styleable.
+ TextAppearance_textStyle, -1);
+
+ setSwitchTypefaceByIndex(typefaceIndex, styleIndex);
+
+ int lineHeight = appearance.getDimensionPixelSize(
+ com.android.internal.R.styleable.TextAppearance_textLineHeight, 0);
+ if (lineHeight != 0) {
+ setLineHeight(lineHeight);
+ }
+
+ appearance.recycle();
+ }
+
+ private void setSwitchTypefaceByIndex(int typefaceIndex, int styleIndex) {
+ Typeface tf = null;
+ switch (typefaceIndex) {
+ case SANS:
+ tf = Typeface.SANS_SERIF;
+ break;
+
+ case SERIF:
+ tf = Typeface.SERIF;
+ break;
+
+ case MONOSPACE:
+ tf = Typeface.MONOSPACE;
+ break;
+ }
+
+ setSwitchTypeface(tf, styleIndex);
+ }
+
+ /**
+ * Sets the typeface and style in which the text should be displayed on the
+ * switch, and turns on the fake bold and italic bits in the Paint if the
+ * Typeface that you provided does not have all the bits in the
+ * style that you specified.
+ */
+ public void setSwitchTypeface(Typeface tf, int style) {
+ if (style > 0) {
+ if (tf == null) {
+ tf = Typeface.defaultFromStyle(style);
+ } else {
+ tf = Typeface.create(tf, style);
+ }
+
+ setSwitchTypeface(tf);
+ // now compute what (if any) algorithmic styling is needed
+ int typefaceStyle = tf != null ? tf.getStyle() : 0;
+ int need = style & ~typefaceStyle;
+ mTextPaint.setFakeBoldText((need & Typeface.BOLD) != 0);
+ mTextPaint.setTextSkewX((need & Typeface.ITALIC) != 0 ? -0.25f : 0);
+ } else {
+ mTextPaint.setFakeBoldText(false);
+ mTextPaint.setTextSkewX(0);
+ setSwitchTypeface(tf);
+ }
+ }
+
+ /**
+ * Sets the typeface and style in which the text should be displayed on the switch.
+ * Note that not all Typeface families actually have bold and italic
+ * variants, so you may need to use
+ * {@link #setSwitchTypeface(Typeface, int)} to get the appearance
+ * that you actually want.
+ *
+ * @attr ref android.R.styleable#TextView_typeface
+ * @attr ref android.R.styleable#TextView_textStyle
+ */
+ public void setSwitchTypeface(Typeface tf) {
+ if (mTextPaint.getTypeface() != tf) {
+ mTextPaint.setTypeface(tf);
+
+ requestLayout();
+ invalidate();
+ }
+ }
+
+ /**
+ * Returns the text for when the button is in the checked state.
+ *
+ * @return The text.
+ */
+ public CharSequence getTextOn() {
+ return mTextOn;
+ }
+
+ /**
+ * Sets the text for when the button is in the checked state.
+ *
+ * @param textOn The text.
+ */
+ public void setTextOn(CharSequence textOn) {
+ mTextOn = textOn;
+ requestLayout();
+ }
+
+ /**
+ * Returns the text for when the button is not in the checked state.
+ *
+ * @return The text.
+ */
+ public CharSequence getTextOff() {
+ return mTextOff;
+ }
+
+ /**
+ * Sets the text for when the button is not in the checked state.
+ *
+ * @param textOff The text.
+ */
+ public void setTextOff(CharSequence textOff) {
+ mTextOff = textOff;
+ requestLayout();
+ }
+
+ @Override
+ public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+ final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+ int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+ int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+
+
+ if (mOnLayout == null) {
+ mOnLayout = makeLayout(mTextOn);
+ }
+ if (mOffLayout == null) {
+ mOffLayout = makeLayout(mTextOff);
+ }
+
+ mTrackDrawable.getPadding(mTempRect);
+ final int maxTextWidth = Math.max(mOnLayout.getWidth(), mOffLayout.getWidth());
+ final int switchWidth = Math.max(mSwitchMinWidth,
+ maxTextWidth * 2 + mThumbTextPadding * 4 + mTempRect.left + mTempRect.right);
+ final int switchHeight = mTrackDrawable.getIntrinsicHeight();
+
+ mThumbWidth = maxTextWidth + mThumbTextPadding * 2;
+
+ switch (widthMode) {
+ case MeasureSpec.AT_MOST:
+ widthSize = Math.min(widthSize, switchWidth);
+ break;
+
+ case MeasureSpec.UNSPECIFIED:
+ widthSize = switchWidth;
+ break;
+
+ case MeasureSpec.EXACTLY:
+ // Just use what we were given
+ break;
+ }
+
+ switch (heightMode) {
+ case MeasureSpec.AT_MOST:
+ heightSize = Math.min(heightSize, switchHeight);
+ break;
+
+ case MeasureSpec.UNSPECIFIED:
+ heightSize = switchHeight;
+ break;
+
+ case MeasureSpec.EXACTLY:
+ // Just use what we were given
+ break;
+ }
+
+ mSwitchWidth = switchWidth;
+ mSwitchHeight = switchHeight;
+
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ final int measuredWidth = getMeasuredWidth();
+ final int measuredHeight = getMeasuredHeight();
+ if (measuredHeight < switchHeight) {
+ setMeasuredDimension(measuredWidth, switchHeight);
+ }
+ }
+
+ private Layout makeLayout(CharSequence text) {
+ return new StaticLayout(text, mTextPaint,
+ (int) Math.ceil(Layout.getDesiredWidth(text, mTextPaint)),
+ Layout.Alignment.ALIGN_NORMAL, 1.f, 0, true);
+ }
+
+ /**
+ * @return true if (x, y) is within the target area of the switch thumb
+ */
+ private boolean hitThumb(float x, float y) {
+ mThumbDrawable.getPadding(mTempRect);
+ final int thumbTop = mSwitchTop - mTouchSlop;
+ final int thumbLeft = mSwitchLeft + (int) (mThumbPosition + 0.5f) - mTouchSlop;
+ final int thumbRight = thumbLeft + mThumbWidth +
+ mTempRect.left + mTempRect.right + mTouchSlop;
+ final int thumbBottom = mSwitchBottom + mTouchSlop;
+ return x > thumbLeft && x < thumbRight && y > thumbTop && y < thumbBottom;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ mVelocityTracker.addMovement(ev);
+ final int action = ev.getActionMasked();
+ switch (action) {
+ case MotionEvent.ACTION_DOWN: {
+ final float x = ev.getX();
+ final float y = ev.getY();
+ if (hitThumb(x, y)) {
+ mTouchMode = TOUCH_MODE_DOWN;
+ mTouchX = x;
+ mTouchY = y;
+ }
+ break;
+ }
+
+ case MotionEvent.ACTION_MOVE: {
+ switch (mTouchMode) {
+ case TOUCH_MODE_IDLE:
+ // Didn't target the thumb, treat normally.
+ break;
+
+ case TOUCH_MODE_DOWN: {
+ final float x = ev.getX();
+ final float y = ev.getY();
+ if (Math.abs(x - mTouchX) > mTouchSlop ||
+ Math.abs(y - mTouchY) > mTouchSlop) {
+ mTouchMode = TOUCH_MODE_DRAGGING;
+ getParent().requestDisallowInterceptTouchEvent(true);
+ mTouchX = x;
+ mTouchY = y;
+ return true;
+ }
+ break;
+ }
+
+ case TOUCH_MODE_DRAGGING: {
+ final float x = ev.getX();
+ final float dx = x - mTouchX;
+ float newPos = Math.max(0,
+ Math.min(mThumbPosition + dx, getThumbScrollRange()));
+ if (newPos != mThumbPosition) {
+ mThumbPosition = newPos;
+ mTouchX = x;
+ invalidate();
+ }
+ return true;
+ }
+ }
+ break;
+ }
+
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL: {
+ if (mTouchMode == TOUCH_MODE_DRAGGING) {
+ stopDrag(ev);
+ return true;
+ }
+ mTouchMode = TOUCH_MODE_IDLE;
+ mVelocityTracker.clear();
+ break;
+ }
+ }
+
+ return super.onTouchEvent(ev);
+ }
+
+ private void cancelSuperTouch(MotionEvent ev) {
+ MotionEvent cancel = MotionEvent.obtain(ev);
+ cancel.setAction(MotionEvent.ACTION_CANCEL);
+ super.onTouchEvent(cancel);
+ cancel.recycle();
+ }
+
+ /**
+ * Called from onTouchEvent to end a drag operation.
+ *
+ * @param ev Event that triggered the end of drag mode - ACTION_UP or ACTION_CANCEL
+ */
+ private void stopDrag(MotionEvent ev) {
+ mTouchMode = TOUCH_MODE_IDLE;
+ boolean commitChange = ev.getAction() == MotionEvent.ACTION_UP;
+
+ cancelSuperTouch(ev);
+
+ if (commitChange) {
+ boolean newState;
+ mVelocityTracker.computeCurrentVelocity(1000);
+ float xvel = mVelocityTracker.getXVelocity();
+ if (Math.abs(xvel) > mMinFlingVelocity) {
+ newState = xvel < 0;
+ } else {
+ newState = getTargetCheckedState();
+ }
+ animateThumbToCheckedState(newState);
+ } else {
+ animateThumbToCheckedState(isChecked());
+ }
+ }
+
+ private void animateThumbToCheckedState(boolean newCheckedState) {
+ float targetPos = newCheckedState ? 0 : getThumbScrollRange();
+ // TODO animate!
+ mThumbPosition = targetPos;
+ setChecked(newCheckedState);
+ }
+
+ private boolean getTargetCheckedState() {
+ return mThumbPosition <= getThumbScrollRange() / 2;
+ }
+
+ @Override
+ public void setChecked(boolean checked) {
+ super.setChecked(checked);
+ mThumbPosition = checked ? 0 : getThumbScrollRange();
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+
+ int switchRight = getWidth() - getPaddingRight();
+ int switchLeft = switchRight - mSwitchWidth;
+ int switchTop = 0;
+ int switchBottom = 0;
+ switch (getGravity() & Gravity.VERTICAL_GRAVITY_MASK) {
+ default:
+ case Gravity.TOP:
+ switchTop = getPaddingTop();
+ switchBottom = switchTop + mSwitchHeight;
+ break;
+
+ case Gravity.CENTER_VERTICAL:
+ switchTop = (getPaddingTop() + getHeight() - getPaddingBottom()) / 2 -
+ mSwitchHeight / 2;
+ switchBottom = switchTop + mSwitchHeight;
+ break;
+
+ case Gravity.BOTTOM:
+ switchBottom = getHeight() - getPaddingBottom();
+ switchTop = switchBottom - mSwitchHeight;
+ break;
+ }
+
+ mSwitchLeft = switchLeft;
+ mSwitchTop = switchTop;
+ mSwitchBottom = switchBottom;
+ mSwitchRight = switchRight;
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ // Draw the switch
+ int switchLeft = mSwitchLeft;
+ int switchTop = mSwitchTop;
+ int switchRight = mSwitchRight;
+ int switchBottom = mSwitchBottom;
+
+ mTrackDrawable.setBounds(switchLeft, switchTop, switchRight, switchBottom);
+ mTrackDrawable.draw(canvas);
+
+ canvas.save();
+
+ mTrackDrawable.getPadding(mTempRect);
+ int switchInnerLeft = switchLeft + mTempRect.left;
+ int switchInnerTop = switchTop + mTempRect.top;
+ int switchInnerRight = switchRight - mTempRect.right;
+ int switchInnerBottom = switchBottom - mTempRect.bottom;
+ canvas.clipRect(switchInnerLeft, switchTop, switchInnerRight, switchBottom);
+
+ mThumbDrawable.getPadding(mTempRect);
+ final int thumbPos = (int) (mThumbPosition + 0.5f);
+ int thumbLeft = switchInnerLeft - mTempRect.left + thumbPos;
+ int thumbRight = switchInnerLeft + thumbPos + mThumbWidth + mTempRect.right;
+
+ mThumbDrawable.setBounds(thumbLeft, switchTop, thumbRight, switchBottom);
+ mThumbDrawable.draw(canvas);
+
+ mTextPaint.setColor(mTextColors.getColorForState(getDrawableState(),
+ mTextColors.getDefaultColor()));
+ mTextPaint.drawableState = getDrawableState();
+
+ Layout switchText = getTargetCheckedState() ? mOnLayout : mOffLayout;
+
+ canvas.translate((thumbLeft + thumbRight) / 2 - switchText.getWidth() / 2,
+ (switchInnerTop + switchInnerBottom) / 2 - switchText.getHeight() / 2);
+ switchText.draw(canvas);
+
+ canvas.restore();
+ }
+
+ @Override
+ public int getCompoundPaddingRight() {
+ int padding = super.getCompoundPaddingRight() + mSwitchWidth;
+ if (!TextUtils.isEmpty(getText())) {
+ padding += mSwitchPadding;
+ }
+ return padding;
+ }
+
+ private int getThumbScrollRange() {
+ if (mTrackDrawable == null) {
+ return 0;
+ }
+ mTrackDrawable.getPadding(mTempRect);
+ return mSwitchWidth - mThumbWidth - mTempRect.left - mTempRect.right;
+ }
+
+ @Override
+ protected int[] onCreateDrawableState(int extraSpace) {
+ final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
+ if (isChecked()) {
+ mergeDrawableStates(drawableState, CHECKED_STATE_SET);
+ }
+ return drawableState;
+ }
+
+ @Override
+ protected void drawableStateChanged() {
+ super.drawableStateChanged();
+
+ int[] myDrawableState = getDrawableState();
+
+ // Set the state of the Drawable
+ mThumbDrawable.setState(myDrawableState);
+ mTrackDrawable.setState(myDrawableState);
+
+ invalidate();
+ }
+
+ @Override
+ protected boolean verifyDrawable(Drawable who) {
+ return super.verifyDrawable(who) || who == mThumbDrawable || who == mTrackDrawable;
+ }
+
+ @Override
+ public void jumpDrawablesToCurrentState() {
+ super.jumpDrawablesToCurrentState();
+ mThumbDrawable.jumpToCurrentState();
+ mTrackDrawable.jumpToCurrentState();
+ }
+}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 88d3f7a..57af643 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -7010,11 +7010,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (start >= prevStart && start < prevEnd) {
// Restore previous selection
Selection.setSelection((Spannable)mText, prevStart, prevEnd);
-
- if (hasSelectionController()) {
- // Revive the anchors.
- getSelectionController().show();
- }
return;
} else {
// Tapping outside stops selection mode, if any
@@ -7024,8 +7019,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
getInsertionController().show();
}
}
- } else if (hasSelection() && hasSelectionController()) {
- getSelectionController().show();
}
}
@@ -7103,7 +7096,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
handled |= mMovement.onTouchEvent(this, (Spannable) mText, event);
}
- if (isTextEditable()) {
+ if (isTextEditable() || mTextIsSelectable) {
if (mScrollX != oldScrollX || mScrollY != oldScrollY) {
// Hide insertion anchor while scrolling. Leave selection.
hideInsertionPointCursorController();
@@ -7153,7 +7146,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
mInsertionControllerEnabled = windowSupportsHandles && isTextEditable() && mCursorVisible &&
- mLayout != null && !mTextIsSelectable;
+ mLayout != null;
mSelectionControllerEnabled = windowSupportsHandles && textCanBeSelected() &&
mLayout != null;
@@ -7172,8 +7165,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* a selectable TextView.
*/
private boolean isTextEditable() {
- return (mText instanceof Editable && onCheckIsTextEditor() && isEnabled())
- || mTextIsSelectable;
+ return mText instanceof Editable && onCheckIsTextEditor() && isEnabled();
}
/**
@@ -7458,6 +7450,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
hasPrimaryClip());
}
+ private boolean isWordCharacter(int position) {
+ final char c = mTransformed.charAt(position);
+ final int type = Character.getType(c);
+ return (c == '\'' || c == '"' ||
+ type == Character.UPPERCASE_LETTER ||
+ type == Character.LOWERCASE_LETTER ||
+ type == Character.TITLECASE_LETTER ||
+ type == Character.MODIFIER_LETTER ||
+ type == Character.DECIMAL_DIGIT_NUMBER);
+ }
+
/**
* Returns the offsets delimiting the 'word' located at position offset.
*
@@ -7467,77 +7470,51 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* Returns a negative value if no valid word was found.
*/
private long getWordLimitsAt(int offset) {
- /*
- * Quick return if the input type is one where adding words
- * to the dictionary doesn't make any sense.
- */
int klass = mInputType & InputType.TYPE_MASK_CLASS;
- if (klass == InputType.TYPE_CLASS_NUMBER ||
- klass == InputType.TYPE_CLASS_PHONE ||
- klass == InputType.TYPE_CLASS_DATETIME) {
+ int variation = mInputType & InputType.TYPE_MASK_VARIATION;
+
+ // Text selection is not permitted in password fields
+ if (variation == InputType.TYPE_TEXT_VARIATION_PASSWORD ||
+ variation == InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD ||
+ variation == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) {
return -1;
}
- int variation = mInputType & InputType.TYPE_MASK_VARIATION;
- if (variation == InputType.TYPE_TEXT_VARIATION_URI ||
- variation == InputType.TYPE_TEXT_VARIATION_PASSWORD ||
- variation == InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD ||
- variation == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD ||
- variation == InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS ||
- variation == InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS ||
- variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
- return -1;
+ final int len = mText.length();
+
+ // Specific text fields: always select the entire text
+ if (klass == InputType.TYPE_CLASS_NUMBER ||
+ klass == InputType.TYPE_CLASS_PHONE ||
+ klass == InputType.TYPE_CLASS_DATETIME ||
+ variation == InputType.TYPE_TEXT_VARIATION_URI ||
+ variation == InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS ||
+ variation == InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS ||
+ variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
+ return len > 0 ? packRangeInLong(0, len) : -1;
}
- int len = mText.length();
int end = Math.min(offset, len);
-
if (end < 0) {
return -1;
}
+ final int MAX_LENGTH = 48;
int start = end;
for (; start > 0; start--) {
- char c = mTransformed.charAt(start - 1);
- int type = Character.getType(c);
-
- // Cases where the text ends with a '.' and we select from the end of the line (right
- // after the dot), or when we select from the space character in "aaaa, bbbb".
- if (start == end && type == Character.OTHER_PUNCTUATION) continue;
-
- if (c != '\'' &&
- type != Character.UPPERCASE_LETTER &&
- type != Character.LOWERCASE_LETTER &&
- type != Character.TITLECASE_LETTER &&
- type != Character.MODIFIER_LETTER &&
- type != Character.DECIMAL_DIGIT_NUMBER) {
- break;
- }
+ if (!isWordCharacter(start - 1)) break;
+ if ((end - start) > MAX_LENGTH) return -1;
}
for (; end < len; end++) {
- char c = mTransformed.charAt(end);
- int type = Character.getType(c);
-
- if (c != '\'' &&
- type != Character.UPPERCASE_LETTER &&
- type != Character.LOWERCASE_LETTER &&
- type != Character.TITLECASE_LETTER &&
- type != Character.MODIFIER_LETTER &&
- type != Character.DECIMAL_DIGIT_NUMBER) {
- break;
- }
+ if (!isWordCharacter(end)) break;
+ if ((end - start) > MAX_LENGTH) return -1;
}
if (start == end) {
return -1;
}
- if (end - start > 48) {
- return -1;
- }
-
boolean hasLetter = false;
for (int i = start; i < end; i++) {
if (Character.isLetter(mTransformed.charAt(i))) {
@@ -7748,7 +7725,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
if (clip != null) {
- clipboard.setPrimaryClip(clip);
+ setPrimaryClip(clip);
}
}
return true;
@@ -7764,14 +7741,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
/**
* Prepare text so that there are not zero or two spaces at beginning and end of region defined
* by [min, max] when replacing this region by paste.
+ * Note that if there was two spaces (or more) at that position before, they are kept. We just
+ * make sure we do not add an extra one from the paste content.
*/
private long prepareSpacesAroundPaste(int min, int max, CharSequence paste) {
// Paste adds/removes spaces before or after insertion as needed.
- if (Character.isSpaceChar(paste.charAt(0))) {
+ if (paste.length() > 0 && Character.isSpaceChar(paste.charAt(0))) {
if (min > 0 && Character.isSpaceChar(mTransformed.charAt(min - 1))) {
// Two spaces at beginning of paste: remove one
final int originalLength = mText.length();
- ((Editable) mText).replace(min - 1, min, "");
+ ((Editable) mText).delete(min - 1, min);
// Due to filters, there is no guarantee that exactly one character was
// removed. Count instead.
final int delta = mText.length() - originalLength;
@@ -7790,10 +7769,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
- if (Character.isSpaceChar(paste.charAt(paste.length() - 1))) {
+ if (paste.length() > 0 && Character.isSpaceChar(paste.charAt(paste.length() - 1))) {
if (max < mText.length() && Character.isSpaceChar(mTransformed.charAt(max))) {
// Two spaces at end of paste: remove one
- ((Editable) mText).replace(max, max + 1, "");
+ ((Editable) mText).delete(max, max + 1);
}
} else {
if (max < mText.length() && !Character.isSpaceChar(mTransformed.charAt(max))) {
@@ -7801,6 +7780,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
((Editable) mText).replace(max, max, " ");
}
}
+
return packRangeInLong(min, max);
}
@@ -7839,26 +7819,31 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return true;
}
- if (!isPositionOnText(mLastDownPositionX, mLastDownPositionY) && mInsertionControllerEnabled) {
+ if (!isPositionOnText(mLastDownPositionX, mLastDownPositionY) &&
+ mInsertionControllerEnabled) {
+ // Long press in empty space moves cursor and shows the Paste affordance if available.
final int offset = getOffset(mLastDownPositionX, mLastDownPositionY);
+ stopSelectionActionMode();
Selection.setSelection((Spannable)mText, offset);
- if (canPaste()) {
- getInsertionController().showWithPaste();
- performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- } else {
- getInsertionController().show();
- }
+ getInsertionController().show(0);
mEatTouchRelease = true;
return true;
}
- if (mSelectionActionMode != null && touchPositionIsInSelection()) {
- final int start = getSelectionStart();
- final int end = getSelectionEnd();
- CharSequence selectedText = mTransformed.subSequence(start, end);
- ClipData data = ClipData.newPlainText(null, null, selectedText);
- startDrag(data, getTextThumbnailBuilder(selectedText), false);
- stopSelectionActionMode();
+ if (mSelectionActionMode != null) {
+ if (touchPositionIsInSelection()) {
+ // Start a drag
+ final int start = getSelectionStart();
+ final int end = getSelectionEnd();
+ CharSequence selectedText = mTransformed.subSequence(start, end);
+ ClipData data = ClipData.newPlainText(null, null, selectedText);
+ startDrag(data, getTextThumbnailBuilder(selectedText), false);
+ mDragSourcePositions = packRangeInLong(start, end);
+ stopSelectionActionMode();
+ } else {
+ selectCurrentWord();
+ getSelectionController().show();
+ }
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
mEatTouchRelease = true;
return true;
@@ -7950,10 +7935,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
/**
* Paste clipboard content between min and max positions.
- *
- * @param clipboard getSystemService(Context.CLIPBOARD_SERVICE)
*/
- private void paste(ClipboardManager clipboard, int min, int max) {
+ private void paste(int min, int max) {
+ ClipboardManager clipboard =
+ (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = clipboard.getPrimaryClip();
if (clip != null) {
boolean didfirst = false;
@@ -7973,9 +7958,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
stopSelectionActionMode();
+ sLastCutOrCopyTime = 0;
}
}
+ private void setPrimaryClip(ClipData clip) {
+ ClipboardManager clipboard = (ClipboardManager) getContext().
+ getSystemService(Context.CLIPBOARD_SERVICE);
+ clipboard.setPrimaryClip(clip);
+ sLastCutOrCopyTime = SystemClock.uptimeMillis();
+ }
+
private class SelectionActionModeCallback implements ActionMode.Callback {
@Override
@@ -8061,9 +8054,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return true;
}
- ClipboardManager clipboard = (ClipboardManager) getContext().
- getSystemService(Context.CLIPBOARD_SERVICE);
-
int min = 0;
int max = mText.length();
@@ -8077,18 +8067,18 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
switch (item.getItemId()) {
case ID_PASTE:
- paste(clipboard, min, max);
+ paste(min, max);
return true;
case ID_CUT:
- clipboard.setPrimaryClip(ClipData.newPlainText(null, null,
+ setPrimaryClip(ClipData.newPlainText(null, null,
mTransformed.subSequence(min, max)));
((Editable) mText).delete(min, max);
stopSelectionActionMode();
return true;
case ID_COPY:
- clipboard.setPrimaryClip(ClipData.newPlainText(null, null,
+ setPrimaryClip(ClipData.newPlainText(null, null,
mTransformed.subSequence(min, max)));
stopSelectionActionMode();
return true;
@@ -8211,9 +8201,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
public void onClick(View v) {
if (canPaste()) {
- ClipboardManager clipboard =
- (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
- paste(clipboard, getSelectionStart(), getSelectionEnd());
+ paste(getSelectionStart(), getSelectionEnd());
}
hide();
}
@@ -8502,6 +8490,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
case MotionEvent.ACTION_UP:
if (mPastePopupWindow != null) {
+ // Will show the paste popup after a delay.
+ mController.show();
+ /* TEMP USER TEST: Display Paste as soon as handle is draggged
long delay = SystemClock.uptimeMillis() - mTouchTimer;
if (delay < ViewConfiguration.getTapTimeout()) {
final float touchOffsetX = ev.getRawX() - mPositionX;
@@ -8515,7 +8506,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (distanceSquared < slopSquared) {
showPastePopupWindow();
}
- }
+ }*/
}
mIsDragging = false;
break;
@@ -8561,6 +8552,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private class InsertionPointCursorController implements CursorController {
private static final int DELAY_BEFORE_FADE_OUT = 4100;
+ private static final int DELAY_BEFORE_PASTE = 2000;
+ private static final int RECENT_CUT_COPY_DURATION = 15 * 1000;
// The cursor controller image. Lazily created.
private HandleView mHandle;
@@ -8571,14 +8564,27 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
};
+ private final Runnable mPastePopupShower = new Runnable() {
+ public void run() {
+ getHandle().showPastePopupWindow();
+ }
+ };
+
public void show() {
- updatePosition();
- getHandle().show();
+ show(DELAY_BEFORE_PASTE);
}
- void showWithPaste() {
- show();
- getHandle().showPastePopupWindow();
+ public void show(int delayBeforePaste) {
+ updatePosition();
+ hideDelayed();
+ getHandle().show();
+ removeCallbacks(mPastePopupShower);
+ if (canPaste()) {
+ final long durationSinceCutOrCopy = SystemClock.uptimeMillis() - sLastCutOrCopyTime;
+ if (durationSinceCutOrCopy < RECENT_CUT_COPY_DURATION)
+ delayBeforePaste = 0;
+ postDelayed(mPastePopupShower, delayBeforePaste);
+ }
}
public void hide() {
@@ -8586,6 +8592,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mHandle.hide();
}
removeCallbacks(mHider);
+ removeCallbacks(mPastePopupShower);
}
private void hideDelayed() {
@@ -8618,7 +8625,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return;
}
- // updatePosition is called only when isShowing. Handle has been created at this point.
getHandle().positionAtCursor(offset, true);
}
@@ -8653,14 +8659,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private int mPreviousTapPositionX;
private int mPreviousTapPositionY;
- private static final int DELAY_BEFORE_FADE_OUT = 4100;
-
- private final Runnable mHider = new Runnable() {
- public void run() {
- hide();
- }
- };
-
SelectionModifierCursorController() {
resetTouchOffsets();
}
@@ -8687,12 +8685,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (mStartHandle != null) mStartHandle.hide();
if (mEndHandle != null) mEndHandle.hide();
mIsShowing = false;
- removeCallbacks(mHider);
- }
-
- private void hideDelayed() {
- removeCallbacks(mHider);
- postDelayed(mHider, DELAY_BEFORE_FADE_OUT);
}
public boolean isShowing() {
@@ -8755,13 +8747,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// The handles have been created since the controller isShowing().
mStartHandle.positionAtCursor(selectionStart, true);
mEndHandle.positionAtCursor(selectionEnd, true);
- hideDelayed();
}
public boolean onTouchEvent(MotionEvent event) {
// This is done even when the View does not have focus, so that long presses can start
// selection and tap can move cursor from this tap position.
- if (isTextEditable()) {
+ if (isTextEditable() || mTextIsSelectable) {
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
final int x = (int) event.getX();
@@ -8781,9 +8772,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
final int slopSquared = doubleTapSlop * doubleTapSlop;
if (distanceSquared < slopSquared) {
startSelectionActionMode();
- // Hacky: onTapUpEvent will open a context menu with cut/copy
- // Prevent this by hiding handles which will be revived instead.
- hide();
}
}
@@ -8967,17 +8955,58 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
Item item = clipData.getItem(i);
content.append(item.coerceToText(TextView.this.mContext));
}
+
final int offset = getOffset((int) event.getX(), (int) event.getY());
+
+ if (mDragSourcePositions != -1) {
+ final int dragSourceStart = extractRangeStartFromLong(mDragSourcePositions);
+ final int dragSourceEnd = extractRangeEndFromLong(mDragSourcePositions);
+ if (offset >= dragSourceStart && offset < dragSourceEnd) {
+ // A drop inside the original selection discards the drop.
+ return true;
+ }
+ }
+
+ final int originalLength = mText.length();
long minMax = prepareSpacesAroundPaste(offset, offset, content);
int min = extractRangeStartFromLong(minMax);
int max = extractRangeEndFromLong(minMax);
+
Selection.setSelection((Spannable) mText, max);
((Editable) mText).replace(min, max, content);
+
+ if (mDragSourcePositions != -1) {
+ int dragSourceStart = extractRangeStartFromLong(mDragSourcePositions);
+ int dragSourceEnd = extractRangeEndFromLong(mDragSourcePositions);
+ if (max <= dragSourceStart) {
+ // Inserting text before selection has shifted positions
+ final int shift = mText.length() - originalLength;
+ dragSourceStart += shift;
+ dragSourceEnd += shift;
+ }
+
+ // Delete original selection
+ ((Editable) mText).delete(dragSourceStart, dragSourceEnd);
+
+ // Make sure we do not leave two adjacent spaces.
+ if ((dragSourceStart == 0 ||
+ Character.isSpaceChar(mTransformed.charAt(dragSourceStart - 1))) &&
+ (dragSourceStart == mText.length() ||
+ Character.isSpaceChar(mTransformed.charAt(dragSourceStart)))) {
+ final int pos = dragSourceStart == mText.length() ?
+ dragSourceStart - 1 : dragSourceStart;
+ ((Editable) mText).delete(pos, pos + 1);
+ }
+ }
+
return true;
}
- case DragEvent.ACTION_DRAG_EXITED:
case DragEvent.ACTION_DRAG_ENDED:
+ mDragSourcePositions = -1;
+ return true;
+
+ case DragEvent.ACTION_DRAG_EXITED:
default:
return true;
}
@@ -9039,6 +9068,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
return mInBatchEditControllers;
}
+ @ViewDebug.ExportedProperty(category = "text")
private CharSequence mText;
private CharSequence mTransformed;
private BufferType mBufferType = BufferType.NORMAL;
@@ -9143,4 +9173,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private InputFilter[] mFilters = NO_FILTERS;
private static final Spanned EMPTY_SPANNED = new SpannedString("");
private static int DRAG_THUMBNAIL_MAX_TEXT_LENGTH = 20;
+ // A packed range containing the drag source if it occured in that TextView. -1 otherwise.
+ private long mDragSourcePositions = -1;
+ // System wide time for last cut or copy action.
+ private static long sLastCutOrCopyTime;
}
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index e61fac3..6cf1387 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -16,6 +16,8 @@
package android.widget;
+import com.android.internal.R;
+
import android.annotation.Widget;
import android.content.Context;
import android.os.Parcel;
@@ -23,9 +25,7 @@ import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
-import android.widget.NumberPicker;
-
-import com.android.internal.R;
+import android.widget.NumberPicker.OnChangedListener;
import java.text.DateFormatSymbols;
import java.util.Calendar;
@@ -51,7 +51,7 @@ import java.util.Calendar;
*/
@Widget
public class TimePicker extends FrameLayout {
-
+
/**
* A no-op callback used in the constructor to avoid null checks
* later in the code.
@@ -70,10 +70,11 @@ public class TimePicker extends FrameLayout {
// ui components
private final NumberPicker mHourPicker;
private final NumberPicker mMinutePicker;
- private final Button mAmPmButton;
- private final String mAmText;
- private final String mPmText;
-
+ private final NumberPicker mAmPmPicker;
+ private final TextView mDivider;
+
+ private final String[] mAmPmStrings;
+
// callbacks
private OnTimeChangedListener mOnTimeChangedListener;
@@ -127,6 +128,10 @@ public class TimePicker extends FrameLayout {
}
});
+ // divider
+ mDivider = (TextView) findViewById(R.id.divider);
+ mDivider.setText(R.string.time_picker_separator);
+
// digits of minute
mMinutePicker = (NumberPicker) findViewById(R.id.minute);
mMinutePicker.setRange(0, 59);
@@ -140,50 +145,41 @@ public class TimePicker extends FrameLayout {
});
// am/pm
- mAmPmButton = (Button) findViewById(R.id.amPm);
-
- // now that the hour/minute picker objects have been initialized, set
- // the hour range properly based on the 12/24 hour display mode.
- configurePickerRanges();
-
- // initialize to current time
- Calendar cal = Calendar.getInstance();
- setOnTimeChangedListener(NO_OP_CHANGE_LISTENER);
-
- // by default we're not in 24 hour mode
- setCurrentHour(cal.get(Calendar.HOUR_OF_DAY));
- setCurrentMinute(cal.get(Calendar.MINUTE));
-
- mIsAm = (mCurrentHour < 12);
-
- /* Get the localized am/pm strings and use them in the spinner */
- DateFormatSymbols dfs = new DateFormatSymbols();
- String[] dfsAmPm = dfs.getAmPmStrings();
- mAmText = dfsAmPm[Calendar.AM];
- mPmText = dfsAmPm[Calendar.PM];
- mAmPmButton.setText(mIsAm ? mAmText : mPmText);
- mAmPmButton.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- requestFocus();
+ mAmPmPicker = (NumberPicker) findViewById(R.id.amPm);
+ mAmPmPicker.setOnChangeListener(new OnChangedListener() {
+ public void onChanged(NumberPicker picker, int oldVal, int newVal) {
+ picker.requestFocus();
if (mIsAm) {
-
// Currently AM switching to PM
if (mCurrentHour < 12) {
mCurrentHour += 12;
- }
+ }
} else {
-
// Currently PM switching to AM
if (mCurrentHour >= 12) {
mCurrentHour -= 12;
}
}
mIsAm = !mIsAm;
- mAmPmButton.setText(mIsAm ? mAmText : mPmText);
onTimeChanged();
}
});
-
+
+ /* Get the localized am/pm strings and use them in the spinner */
+ mAmPmStrings = new DateFormatSymbols().getAmPmStrings();
+
+ // now that the hour/minute picker objects have been initialized, set
+ // the hour range properly based on the 12/24 hour display mode.
+ configurePickerRanges();
+
+ // initialize to current time
+ Calendar cal = Calendar.getInstance();
+ setOnTimeChangedListener(NO_OP_CHANGE_LISTENER);
+
+ // by default we're not in 24 hour mode
+ setCurrentHour(cal.get(Calendar.HOUR_OF_DAY));
+ setCurrentMinute(cal.get(Calendar.MINUTE));
+
if (!isEnabled()) {
setEnabled(false);
}
@@ -194,7 +190,7 @@ public class TimePicker extends FrameLayout {
super.setEnabled(enabled);
mMinutePicker.setEnabled(enabled);
mHourPicker.setEnabled(enabled);
- mAmPmButton.setEnabled(enabled);
+ mAmPmPicker.setEnabled(enabled);
}
/**
@@ -327,12 +323,15 @@ public class TimePicker extends FrameLayout {
int currentHour = mCurrentHour;
if (!mIs24HourView) {
// convert [0,23] ordinal to wall clock display
- if (currentHour > 12) currentHour -= 12;
- else if (currentHour == 0) currentHour = 12;
+ if (currentHour > 12) {
+ currentHour -= 12;
+ } else if (currentHour == 0) {
+ currentHour = 12;
+ }
}
mHourPicker.setCurrent(currentHour);
mIsAm = mCurrentHour < 12;
- mAmPmButton.setText(mIsAm ? mAmText : mPmText);
+ mAmPmPicker.setCurrent(mIsAm ? Calendar.AM : Calendar.PM);
onTimeChanged();
}
@@ -340,16 +339,19 @@ public class TimePicker extends FrameLayout {
if (mIs24HourView) {
mHourPicker.setRange(0, 23);
mHourPicker.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER);
- mAmPmButton.setVisibility(View.GONE);
+ mAmPmPicker.setVisibility(View.GONE);
} else {
mHourPicker.setRange(1, 12);
mHourPicker.setFormatter(null);
- mAmPmButton.setVisibility(View.VISIBLE);
+ mAmPmPicker.setVisibility(View.VISIBLE);
+ mAmPmPicker.setRange(0, 1, mAmPmStrings);
}
}
private void onTimeChanged() {
- mOnTimeChangedListener.onTimeChanged(this, getCurrentHour(), getCurrentMinute());
+ if (mOnTimeChangedListener != null) {
+ mOnTimeChangedListener.onTimeChanged(this, getCurrentHour(), getCurrentMinute());
+ }
}
/**
@@ -357,6 +359,6 @@ public class TimePicker extends FrameLayout {
*/
private void updateMinuteDisplay() {
mMinutePicker.setCurrent(mCurrentMinute);
- mOnTimeChangedListener.onTimeChanged(this, getCurrentHour(), getCurrentMinute());
+ onTimeChanged();
}
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 90423be..bf59753 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -95,6 +95,7 @@ public class LockPatternUtils {
private final static String PATTERN_EVER_CHOSEN_KEY = "lockscreen.patterneverchosen";
public final static String PASSWORD_TYPE_KEY = "lockscreen.password_type";
private final static String LOCK_PASSWORD_SALT_KEY = "lockscreen.password_salt";
+ private final static String DISABLE_LOCKSCREEN_KEY = "lockscreen.disabled";
private final static String PASSWORD_HISTORY_KEY = "lockscreen.passwordhistory";
@@ -355,6 +356,26 @@ public class LockPatternUtils {
}
/**
+ * Disable showing lock screen at all when the DevicePolicyManager allows it.
+ * This is only meaningful if pattern, pin or password are not set.
+ *
+ * @param disable Disables lock screen when true
+ */
+ public void setLockScreenDisabled(boolean disable) {
+ setLong(DISABLE_LOCKSCREEN_KEY, disable ? 1 : 0);
+ }
+
+ /**
+ * Determine if LockScreen can be disabled. This is used, for example, to tell if we should
+ * show LockScreen or go straight to the home screen.
+ *
+ * @return true if lock screen is can be disabled
+ */
+ public boolean isLockScreenDisabled() {
+ return !isSecure() && getLong(DISABLE_LOCKSCREEN_KEY, 0) != 0;
+ }
+
+ /**
* Save a lock pattern.
* @param pattern The new pattern to save.
*/
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 695d50a4..b033878 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -579,20 +579,30 @@ static int mainWorkCallback(int fd, int events, void* data) {
while ((keyEvent=code->nativeInputQueue->consumeUnhandledEvent()) != NULL) {
jobject inputEventObj = android_view_KeyEvent_fromNative(
code->env, keyEvent);
- jboolean handled = code->env->CallBooleanMethod(code->clazz,
- gNativeActivityClassInfo.dispatchUnhandledKeyEvent, inputEventObj);
- checkAndClearExceptionFromCallback(code->env, "dispatchUnhandledKeyEvent");
- code->env->DeleteLocalRef(inputEventObj);
+ jboolean handled;
+ if (inputEventObj) {
+ handled = code->env->CallBooleanMethod(code->clazz,
+ gNativeActivityClassInfo.dispatchUnhandledKeyEvent, inputEventObj);
+ checkAndClearExceptionFromCallback(code->env, "dispatchUnhandledKeyEvent");
+ code->env->DeleteLocalRef(inputEventObj);
+ } else {
+ LOGE("Failed to obtain key event for dispatchUnhandledKeyEvent.");
+ handled = false;
+ }
code->nativeInputQueue->finishEvent(keyEvent, handled, true);
}
int seq;
while ((keyEvent=code->nativeInputQueue->consumePreDispatchingEvent(&seq)) != NULL) {
jobject inputEventObj = android_view_KeyEvent_fromNative(
code->env, keyEvent);
- code->env->CallVoidMethod(code->clazz,
- gNativeActivityClassInfo.preDispatchKeyEvent, inputEventObj, seq);
- checkAndClearExceptionFromCallback(code->env, "preDispatchKeyEvent");
- code->env->DeleteLocalRef(inputEventObj);
+ if (inputEventObj) {
+ code->env->CallVoidMethod(code->clazz,
+ gNativeActivityClassInfo.preDispatchKeyEvent, inputEventObj, seq);
+ checkAndClearExceptionFromCallback(code->env, "preDispatchKeyEvent");
+ code->env->DeleteLocalRef(inputEventObj);
+ } else {
+ LOGE("Failed to obtain key event for preDispatchKeyEvent.");
+ }
}
} break;
case CMD_FINISH: {
@@ -987,7 +997,12 @@ dispatchKeyEvent_native(JNIEnv* env, jobject clazz, jint handle, jobject eventOb
NativeCode* code = (NativeCode*)handle;
if (code->nativeInputQueue != NULL) {
KeyEvent* event = code->nativeInputQueue->createKeyEvent();
- android_view_KeyEvent_toNative(env, eventObj, event);
+ status_t status = android_view_KeyEvent_toNative(env, eventObj, event);
+ if (status) {
+ delete event;
+ jniThrowRuntimeException(env, "Could not read contents of KeyEvent object.");
+ return;
+ }
code->nativeInputQueue->dispatchEvent(event);
}
}
diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp
index 040dac3..fad9539 100644
--- a/core/jni/android_database_CursorWindow.cpp
+++ b/core/jni/android_database_CursorWindow.cpp
@@ -63,7 +63,8 @@ static void native_init_empty(JNIEnv * env, jobject object, jboolean localOnly)
}
if (!window->initBuffer(localOnly)) {
- jniThrowException(env, "java/lang/IllegalStateException", "Couldn't init cursor window");
+ jniThrowException(env, "java/lang/RuntimeException",
+ "Memory couldn't be allocated for 1MB CursorWindow object.");
delete window;
return;
}
@@ -82,11 +83,13 @@ static void native_init_memory(JNIEnv * env, jobject object, jobject memObj)
CursorWindow * window = new CursorWindow();
if (!window) {
- jniThrowException(env, "java/lang/RuntimeException", "No memory for native window object");
+ jniThrowException(env, "java/lang/RuntimeException",
+ "CursorWindow of size 1MB couldn't be created. No memory?");
return;
}
if (!window->setMemory(memory)) {
- jniThrowException(env, "java/lang/RuntimeException", "No memory in memObj");
+ jniThrowException(env, "java/lang/RuntimeException",
+ "Memory couldn't be initialized for 1MB CursorWindow object.");
delete window;
return;
}
@@ -131,8 +134,9 @@ LOG_WINDOW("Closing window %p", window);
static void throwExceptionWithRowCol(JNIEnv * env, jint row, jint column)
{
- char buf[100];
- snprintf(buf, sizeof(buf), "get field slot from row %d col %d failed", row, column);
+ char buf[200];
+ snprintf(buf, sizeof(buf), "Couldn't read row %d, col %d from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it",
+ row, column);
jniThrowException(env, "java/lang/IllegalStateException", buf);
}
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index c4056a4..2528db1 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -1296,7 +1296,7 @@ static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz
{
AssetManager* am = assetManagerForJavaObject(env, clazz);
if (am == NULL) {
- return NULL;
+ return 0;
}
const ResTable& res(am->getResources());
diff --git a/core/jni/android_view_KeyEvent.cpp b/core/jni/android_view_KeyEvent.cpp
index 7e7583c..4b04b8b 100644
--- a/core/jni/android_view_KeyEvent.cpp
+++ b/core/jni/android_view_KeyEvent.cpp
@@ -30,7 +30,8 @@ namespace android {
static struct {
jclass clazz;
- jmethodID ctor;
+ jmethodID obtain;
+ jmethodID recycle;
jfieldID mDeviceId;
jfieldID mSource;
@@ -48,7 +49,8 @@ static struct {
// ----------------------------------------------------------------------------
jobject android_view_KeyEvent_fromNative(JNIEnv* env, const KeyEvent* event) {
- return env->NewObject(gKeyEventClassInfo.clazz, gKeyEventClassInfo.ctor,
+ jobject eventObj = env->CallStaticObjectMethod(gKeyEventClassInfo.clazz,
+ gKeyEventClassInfo.obtain,
nanoseconds_to_milliseconds(event->getDownTime()),
nanoseconds_to_milliseconds(event->getEventTime()),
event->getAction(),
@@ -58,10 +60,18 @@ jobject android_view_KeyEvent_fromNative(JNIEnv* env, const KeyEvent* event) {
event->getDeviceId(),
event->getScanCode(),
event->getFlags(),
- event->getSource());
+ event->getSource(),
+ NULL);
+ if (env->ExceptionCheck()) {
+ LOGE("An exception occurred while obtaining a key event.");
+ LOGE_EX(env);
+ env->ExceptionClear();
+ return NULL;
+ }
+ return eventObj;
}
-void android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj,
+status_t android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj,
KeyEvent* event) {
jint deviceId = env->GetIntField(eventObj, gKeyEventClassInfo.mDeviceId);
jint source = env->GetIntField(eventObj, gKeyEventClassInfo.mSource);
@@ -77,6 +87,18 @@ void android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj,
event->initialize(deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount,
milliseconds_to_nanoseconds(downTime),
milliseconds_to_nanoseconds(eventTime));
+ return OK;
+}
+
+status_t android_view_KeyEvent_recycle(JNIEnv* env, jobject eventObj) {
+ env->CallVoidMethod(eventObj, gKeyEventClassInfo.recycle);
+ if (env->ExceptionCheck()) {
+ LOGW("An exception occurred while recycling a key event.");
+ LOGW_EX(env);
+ env->ExceptionClear();
+ return UNKNOWN_ERROR;
+ }
+ return OK;
}
static jboolean native_isSystemKey(JNIEnv* env, jobject clazz, jint keyCode) {
@@ -87,6 +109,7 @@ static jboolean native_hasDefaultAction(JNIEnv* env, jobject clazz, jint keyCode
return KeyEvent::hasDefaultAction(keyCode);
}
+
// ----------------------------------------------------------------------------
static const JNINativeMethod g_methods[] = {
@@ -99,6 +122,10 @@ static const JNINativeMethod g_methods[] = {
LOG_FATAL_IF(! var, "Unable to find class " className); \
var = jclass(env->NewGlobalRef(var));
+#define GET_STATIC_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
+ var = env->GetStaticMethodID(clazz, methodName, fieldDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find static method" methodName);
+
#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
LOG_FATAL_IF(! var, "Unable to find method" methodName);
@@ -109,9 +136,11 @@ static const JNINativeMethod g_methods[] = {
int register_android_view_KeyEvent(JNIEnv* env) {
FIND_CLASS(gKeyEventClassInfo.clazz, "android/view/KeyEvent");
-
- GET_METHOD_ID(gKeyEventClassInfo.ctor, gKeyEventClassInfo.clazz,
- "<init>", "(JJIIIIIIII)V");
+
+ GET_STATIC_METHOD_ID(gKeyEventClassInfo.obtain, gKeyEventClassInfo.clazz,
+ "obtain", "(JJIIIIIIIILjava/lang/String;)Landroid/view/KeyEvent;");
+ GET_METHOD_ID(gKeyEventClassInfo.recycle, gKeyEventClassInfo.clazz,
+ "recycle", "()V");
GET_FIELD_ID(gKeyEventClassInfo.mDeviceId, gKeyEventClassInfo.clazz,
"mDeviceId", "I");
diff --git a/core/jni/android_view_KeyEvent.h b/core/jni/android_view_KeyEvent.h
index 0bd410c..586eb2f 100644
--- a/core/jni/android_view_KeyEvent.h
+++ b/core/jni/android_view_KeyEvent.h
@@ -18,18 +18,28 @@
#define _ANDROID_VIEW_KEYEVENT_H
#include "jni.h"
+#include <utils/Errors.h>
+#include <utils/threads.h>
namespace android {
class KeyEvent;
-/* Obtains an instance of a DVM KeyEvent object as a copy of a native KeyEvent instance. */
+/* Obtains an instance of a DVM KeyEvent object as a copy of a native KeyEvent instance.
+ * Returns NULL on error. */
extern jobject android_view_KeyEvent_fromNative(JNIEnv* env, const KeyEvent* event);
-/* Copies the contents of a DVM KeyEvent object to a native KeyEvent instance. */
-extern void android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj,
+/* Copies the contents of a DVM KeyEvent object to a native KeyEvent instance.
+ * Returns non-zero on error. */
+extern status_t android_view_KeyEvent_toNative(JNIEnv* env, jobject eventObj,
KeyEvent* event);
+/* Recycles a DVM KeyEvent object.
+ * Key events should only be recycled if they are owned by the system since user
+ * code expects them to be essentially immutable, "tracking" notwithstanding.
+ * Returns non-zero on error. */
+extern status_t android_view_KeyEvent_recycle(JNIEnv* env, jobject eventObj);
+
} // namespace android
#endif // _ANDROID_OS_KEYEVENT_H
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index 537ac72..f32f0ff 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -169,7 +169,7 @@ jobject android_view_MotionEvent_fromNative(JNIEnv* env, const MotionEvent* even
return eventObj;
}
-void android_view_MotionEvent_toNative(JNIEnv* env, jobject eventObj,
+status_t android_view_MotionEvent_toNative(JNIEnv* env, jobject eventObj,
MotionEvent* event) {
jint deviceId = env->GetIntField(eventObj, gMotionEventClassInfo.mDeviceId);
jint source = env->GetIntField(eventObj, gMotionEventClassInfo.mSource);
@@ -184,6 +184,16 @@ void android_view_MotionEvent_toNative(JNIEnv* env, jobject eventObj,
jint flags = env->GetIntField(eventObj, gMotionEventClassInfo.mFlags);
jint numPointers = env->GetIntField(eventObj, gMotionEventClassInfo.mNumPointers);
jint numSamples = env->GetIntField(eventObj, gMotionEventClassInfo.mNumSamples);
+
+ if (numPointers == 0) {
+ LOGE("Malformed MotionEvent: mNumPointers was zero");
+ return BAD_VALUE;
+ }
+ if (numSamples == 0) {
+ LOGE("Malformed MotionEvent: mNumSamples was zero");
+ return BAD_VALUE;
+ }
+
jintArray pointerIdentifierArray = jintArray(env->GetObjectField(eventObj,
gMotionEventClassInfo.mPointerIdentifiers));
jfloatArray dataSampleArray = jfloatArray(env->GetObjectField(eventObj,
@@ -191,9 +201,6 @@ void android_view_MotionEvent_toNative(JNIEnv* env, jobject eventObj,
jlongArray eventTimeNanoSampleArray = jlongArray(env->GetObjectField(eventObj,
gMotionEventClassInfo.mEventTimeNanoSamples));
- LOG_FATAL_IF(numPointers == 0, "numPointers was zero");
- LOG_FATAL_IF(numSamples == 0, "numSamples was zero");
-
jint* pointerIdentifiers = (jint*)env->GetPrimitiveArrayCritical(pointerIdentifierArray, NULL);
jfloat* dataSamples = (jfloat*)env->GetPrimitiveArrayCritical(dataSampleArray, NULL);
jlong* eventTimeNanoSamples = (jlong*)env->GetPrimitiveArrayCritical(
@@ -236,22 +243,25 @@ void android_view_MotionEvent_toNative(JNIEnv* env, jobject eventObj,
event->addSample(sampleEventTime, samplePointerCoords);
}
- env->ReleasePrimitiveArrayCritical(pointerIdentifierArray, pointerIdentifiers, JNI_ABORT);
- env->ReleasePrimitiveArrayCritical(dataSampleArray, dataSamples, JNI_ABORT);
env->ReleasePrimitiveArrayCritical(eventTimeNanoSampleArray, eventTimeNanoSamples, JNI_ABORT);
+ env->ReleasePrimitiveArrayCritical(dataSampleArray, dataSamples, JNI_ABORT);
+ env->ReleasePrimitiveArrayCritical(pointerIdentifierArray, pointerIdentifiers, JNI_ABORT);
- env->DeleteLocalRef(pointerIdentifierArray);
- env->DeleteLocalRef(dataSampleArray);
env->DeleteLocalRef(eventTimeNanoSampleArray);
+ env->DeleteLocalRef(dataSampleArray);
+ env->DeleteLocalRef(pointerIdentifierArray);
+ return OK;
}
-void android_view_MotionEvent_recycle(JNIEnv* env, jobject eventObj) {
+status_t android_view_MotionEvent_recycle(JNIEnv* env, jobject eventObj) {
env->CallVoidMethod(eventObj, gMotionEventClassInfo.recycle);
if (env->ExceptionCheck()) {
LOGW("An exception occurred while recycling a motion event.");
LOGW_EX(env);
env->ExceptionClear();
+ return UNKNOWN_ERROR;
}
+ return OK;
}
static inline float transformAngle(const SkMatrix* matrix, float angleRadians) {
diff --git a/core/jni/android_view_MotionEvent.h b/core/jni/android_view_MotionEvent.h
index 86e4bde..80dc861 100644
--- a/core/jni/android_view_MotionEvent.h
+++ b/core/jni/android_view_MotionEvent.h
@@ -18,20 +18,24 @@
#define _ANDROID_VIEW_MOTIONEVENT_H
#include "jni.h"
+#include <utils/Errors.h>
namespace android {
class MotionEvent;
-/* Obtains an instance of a DVM MotionEvent object as a copy of a native MotionEvent instance. */
+/* Obtains an instance of a DVM MotionEvent object as a copy of a native MotionEvent instance.
+ * Returns NULL on error. */
extern jobject android_view_MotionEvent_fromNative(JNIEnv* env, const MotionEvent* event);
-/* Copies the contents of a DVM MotionEvent object to a native MotionEvent instance. */
-extern void android_view_MotionEvent_toNative(JNIEnv* env, jobject eventObj,
+/* Copies the contents of a DVM MotionEvent object to a native MotionEvent instance.
+ * Returns non-zero on error. */
+extern status_t android_view_MotionEvent_toNative(JNIEnv* env, jobject eventObj,
MotionEvent* event);
-/* Recycles a DVM MotionEvent object. */
-extern void android_view_MotionEvent_recycle(JNIEnv* env, jobject eventObj);
+/* Recycles a DVM MotionEvent object.
+ * Returns non-zero on error. */
+extern status_t android_view_MotionEvent_recycle(JNIEnv* env, jobject eventObj);
} // namespace android
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 9a85edc..206e320 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -32,6 +32,7 @@
#include <SkCanvas.h>
#include <SkBitmap.h>
#include <SkRegion.h>
+#include <SkPixelRef.h>
#include "jni.h"
#include <android_runtime/AndroidRuntime.h>
@@ -437,9 +438,15 @@ static void Surface_unfreezeDisplay(
}
}
-class ScreenshotBitmap : public SkBitmap {
+class ScreenshotPixelRef : public SkPixelRef {
public:
- ScreenshotBitmap() {
+ ScreenshotPixelRef(SkColorTable* ctable) {
+ fCTable = ctable;
+ ctable->safeRef();
+ setImmutable();
+ }
+ virtual ~ScreenshotPixelRef() {
+ SkSafeUnref(fCTable);
}
status_t update(int width, int height) {
@@ -450,40 +457,71 @@ public:
return res;
}
- void const* base = mScreenshot.getPixels();
- uint32_t w = mScreenshot.getWidth();
- uint32_t h = mScreenshot.getHeight();
- uint32_t s = mScreenshot.getStride();
- uint32_t f = mScreenshot.getFormat();
+ return NO_ERROR;
+ }
- ssize_t bpr = s * android::bytesPerPixel(f);
- setConfig(convertPixelFormat(f), w, h, bpr);
- if (f == PIXEL_FORMAT_RGBX_8888) {
- setIsOpaque(true);
- }
- if (w > 0 && h > 0) {
- setPixels((void*)base);
- } else {
- // be safe with an empty bitmap.
- setPixels(NULL);
- }
+ uint32_t getWidth() const {
+ return mScreenshot.getWidth();
+ }
- return NO_ERROR;
+ uint32_t getHeight() const {
+ return mScreenshot.getHeight();
+ }
+
+ uint32_t getStride() const {
+ return mScreenshot.getStride();
+ }
+
+ uint32_t getFormat() const {
+ return mScreenshot.getFormat();
+ }
+
+protected:
+ // overrides from SkPixelRef
+ virtual void* onLockPixels(SkColorTable** ct) {
+ *ct = fCTable;
+ return (void*)mScreenshot.getPixels();
+ }
+
+ virtual void onUnlockPixels() {
}
private:
ScreenshotClient mScreenshot;
+ SkColorTable* fCTable;
+
+ typedef SkPixelRef INHERITED;
};
static jobject Surface_screenshot(JNIEnv* env, jobject clazz, jint width, jint height)
{
- ScreenshotBitmap* bitmap = new ScreenshotBitmap();
-
- if (bitmap->update(width, height) != NO_ERROR) {
- delete bitmap;
+ ScreenshotPixelRef* pixels = new ScreenshotPixelRef(NULL);
+ if (pixels->update(width, height) != NO_ERROR) {
+ delete pixels;
return 0;
}
+ uint32_t w = pixels->getWidth();
+ uint32_t h = pixels->getHeight();
+ uint32_t s = pixels->getStride();
+ uint32_t f = pixels->getFormat();
+ ssize_t bpr = s * android::bytesPerPixel(f);
+
+ SkBitmap* bitmap = new SkBitmap();
+ bitmap->setConfig(convertPixelFormat(f), w, h, bpr);
+ if (f == PIXEL_FORMAT_RGBX_8888) {
+ bitmap->setIsOpaque(true);
+ }
+
+ if (w > 0 && h > 0) {
+ bitmap->setPixelRef(pixels)->unref();
+ bitmap->lockPixels();
+ } else {
+ // be safe with an empty bitmap.
+ delete pixels;
+ bitmap->setPixels(NULL);
+ }
+
return GraphicsJNI::createBitmap(env, bitmap, false, NULL);
}
diff --git a/core/res/res/drawable-hdpi/switch_bg_disabled_holo_dark.9.png b/core/res/res/drawable-hdpi/switch_bg_disabled_holo_dark.9.png
new file mode 100644
index 0000000..df435e4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/switch_bg_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_bg_disabled_holo_light.9.png b/core/res/res/drawable-hdpi/switch_bg_disabled_holo_light.9.png
new file mode 100644
index 0000000..4c8cc86
--- /dev/null
+++ b/core/res/res/drawable-hdpi/switch_bg_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_bg_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/switch_bg_focused_holo_dark.9.png
new file mode 100644
index 0000000..a4ec766
--- /dev/null
+++ b/core/res/res/drawable-hdpi/switch_bg_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_bg_focused_holo_light.9.png b/core/res/res/drawable-hdpi/switch_bg_focused_holo_light.9.png
new file mode 100644
index 0000000..a571aa8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/switch_bg_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_bg_holo_dark.9.png b/core/res/res/drawable-hdpi/switch_bg_holo_dark.9.png
new file mode 100644
index 0000000..f86e7e4
--- /dev/null
+++ b/core/res/res/drawable-hdpi/switch_bg_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_bg_holo_light.9.png b/core/res/res/drawable-hdpi/switch_bg_holo_light.9.png
new file mode 100644
index 0000000..b4584a7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/switch_bg_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_disabled_holo_dark.9.png b/core/res/res/drawable-hdpi/switch_thumb_disabled_holo_dark.9.png
new file mode 100644
index 0000000..c01ad87
--- /dev/null
+++ b/core/res/res/drawable-hdpi/switch_thumb_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_disabled_holo_light.9.png b/core/res/res/drawable-hdpi/switch_thumb_disabled_holo_light.9.png
new file mode 100644
index 0000000..b3e428d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/switch_thumb_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_holo_dark.9.png b/core/res/res/drawable-hdpi/switch_thumb_holo_dark.9.png
new file mode 100644
index 0000000..4d3d5b7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/switch_thumb_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_holo_light.9.png b/core/res/res/drawable-hdpi/switch_thumb_holo_light.9.png
new file mode 100644
index 0000000..16e11b6
--- /dev/null
+++ b/core/res/res/drawable-hdpi/switch_thumb_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_dark.9.png b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_dark.9.png
new file mode 100644
index 0000000..3900997
--- /dev/null
+++ b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_light.9.png b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_light.9.png
new file mode 100644
index 0000000..ab4fd8d
--- /dev/null
+++ b/core/res/res/drawable-hdpi/switch_thumb_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_bg_disabled_holo_dark.9.png b/core/res/res/drawable-mdpi/switch_bg_disabled_holo_dark.9.png
new file mode 100644
index 0000000..c75612c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/switch_bg_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_bg_disabled_holo_light.9.png b/core/res/res/drawable-mdpi/switch_bg_disabled_holo_light.9.png
new file mode 100644
index 0000000..67adadc
--- /dev/null
+++ b/core/res/res/drawable-mdpi/switch_bg_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_bg_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/switch_bg_focused_holo_dark.9.png
new file mode 100644
index 0000000..9a05f84
--- /dev/null
+++ b/core/res/res/drawable-mdpi/switch_bg_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_bg_focused_holo_light.9.png b/core/res/res/drawable-mdpi/switch_bg_focused_holo_light.9.png
new file mode 100644
index 0000000..58d65ad
--- /dev/null
+++ b/core/res/res/drawable-mdpi/switch_bg_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_bg_holo_dark.9.png b/core/res/res/drawable-mdpi/switch_bg_holo_dark.9.png
new file mode 100644
index 0000000..172030d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/switch_bg_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_bg_holo_light.9.png b/core/res/res/drawable-mdpi/switch_bg_holo_light.9.png
new file mode 100644
index 0000000..4ae089b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/switch_bg_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_disabled_holo_dark.9.png b/core/res/res/drawable-mdpi/switch_thumb_disabled_holo_dark.9.png
new file mode 100644
index 0000000..7e205ac
--- /dev/null
+++ b/core/res/res/drawable-mdpi/switch_thumb_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_disabled_holo_light.9.png b/core/res/res/drawable-mdpi/switch_thumb_disabled_holo_light.9.png
new file mode 100644
index 0000000..b4e7cf5
--- /dev/null
+++ b/core/res/res/drawable-mdpi/switch_thumb_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_holo_dark.9.png b/core/res/res/drawable-mdpi/switch_thumb_holo_dark.9.png
new file mode 100644
index 0000000..7003318
--- /dev/null
+++ b/core/res/res/drawable-mdpi/switch_thumb_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_holo_light.9.png b/core/res/res/drawable-mdpi/switch_thumb_holo_light.9.png
new file mode 100644
index 0000000..97afcbf
--- /dev/null
+++ b/core/res/res/drawable-mdpi/switch_thumb_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_dark.9.png b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_dark.9.png
new file mode 100644
index 0000000..1adc9ee
--- /dev/null
+++ b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_light.9.png b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_light.9.png
new file mode 100644
index 0000000..29c6328
--- /dev/null
+++ b/core/res/res/drawable-mdpi/switch_thumb_pressed_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable/switch_inner_holo_dark.xml b/core/res/res/drawable/switch_inner_holo_dark.xml
new file mode 100644
index 0000000..3eb55ee
--- /dev/null
+++ b/core/res/res/drawable/switch_inner_holo_dark.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:drawable="@drawable/switch_thumb_disabled_holo_dark" />
+ <item android:state_pressed="true" android:drawable="@drawable/switch_thumb_pressed_holo_dark" />
+ <item android:drawable="@drawable/switch_thumb_holo_dark" />
+</selector>
diff --git a/core/res/res/drawable/switch_inner_holo_light.xml b/core/res/res/drawable/switch_inner_holo_light.xml
new file mode 100644
index 0000000..9b287cf
--- /dev/null
+++ b/core/res/res/drawable/switch_inner_holo_light.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:drawable="@drawable/switch_thumb_disabled_holo_light" />
+ <item android:state_pressed="true" android:drawable="@drawable/switch_thumb_pressed_holo_light" />
+ <item android:drawable="@drawable/switch_thumb_holo_light" />
+</selector>
diff --git a/core/res/res/drawable/switch_track_holo_dark.xml b/core/res/res/drawable/switch_track_holo_dark.xml
new file mode 100644
index 0000000..c9a940d
--- /dev/null
+++ b/core/res/res/drawable/switch_track_holo_dark.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:drawable="@drawable/switch_bg_disabled_holo_dark" />
+ <item android:state_focused="true" android:drawable="@drawable/switch_bg_focused_holo_dark" />
+ <item android:drawable="@drawable/switch_bg_holo_dark" />
+</selector>
diff --git a/core/res/res/drawable/switch_track_holo_light.xml b/core/res/res/drawable/switch_track_holo_light.xml
new file mode 100644
index 0000000..98e53b5
--- /dev/null
+++ b/core/res/res/drawable/switch_track_holo_light.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:drawable="@drawable/switch_bg_disabled_holo_light" />
+ <item android:state_focused="true" android:drawable="@drawable/switch_bg_focused_holo_light" />
+ <item android:drawable="@drawable/switch_bg_holo_light" />
+</selector>
diff --git a/core/res/res/drawable/timepicker_down_btn.xml b/core/res/res/drawable/timepicker_down_btn.xml
index 61a252a..d4908cb 100644
--- a/core/res/res/drawable/timepicker_down_btn.xml
+++ b/core/res/res/drawable/timepicker_down_btn.xml
@@ -16,15 +16,28 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="false" android:state_enabled="true"
- android:state_focused="false" android:drawable="@drawable/timepicker_down_normal" />
- <item android:state_pressed="true" android:state_enabled="true"
+ <item android:state_pressed="false"
+ android:state_enabled="true"
+ android:state_focused="false"
+ android:drawable="@drawable/timepicker_down_normal" />
+
+ <item android:state_pressed="true"
+ android:state_enabled="true"
android:drawable="@drawable/timepicker_down_pressed" />
- <item android:state_pressed="false" android:state_enabled="true"
- android:state_focused="true" android:drawable="@drawable/timepicker_down_selected" />
- <item android:state_pressed="false" android:state_enabled="false"
- android:state_focused="false" android:drawable="@drawable/timepicker_down_disabled" />
- <item android:state_pressed="false" android:state_enabled="false"
- android:state_focused="true" android:drawable="@drawable/timepicker_down_disabled_focused" />
+
+ <item android:state_pressed="false"
+ android:state_enabled="true"
+ android:state_focused="true"
+ android:drawable="@drawable/timepicker_down_selected" />
+
+ <item android:state_pressed="false"
+ android:state_enabled="false"
+ android:state_focused="false"
+ android:drawable="@drawable/timepicker_down_disabled" />
+
+ <item android:state_pressed="false"
+ android:state_enabled="false"
+ android:state_focused="true"
+ android:drawable="@drawable/timepicker_down_disabled_focused" />
</selector>
diff --git a/core/res/res/drawable/timepicker_down_btn_holo_dark.xml b/core/res/res/drawable/timepicker_down_btn_holo_dark.xml
new file mode 100644
index 0000000..b4b824d
--- /dev/null
+++ b/core/res/res/drawable/timepicker_down_btn_holo_dark.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:state_pressed="false"
+ android:state_enabled="true"
+ android:state_focused="false"
+ android:drawable="@drawable/timepicker_down_normal_holo_dark" />
+
+ <item android:state_pressed="true"
+ android:state_enabled="true"
+ android:drawable="@drawable/timepicker_down_pressed_holo_dark" />
+
+ <item android:state_pressed="false"
+ android:state_enabled="true"
+ android:state_focused="true"
+ android:drawable="@drawable/timepicker_down_focused_holo_dark" />
+
+ <item android:state_pressed="false"
+ android:state_enabled="false"
+ android:state_focused="false"
+ android:drawable="@drawable/timepicker_down_disabled_holo_dark" />
+
+ <item android:state_pressed="false"
+ android:state_enabled="false"
+ android:state_focused="true"
+ android:drawable="@drawable/timepicker_down_disabled_focused_holo_dark" />
+
+</selector>
diff --git a/core/res/res/drawable/timepicker_down_btn_holo_light.xml b/core/res/res/drawable/timepicker_down_btn_holo_light.xml
new file mode 100644
index 0000000..7ae5e53
--- /dev/null
+++ b/core/res/res/drawable/timepicker_down_btn_holo_light.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:state_pressed="false"
+ android:state_enabled="true"
+ android:state_focused="false"
+ android:drawable="@drawable/timepicker_down_normal_holo_light" />
+
+ <item android:state_pressed="true"
+ android:state_enabled="true"
+ android:drawable="@drawable/timepicker_down_pressed_holo_light" />
+
+ <item android:state_pressed="false"
+ android:state_enabled="true"
+ android:state_focused="true"
+ android:drawable="@drawable/timepicker_down_focused_holo_light" />
+
+ <item android:state_pressed="false"
+ android:state_enabled="false"
+ android:state_focused="false"
+ android:drawable="@drawable/timepicker_down_disabled_holo_light" />
+
+ <item android:state_pressed="false"
+ android:state_enabled="false"
+ android:state_focused="true"
+ android:drawable="@drawable/timepicker_down_disabled_focused_holo_light" />
+
+</selector>
diff --git a/core/res/res/drawable/timepicker_input.xml b/core/res/res/drawable/timepicker_input.xml
index b811d4e..1768673 100644
--- a/core/res/res/drawable/timepicker_input.xml
+++ b/core/res/res/drawable/timepicker_input.xml
@@ -16,15 +16,28 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="false" android:state_enabled="true"
- android:state_focused="false" android:drawable="@drawable/timepicker_input_normal" />
- <item android:state_pressed="true" android:state_enabled="true"
+ <item android:state_pressed="false"
+ android:state_enabled="true"
+ android:state_focused="false"
+ android:drawable="@drawable/timepicker_input_normal" />
+
+ <item android:state_pressed="true"
+ android:state_enabled="true"
android:drawable="@drawable/timepicker_input_pressed" />
- <item android:state_pressed="false" android:state_enabled="true"
- android:state_focused="true" android:drawable="@drawable/timepicker_input_selected" />
- <item android:state_pressed="false" android:state_enabled="false"
- android:state_focused="false" android:drawable="@drawable/timepicker_input_disabled" />
- <item android:state_pressed="false" android:state_enabled="false"
- android:state_focused="true" android:drawable="@drawable/timepicker_input_normal" />
+
+ <item android:state_pressed="false"
+ android:state_enabled="true"
+ android:state_focused="true"
+ android:drawable="@drawable/timepicker_input_selected" />
+
+ <item android:state_pressed="false"
+ android:state_enabled="false"
+ android:state_focused="false"
+ android:drawable="@drawable/timepicker_input_disabled" />
+
+ <item android:state_pressed="false"
+ android:state_enabled="false"
+ android:state_focused="true"
+ android:drawable="@drawable/timepicker_input_normal" />
</selector>
diff --git a/core/res/res/drawable/timepicker_up_btn.xml b/core/res/res/drawable/timepicker_up_btn.xml
index 5428aee..fbaed08 100644
--- a/core/res/res/drawable/timepicker_up_btn.xml
+++ b/core/res/res/drawable/timepicker_up_btn.xml
@@ -16,15 +16,28 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="false" android:state_enabled="true"
- android:state_focused="false" android:drawable="@drawable/timepicker_up_normal" />
- <item android:state_pressed="true" android:state_enabled="true"
+ <item android:state_pressed="false"
+ android:state_enabled="true"
+ android:state_focused="false"
+ android:drawable="@drawable/timepicker_up_normal" />
+
+ <item android:state_pressed="true"
+ android:state_enabled="true"
android:drawable="@drawable/timepicker_up_pressed" />
- <item android:state_pressed="false" android:state_enabled="true"
- android:state_focused="true" android:drawable="@drawable/timepicker_up_selected" />
- <item android:state_pressed="false" android:state_enabled="false"
- android:state_focused="false" android:drawable="@drawable/timepicker_up_disabled" />
- <item android:state_pressed="false" android:state_enabled="false"
- android:state_focused="true" android:drawable="@drawable/timepicker_up_disabled_focused" />
+
+ <item android:state_pressed="false"
+ android:state_enabled="true"
+ android:state_focused="true"
+ android:drawable="@drawable/timepicker_up_selected" />
+
+ <item android:state_pressed="false"
+ android:state_enabled="false"
+ android:state_focused="false"
+ android:drawable="@drawable/timepicker_up_disabled" />
+
+ <item android:state_pressed="false"
+ android:state_enabled="false"
+ android:state_focused="true"
+ android:drawable="@drawable/timepicker_up_disabled_focused" />
</selector>
diff --git a/core/res/res/drawable/timepicker_up_btn_holo_dark.xml b/core/res/res/drawable/timepicker_up_btn_holo_dark.xml
new file mode 100644
index 0000000..af5f6eb
--- /dev/null
+++ b/core/res/res/drawable/timepicker_up_btn_holo_dark.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:state_pressed="false"
+ android:state_enabled="true"
+ android:state_focused="false"
+ android:drawable="@drawable/timepicker_up_normal_holo_dark" />
+
+ <item android:state_pressed="true"
+ android:state_enabled="true"
+ android:drawable="@drawable/timepicker_up_pressed_holo_dark" />
+
+ <item android:state_pressed="false"
+ android:state_enabled="true"
+ android:state_focused="true"
+ android:drawable="@drawable/timepicker_up_focused_holo_dark" />
+
+ <item android:state_pressed="false"
+ android:state_enabled="false"
+ android:state_focused="false"
+ android:drawable="@drawable/timepicker_up_disabled_holo_dark" />
+
+ <item android:state_pressed="false"
+ android:state_enabled="false"
+ android:state_focused="true"
+ android:drawable="@drawable/timepicker_up_disabled_focused_holo_dark" />
+
+</selector>
diff --git a/core/res/res/drawable/timepicker_up_btn_holo_light.xml b/core/res/res/drawable/timepicker_up_btn_holo_light.xml
new file mode 100644
index 0000000..6025d3a
--- /dev/null
+++ b/core/res/res/drawable/timepicker_up_btn_holo_light.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <item android:state_pressed="false"
+ android:state_enabled="true"
+ android:state_focused="false"
+ android:drawable="@drawable/timepicker_up_normal_holo_light" />
+
+ <item android:state_pressed="true"
+ android:state_enabled="true"
+ android:drawable="@drawable/timepicker_up_pressed_holo_light" />
+
+ <item android:state_pressed="false"
+ android:state_enabled="true"
+ android:state_focused="true"
+ android:drawable="@drawable/timepicker_up_focused_holo_light" />
+
+ <item android:state_pressed="false"
+ android:state_enabled="false"
+ android:state_focused="false"
+ android:drawable="@drawable/timepicker_up_focused_holo_light" />
+
+ <item android:state_pressed="false"
+ android:state_enabled="false"
+ android:state_focused="true"
+ android:drawable="@drawable/timepicker_up_disabled_focused_holo_light" />
+
+</selector>
diff --git a/core/res/res/layout-xlarge/alert_dialog.xml b/core/res/res/layout-xlarge/alert_dialog.xml
index 82b4509..291e1c2 100644
--- a/core/res/res/layout-xlarge/alert_dialog.xml
+++ b/core/res/res/layout-xlarge/alert_dialog.xml
@@ -29,9 +29,7 @@
android:paddingLeft="3dip"
android:paddingRight="1dip"
android:majorWeightMin="0.45"
- android:minorWeightMin="0.72"
- android:majorWeightMax="0.45"
- android:minorWeightMax="0.72">
+ android:minorWeightMin="0.72">
<LinearLayout android:id="@+id/topPanel"
android:layout_width="match_parent"
diff --git a/core/res/res/layout-xlarge/alert_dialog_holo.xml b/core/res/res/layout-xlarge/alert_dialog_holo.xml
index a01e03a..72b1e31 100644
--- a/core/res/res/layout-xlarge/alert_dialog_holo.xml
+++ b/core/res/res/layout-xlarge/alert_dialog_holo.xml
@@ -28,9 +28,7 @@
android:paddingLeft="3dip"
android:paddingRight="1dip"
android:majorWeightMin="0.45"
- android:minorWeightMin="0.72"
- android:majorWeightMax="0.45"
- android:minorWeightMax="0.72">
+ android:minorWeightMin="0.72">
<LinearLayout android:id="@+id/topPanel"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/alert_dialog.xml b/core/res/res/layout/alert_dialog.xml
index e3ba634..fd20bd1 100644
--- a/core/res/res/layout/alert_dialog.xml
+++ b/core/res/res/layout/alert_dialog.xml
@@ -29,8 +29,7 @@
android:paddingLeft="3dip"
android:paddingRight="1dip"
android:majorWeightMin="0.65"
- android:minorWeightMin="0.9"
- android:majorWeightMax="0.65">
+ android:minorWeightMin="0.9">
<LinearLayout android:id="@+id/topPanel"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/number_picker.xml b/core/res/res/layout/number_picker.xml
index 9241708..44c99cf 100644
--- a/core/res/res/layout/number_picker.xml
+++ b/core/res/res/layout/number_picker.xml
@@ -19,24 +19,19 @@
<merge xmlns:android="http://schemas.android.com/apk/res/android">
- <NumberPickerButton android:id="@+id/increment"
- android:layout_width="match_parent"
+ <ImageButton android:id="@+id/increment"
+ android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:background="@drawable/timepicker_up_btn" />
+ style="?android:attr/numberPickerUpButtonStyle" />
<EditText android:id="@+id/timepicker_input"
- android:layout_width="match_parent"
+ android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:gravity="center"
- android:singleLine="true"
- style="?android:attr/textAppearanceLargeInverse"
- android:textColor="@android:color/primary_text_light"
- android:textSize="30sp"
- android:background="@drawable/timepicker_input" />
+ style="?android:attr/numberPickerInputTextStyle" />
- <NumberPickerButton android:id="@+id/decrement"
- android:layout_width="match_parent"
+ <ImageButton android:id="@+id/decrement"
+ android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:background="@drawable/timepicker_down_btn" />
+ style="?android:attr/numberPickerDownButtonStyle" />
</merge>
diff --git a/core/res/res/layout/preference_list_content.xml b/core/res/res/layout/preference_list_content.xml
index 0f84418..fd488bd 100644
--- a/core/res/res/layout/preference_list_content.xml
+++ b/core/res/res/layout/preference_list_content.xml
@@ -64,8 +64,6 @@
android:layout_marginRight="@dimen/preference_screen_side_margin"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
- android:paddingLeft="32dip"
- android:paddingRight="32dip"
android:background="?attr/preferencePanelBackground"
android:visibility="gone" />
</LinearLayout>
diff --git a/core/res/res/layout/preference_list_fragment.xml b/core/res/res/layout/preference_list_fragment.xml
index dbe0df0..69fb73a 100644
--- a/core/res/res/layout/preference_list_fragment.xml
+++ b/core/res/res/layout/preference_list_fragment.xml
@@ -18,11 +18,11 @@
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/default_preference_layout"
android:orientation="vertical"
android:layout_height="match_parent"
android:layout_width="match_parent"
- android:background="@android:color/transparent">
+ android:background="@android:color/transparent"
+ android:layout_removeBorders="true">
<ListView android:id="@android:id/list"
android:layout_width="match_parent"
@@ -30,6 +30,8 @@
android:layout_weight="1"
android:paddingTop="48dip"
android:paddingBottom="48dip"
+ android:paddingLeft="32dip"
+ android:paddingRight="32dip"
android:clipToPadding="false"
android:drawSelectorOnTop="false"
android:cacheColorHint="@android:color/transparent"
diff --git a/core/res/res/layout/time_picker.xml b/core/res/res/layout/time_picker.xml
index 6124ea8..fa28842 100644
--- a/core/res/res/layout/time_picker.xml
+++ b/core/res/res/layout/time_picker.xml
@@ -28,32 +28,46 @@
<!-- hour -->
<NumberPicker
android:id="@+id/hour"
- android:layout_width="70dip"
+ android:layout_width="48dip"
android:layout_height="wrap_content"
+ android:layout_marginRight="20dip"
+ android:layout_marginTop="35dip"
+ android:layout_marginBottom="35dip"
android:focusable="true"
android:focusableInTouchMode="true"
/>
-
+
+ <!-- divider -->
+ <TextView
+ android:id="@+id/divider"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ />
+
<!-- minute -->
<NumberPicker
android:id="@+id/minute"
- android:layout_width="70dip"
+ android:layout_width="48dip"
android:layout_height="wrap_content"
- android:layout_marginLeft="5dip"
+ android:layout_marginLeft="20dip"
+ android:layout_marginRight="22dip"
+ android:layout_marginTop="35dip"
+ android:layout_marginBottom="35dip"
android:focusable="true"
android:focusableInTouchMode="true"
/>
-
+
<!-- AM / PM -->
- <Button
+ <NumberPicker
android:id="@+id/amPm"
- android:layout_width="wrap_content"
+ android:layout_width="48dip"
android:layout_height="wrap_content"
- android:layout_marginTop="43dip"
- android:layout_marginLeft="5dip"
- android:paddingLeft="20dip"
- android:paddingRight="20dip"
- style="?android:attr/textAppearanceLargeInverse"
- android:textColor="@android:color/primary_text_light_nodisable"
+ android:layout_marginLeft="22dip"
+ android:layout_marginTop="35dip"
+ android:layout_marginBottom="35dip"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
/>
+
</LinearLayout>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 006e36a..fd4b32c 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -667,7 +667,8 @@
<skip />
<!-- no translation found for lockscreen_too_many_failed_pin_attempts_dialog_message (6827749231465145590) -->
<skip />
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"لقد رسمت نقش إلغاء التأمين بشكل غير صحيح <xliff:g id="NUMBER_0">%d</xliff:g> مرة. بعد <xliff:g id="NUMBER_1">%d</xliff:g> من المحاولات غير الناجحة الأخرى، ستُطالب بإلغاء تأمين الهاتف باستخدام معلومات تسجيل الدخول إلى Google."\n\n" الرجاء المحاولة مرة أخرى خلال <xliff:g id="NUMBER_2">%d</xliff:g> ثانية."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"لقد رسمت نقش إلغاء التأمين بشكل غير صحيح <xliff:g id="NUMBER_0">%d</xliff:g> مرة. بعد <xliff:g id="NUMBER_1">%d</xliff:g> من المحاولات غير الناجحة الأخرى، ستُطالب بإلغاء تأمين الهاتف باستخدام معلومات تسجيل الدخول إلى Google."\n\n" الرجاء المحاولة مرة أخرى خلال <xliff:g id="NUMBER_2">%d</xliff:g> ثانية."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"حاول مرة أخرى خلال <xliff:g id="NUMBER">%d</xliff:g> ثانية."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"هل نسيت النمط؟"</string>
@@ -698,6 +699,8 @@
<string name="double_tap_toast" msgid="1068216937244567247">"نصيحة: اضغط مرتين للتكبير والتصغير."</string>
<!-- no translation found for autofill_this_form (1272247532604569872) -->
<skip />
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<!-- no translation found for autofill_address_name_separator (2504700673286691795) -->
<skip />
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 2c7dbeb..e01bb9b 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -667,7 +667,8 @@
<skip />
<!-- no translation found for lockscreen_too_many_failed_pin_attempts_dialog_message (6827749231465145590) -->
<skip />
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"Нарисувахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни опита ще ви бъде поискано да отключите телефона, използвайки данните си за вход в Google."\n\n" Моля, опитайте отново след <xliff:g id="NUMBER_2">%d</xliff:g> секунди."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"Нарисувахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни опита ще ви бъде поискано да отключите телефона, използвайки данните си за вход в Google."\n\n" Моля, опитайте отново след <xliff:g id="NUMBER_2">%d</xliff:g> секунди."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Опитайте отново след <xliff:g id="NUMBER">%d</xliff:g> секунди."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Забравили сте фигурата?"</string>
@@ -698,6 +699,8 @@
<string name="double_tap_toast" msgid="1068216937244567247">"Съвет: докоснете двукратно, за да увеличите или намалите мащаба."</string>
<!-- no translation found for autofill_this_form (1272247532604569872) -->
<skip />
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<!-- no translation found for autofill_address_name_separator (2504700673286691795) -->
<skip />
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 222be36..c32c95a 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -667,7 +667,8 @@
<skip />
<!-- no translation found for lockscreen_too_many_failed_pin_attempts_dialog_message (6827749231465145590) -->
<skip />
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"Heu dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%d</xliff:g> vegades de manera incorrecta. Després de <xliff:g id="NUMBER_1">%d</xliff:g> intents incorrectes més, se us demanarà que desbloquegeu el telèfon amb l\'inici de sessió de Google."\n\n" Torneu-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%d</xliff:g> segons."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"Heu dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%d</xliff:g> vegades de manera incorrecta. Després de <xliff:g id="NUMBER_1">%d</xliff:g> intents incorrectes més, se us demanarà que desbloquegeu el telèfon amb l\'inici de sessió de Google."\n\n" Torneu-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%d</xliff:g> segons."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Torneu-ho a provar d\'aquí a <xliff:g id="NUMBER">%d</xliff:g> segons."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Heu oblidat el patró?"</string>
@@ -698,6 +699,8 @@
<string name="double_tap_toast" msgid="1068216937244567247">"Consell: Piqueu dos cops per ampliar i reduir."</string>
<!-- no translation found for autofill_this_form (1272247532604569872) -->
<skip />
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<!-- no translation found for autofill_address_name_separator (2504700673286691795) -->
<skip />
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 666032c..f65f585 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -632,7 +632,8 @@
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"<xliff:g id="NUMBER_0">%d</xliff:g>krát jste nakreslili nesprávné bezpečnostní gesto. "\n\n"Opakujte prosím akci za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="4906034376425175381">"Vícekrát (<xliff:g id="NUMBER_0">%d</xliff:g>) jste nesprávně zadali heslo. "\n\n"Zkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6827749231465145590">"Vícekrát (<xliff:g id="NUMBER_0">%d</xliff:g>) jste nesprávně zadali kód PIN. "\n\n"Zkuste to znovu za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"<xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně nakreslili své bezpečnostní gesto. Po dalších neúspěšných pokusech (<xliff:g id="NUMBER_1">%d</xliff:g>) budete požádáni o odemčení telefonu pomocí přihlášení do účtu Google."\n\n" Akci prosím opakujte za několik sekund (<xliff:g id="NUMBER_2">%d</xliff:g>)."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"<xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně nakreslili své bezpečnostní gesto. Po dalších neúspěšných pokusech (<xliff:g id="NUMBER_1">%d</xliff:g>) budete požádáni o odemčení telefonu pomocí přihlášení do účtu Google."\n\n" Akci prosím opakujte za několik sekund (<xliff:g id="NUMBER_2">%d</xliff:g>)."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Sekundy zbývající do dalšího pokusu: <xliff:g id="NUMBER">%d</xliff:g>."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Zapomněli jste gesto?"</string>
@@ -662,6 +663,8 @@
<string name="save_password_label" msgid="6860261758665825069">"Potvrdit"</string>
<string name="double_tap_toast" msgid="1068216937244567247">"Tip: Dvojitým klepnutím můžete zobrazení přiblížit nebo oddálit."</string>
<!-- outdated translation 8940110866775097494 --> <string name="autofill_this_form" msgid="1272247532604569872">"Automaticky vyplnit tento formulář"</string>
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 36eb27a..8bb762b 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -632,7 +632,8 @@
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. "\n\n"Prøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="4906034376425175381">"Du har indtastet din adgangskode forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. "\n\n"Prøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6827749231465145590">"Du har indtastet din pinkode forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. "\n\n"Prøv igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> forsøg mere vil du blive bedt om at låse din telefon op ved hjælp af dit Google-login"\n\n" Prøv igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%d</xliff:g> forsøg mere vil du blive bedt om at låse din telefon op ved hjælp af dit Google-login"\n\n" Prøv igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Prøv igen om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Har du glemt mønstret?"</string>
@@ -662,6 +663,8 @@
<string name="save_password_label" msgid="6860261758665825069">"Bekræft"</string>
<string name="double_tap_toast" msgid="1068216937244567247">"Tip: Dobbeltklik for at zoome ind eller ud."</string>
<!-- outdated translation 8940110866775097494 --> <string name="autofill_this_form" msgid="1272247532604569872">"Autofuldfør denne formular"</string>
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index fe7ddc7..87e57ce 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -632,7 +632,8 @@
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. "\n\n"Versuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden erneut."</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="4906034376425175381">"Sie haben Ihr Passwort <xliff:g id="NUMBER_0">%d</xliff:g> Mal falsch eingegeben. "\n\n"Versuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden erneut."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6827749231465145590">"Sie haben Ihre PIN <xliff:g id="NUMBER_0">%d</xliff:g> Mal falsch eingegeben. "\n\n"Versuchen Sie es in <xliff:g id="NUMBER_1">%d</xliff:g> Sekunden erneut."</string>
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Telefon mithilfe Ihrer Google-Anmeldeinformationen zu entsperren. "\n\n"Versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden erneut."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Telefon mithilfe Ihrer Google-Anmeldeinformationen zu entsperren. "\n\n"Versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden erneut."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Versuchen Sie es in <xliff:g id="NUMBER">%d</xliff:g> Sekunden erneut."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Muster vergessen?"</string>
@@ -662,6 +663,8 @@
<string name="save_password_label" msgid="6860261758665825069">"Bestätigen"</string>
<string name="double_tap_toast" msgid="1068216937244567247">"Tipp: Zum Heranzoomen und Vergrößern zweimal tippen"</string>
<!-- outdated translation 8940110866775097494 --> <string name="autofill_this_form" msgid="1272247532604569872">"Dieses Formular automatisch ausfüllen"</string>
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 2103aef..bbd02f2 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -632,7 +632,8 @@
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Σχεδιάσατε εσφαλμένα το μοτίβο ξεκλειδώματος<xliff:g id="NUMBER_0">%d</xliff:g> φορές. "\n\n"Προσπαθήστε ξανά σε <xliff:g id="NUMBER_1">%d</xliff:g> δευτερόλεπτα."</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="4906034376425175381">"Καταχωρίσατε εσφαλμένα τον κωδικό πρόσβασης <xliff:g id="NUMBER_0">%d</xliff:g> φορές. "\n\n"Προσπαθήστε ξανά σε <xliff:g id="NUMBER_1">%d</xliff:g> δευτερόλεπτα."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6827749231465145590">"Καταχωρίσατε εσφαλμένα το PIN σας<xliff:g id="NUMBER_0">%d</xliff:g> φορές. "\n\n"Προσπαθήστε ξανά σε <xliff:g id="NUMBER_1">%d</xliff:g> δευτερόλεπτα."</string>
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> ανεπιτυχείς προσπάθειες ακόμη, θα σας ζητηθεί να ξεκλειδώσετε το τηλέφωνό σας με τη χρήση της σύνδεσής σας Google."\n\n" Προσπαθήστε ξανά σε <xliff:g id="NUMBER_2">%d</xliff:g> δευτερόλεπτα."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%d</xliff:g> ανεπιτυχείς προσπάθειες ακόμη, θα σας ζητηθεί να ξεκλειδώσετε το τηλέφωνό σας με τη χρήση της σύνδεσής σας Google."\n\n" Προσπαθήστε ξανά σε <xliff:g id="NUMBER_2">%d</xliff:g> δευτερόλεπτα."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Προσπαθήστε ξανά σε <xliff:g id="NUMBER">%d</xliff:g> δευτερόλεπτα."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Ξεχάσατε το μοτίβο;"</string>
@@ -662,6 +663,8 @@
<string name="save_password_label" msgid="6860261758665825069">"Επιβεβαίωση"</string>
<string name="double_tap_toast" msgid="1068216937244567247">"Συμβουλή: διπλό άγγιγμα για μεγέθυνση και σμίκρυνση."</string>
<!-- outdated translation 8940110866775097494 --> <string name="autofill_this_form" msgid="1272247532604569872">"Να γίνει αυτόματη συμπλήρωση αυτής της φόρμας"</string>
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index ce642aa..eab891f 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -658,7 +658,8 @@
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"You have drawn your unlock pattern incorrectly <xliff:g id="NUMBER_0">%d</xliff:g> times. "\n\n"Please try again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="4906034376425175381">"You have entered your password incorrectly <xliff:g id="NUMBER_0">%d</xliff:g> times. "\n\n"Please try again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6827749231465145590">"You have entered your PIN incorrectly <xliff:g id="NUMBER_0">%d</xliff:g> times. "\n\n"Please try again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"You have drawn your unlock pattern incorrectly <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using your Google sign-in."\n\n" Please try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"You have drawn your unlock pattern incorrectly <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using your Google sign-in."\n\n" Please try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Try again in <xliff:g id="NUMBER">%d</xliff:g> seconds."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Forgotten pattern?"</string>
@@ -689,6 +690,8 @@
<string name="double_tap_toast" msgid="1068216937244567247">"Tip: double-tap to zoom in and out."</string>
<!-- no translation found for autofill_this_form (1272247532604569872) -->
<skip />
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<!-- no translation found for autofill_address_name_separator (2504700673286691795) -->
<skip />
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index bd5371f..7fc79b1 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -631,7 +631,8 @@
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Has extraído incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Vuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="4906034376425175381">"Has ingresado tu contraseña de manera incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Vuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6827749231465145590">"Has ingresado tu PIN de manera incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Vuelve a intentarlo en <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"Has extraído incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos, se te solicitará que desbloquees tu teléfono al iniciar sesión en Google. "\n\n" Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"Has extraído incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos, se te solicitará que desbloquees tu teléfono al iniciar sesión en Google. "\n\n" Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Vuelve a intentarlo en <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"¿Olvidaste el patrón?"</string>
@@ -661,6 +662,8 @@
<string name="save_password_label" msgid="6860261758665825069">"Confirmar"</string>
<string name="double_tap_toast" msgid="1068216937244567247">"Sugerencia: presiona dos veces para acercar y alejar"</string>
<!-- outdated translation 8940110866775097494 --> <string name="autofill_this_form" msgid="1272247532604569872">"Autocompletar este formulario"</string>
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 5de5c9f..1b28dca 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -632,7 +632,8 @@
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Has realizado <xliff:g id="NUMBER_0">%d</xliff:g> intentos fallidos de creación de un patrón de desbloqueo. "\n\n"Inténtalo de nuevo dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="4906034376425175381">"Has introducido una contraseña incorrecta <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Inténtalo de nuevo dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6827749231465145590">"Has introducido un PIN incorrecto <xliff:g id="NUMBER_0">%d</xliff:g> veces. "\n\n"Inténtalo de nuevo dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"Has realizado <xliff:g id="NUMBER_0">%d</xliff:g> intentos fallidos de creación del patrón de desbloqueo. Si realizas <xliff:g id="NUMBER_1">%d</xliff:g> intentos fallidos más, se te pedirá que desbloquees el teléfono con tus credenciales de acceso de Google."\n\n" Espera <xliff:g id="NUMBER_2">%d</xliff:g> segundos e inténtalo de nuevo."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"Has realizado <xliff:g id="NUMBER_0">%d</xliff:g> intentos fallidos de creación del patrón de desbloqueo. Si realizas <xliff:g id="NUMBER_1">%d</xliff:g> intentos fallidos más, se te pedirá que desbloquees el teléfono con tus credenciales de acceso de Google."\n\n" Espera <xliff:g id="NUMBER_2">%d</xliff:g> segundos e inténtalo de nuevo."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Espera <xliff:g id="NUMBER">%d</xliff:g> segundos y vuelve a intentarlo."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"¿Has olvidado el patrón?"</string>
@@ -662,6 +663,8 @@
<string name="save_password_label" msgid="6860261758665825069">"Confirmar"</string>
<string name="double_tap_toast" msgid="1068216937244567247">"Sugerencia: toca dos veces para ampliar o reducir."</string>
<!-- outdated translation 8940110866775097494 --> <string name="autofill_this_form" msgid="1272247532604569872">"Autocompletar este formulario"</string>
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index cd67c09..cbb5fe3 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -667,7 +667,8 @@
<skip />
<!-- no translation found for lockscreen_too_many_failed_pin_attempts_dialog_message (6827749231465145590) -->
<skip />
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"شما الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه کشیده اید. <xliff:g id="NUMBER_1">%d</xliff:g> تلاش های ناموفق بیشتر سبب می شود از شما خواسته شود که برای بازگشایی قفل گوشی خود به برنامه Google وارد شوید."\n\n" لطفاً پس از <xliff:g id="NUMBER_2">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"شما الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه کشیده اید. <xliff:g id="NUMBER_1">%d</xliff:g> تلاش های ناموفق بیشتر سبب می شود از شما خواسته شود که برای بازگشایی قفل گوشی خود به برنامه Google وارد شوید."\n\n" لطفاً پس از <xliff:g id="NUMBER_2">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"در <xliff:g id="NUMBER">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"الگو را فراموش کرده اید؟"</string>
@@ -698,6 +699,8 @@
<string name="double_tap_toast" msgid="1068216937244567247">"نکته: برای انجام بزرگنمایی مثبت و منفی، دو بار ضربه بزنید."</string>
<!-- no translation found for autofill_this_form (1272247532604569872) -->
<skip />
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<!-- no translation found for autofill_address_name_separator (2504700673286691795) -->
<skip />
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 7329bed..3390669 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -667,7 +667,8 @@
<skip />
<!-- no translation found for lockscreen_too_many_failed_pin_attempts_dialog_message (6827749231465145590) -->
<skip />
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%d</xliff:g> kertaa, sinua pyydetään poistamaan puhelimesi lukitus Google-sisäänkirjautumisen avulla."\n\n" Yritä uudelleen <xliff:g id="NUMBER_2">%d</xliff:g> sekunnin kuluttua."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%d</xliff:g> kertaa, sinua pyydetään poistamaan puhelimesi lukitus Google-sisäänkirjautumisen avulla."\n\n" Yritä uudelleen <xliff:g id="NUMBER_2">%d</xliff:g> sekunnin kuluttua."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Yritä uudelleen <xliff:g id="NUMBER">%d</xliff:g> sekunnin kuluttua."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Unohditko mallin?"</string>
@@ -698,6 +699,8 @@
<string name="double_tap_toast" msgid="1068216937244567247">"Vinkki: lähennä ja loitonna kaksoisnapauttamalla"</string>
<!-- no translation found for autofill_this_form (1272247532604569872) -->
<skip />
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<!-- no translation found for autofill_address_name_separator (2504700673286691795) -->
<skip />
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index fa97fc0..f618070 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -632,7 +632,8 @@
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Vous avez mal reproduit le schéma de déverrouillage <xliff:g id="NUMBER_0">%d</xliff:g> fois. "\n\n"Veuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="4906034376425175381">"Vous avez saisi un mot de passe incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. "\n\n"Veuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6827749231465145590">"Vous avez saisi un code PIN incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. "\n\n"Veuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"Vous avez mal saisi le schéma de déverrouillage <xliff:g id="NUMBER_0">%d</xliff:g> fois. Au bout de <xliff:g id="NUMBER_1">%d</xliff:g> tentatives supplémentaires, vous devrez débloquer votre téléphone à l\'aide de votre identifiant Google."\n\n"Merci de réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"Vous avez mal saisi le schéma de déverrouillage <xliff:g id="NUMBER_0">%d</xliff:g> fois. Au bout de <xliff:g id="NUMBER_1">%d</xliff:g> tentatives supplémentaires, vous devrez débloquer votre téléphone à l\'aide de votre identifiant Google."\n\n"Merci de réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Réessayez dans <xliff:g id="NUMBER">%d</xliff:g> secondes."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Schéma oublié ?"</string>
@@ -662,6 +663,8 @@
<string name="save_password_label" msgid="6860261758665825069">"Confirmer"</string>
<string name="double_tap_toast" msgid="1068216937244567247">"Conseil : Appuyez deux fois pour effectuer un zoom avant ou arrière."</string>
<!-- outdated translation 8940110866775097494 --> <string name="autofill_this_form" msgid="1272247532604569872">"Permettre le remplissage automatique du formulaire"</string>
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
diff --git a/core/res/res/values-he/strings.xml b/core/res/res/values-he/strings.xml
index 9792bd9..c5d945c 100644
--- a/core/res/res/values-he/strings.xml
+++ b/core/res/res/values-he/strings.xml
@@ -667,7 +667,8 @@
<skip />
<!-- no translation found for lockscreen_too_many_failed_pin_attempts_dialog_message (6827749231465145590) -->
<skip />
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"ציירת את קו ביטול הנעילה באופן שגוי <xliff:g id="NUMBER_0">%d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות כושלים נוספים, תתבקש לבטל את נעילה הטלפון באמצעות פרטי הכניסה שלך ב-Google."\n\n" נסה שוב בעוד <xliff:g id="NUMBER_2">%d</xliff:g> שניות."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"ציירת את קו ביטול הנעילה באופן שגוי <xliff:g id="NUMBER_0">%d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות כושלים נוספים, תתבקש לבטל את נעילה הטלפון באמצעות פרטי הכניסה שלך ב-Google."\n\n" נסה שוב בעוד <xliff:g id="NUMBER_2">%d</xliff:g> שניות."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"נסה שוב בעוד <xliff:g id="NUMBER">%d</xliff:g> שניות."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"שכחת את הקו?"</string>
@@ -698,6 +699,8 @@
<string name="double_tap_toast" msgid="1068216937244567247">"טיפש: הקש פעמיים כדי להתקרב ולהתרחק."</string>
<!-- no translation found for autofill_this_form (1272247532604569872) -->
<skip />
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<!-- no translation found for autofill_address_name_separator (2504700673286691795) -->
<skip />
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 1116841..bc6d451 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -667,7 +667,8 @@
<skip />
<!-- no translation found for lockscreen_too_many_failed_pin_attempts_dialog_message (6827749231465145590) -->
<skip />
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"Netočno ste iscrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. Nakon još <xliff:g id="NUMBER_1">%d</xliff:g> neuspješna pokušaja, morat ćete otključati telefon pomoću Google prijave."\n\n" Pokušajte ponovo za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"Netočno ste iscrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. Nakon još <xliff:g id="NUMBER_1">%d</xliff:g> neuspješna pokušaja, morat ćete otključati telefon pomoću Google prijave."\n\n" Pokušajte ponovo za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Pokušajte ponovno za <xliff:g id="NUMBER">%d</xliff:g> s."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Zaboravili ste uzorak?"</string>
@@ -698,6 +699,8 @@
<string name="double_tap_toast" msgid="1068216937244567247">"Savjet: Dvaput dotaknite za povećanje i smanjivanje."</string>
<!-- no translation found for autofill_this_form (1272247532604569872) -->
<skip />
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<!-- no translation found for autofill_address_name_separator (2504700673286691795) -->
<skip />
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 5f6dddd..36aea65 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -667,7 +667,8 @@
<skip />
<!-- no translation found for lockscreen_too_many_failed_pin_attempts_dialog_message (6827749231465145590) -->
<skip />
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"Helytelenül rajzolta le a feloldási mintát <xliff:g id="NUMBER_0">%d</xliff:g> alkalommal. További <xliff:g id="NUMBER_1">%d</xliff:g> sikertelen kísérlet után a Google rendszerében használt bejelentkezési adataival kell feloldania a telefonját."\n\n" Kérjük, próbálja újra <xliff:g id="NUMBER_2">%d</xliff:g> másodperc múlva."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"Helytelenül rajzolta le a feloldási mintát <xliff:g id="NUMBER_0">%d</xliff:g> alkalommal. További <xliff:g id="NUMBER_1">%d</xliff:g> sikertelen kísérlet után a Google rendszerében használt bejelentkezési adataival kell feloldania a telefonját."\n\n" Kérjük, próbálja újra <xliff:g id="NUMBER_2">%d</xliff:g> másodperc múlva."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Próbálkozzon újra <xliff:g id="NUMBER">%d</xliff:g> másodperc múlva."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Elfelejtette a mintát?"</string>
@@ -698,6 +699,8 @@
<string name="double_tap_toast" msgid="1068216937244567247">"Tipp: érintse meg kétszer a nagyításhoz és kicsinyítéshez."</string>
<!-- no translation found for autofill_this_form (1272247532604569872) -->
<skip />
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<!-- no translation found for autofill_address_name_separator (2504700673286691795) -->
<skip />
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
diff --git a/core/res/res/values-id/strings.xml b/core/res/res/values-id/strings.xml
index 1de0f41..2d07b33 100644
--- a/core/res/res/values-id/strings.xml
+++ b/core/res/res/values-id/strings.xml
@@ -667,7 +667,8 @@
<skip />
<!-- no translation found for lockscreen_too_many_failed_pin_attempts_dialog_message (6827749231465145590) -->
<skip />
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"Anda telah salah menggambar pola pembuka kunci sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> upaya gagal lagi, Anda akan diminta membuka kunci ponsel menggunakan info masuk Google."\n\n" Harap coba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> detik."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"Anda telah salah menggambar pola pembuka kunci sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> upaya gagal lagi, Anda akan diminta membuka kunci ponsel menggunakan info masuk Google."\n\n" Harap coba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> detik."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Coba lagi dalam <xliff:g id="NUMBER">%d</xliff:g> detik."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Lupa pola?"</string>
@@ -698,6 +699,8 @@
<string name="double_tap_toast" msgid="1068216937244567247">"Kiat: ketuk dua kali untuk memperbesar dan memperkecil."</string>
<!-- no translation found for autofill_this_form (1272247532604569872) -->
<skip />
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<!-- no translation found for autofill_address_name_separator (2504700673286691795) -->
<skip />
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 89d0a32..238a748 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -632,7 +632,8 @@
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi di inserimento della sequenza di sblocco. "\n\n"Riprova fra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="4906034376425175381">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento della password. "\n\n"Riprova tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6827749231465145590">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi errati di inserimento del PIN. "\n\n"Riprova tra <xliff:g id="NUMBER_1">%d</xliff:g> secondi."</string>
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il telefono tramite i dati di accesso di Google."\n\n"Riprova fra <xliff:g id="NUMBER_2">%d</xliff:g> secondi."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"<xliff:g id="NUMBER_0">%d</xliff:g> tentativi di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il telefono tramite i dati di accesso di Google."\n\n"Riprova fra <xliff:g id="NUMBER_2">%d</xliff:g> secondi."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Riprova fra <xliff:g id="NUMBER">%d</xliff:g> secondi."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Hai dimenticato la sequenza?"</string>
@@ -662,6 +663,8 @@
<string name="save_password_label" msgid="6860261758665825069">"Conferma"</string>
<string name="double_tap_toast" msgid="1068216937244567247">"Suggerimento. Tocca due volte per aumentare/ridurre lo zoom."</string>
<!-- outdated translation 8940110866775097494 --> <string name="autofill_this_form" msgid="1272247532604569872">"Compila automaticamente il modulo"</string>
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index dcbcdc2..75d3722 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -632,7 +632,8 @@
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"ロック解除のパターンは<xliff:g id="NUMBER_0">%d</xliff:g>回とも正しく指定されていません。"\n\n"<xliff:g id="NUMBER_1">%d</xliff:g>秒後にもう一度指定してください。"</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="4906034376425175381">"入力したパスワードは<xliff:g id="NUMBER_0">%d</xliff:g>回とも正しくありませんでした。"\n\n"<xliff:g id="NUMBER_1">%d</xliff:g>秒後にもう一度入力してください。"</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6827749231465145590">"入力したPINは<xliff:g id="NUMBER_0">%d</xliff:g>回とも正しくありませんでした。"\n\n"<xliff:g id="NUMBER_1">%d</xliff:g>秒後にもう一度入力してください。"</string>
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"指定したパターンは<xliff:g id="NUMBER_0">%d</xliff:g>回とも正しくありません。あと<xliff:g id="NUMBER_1">%d</xliff:g>回指定に失敗すると、携帯電話のロックの解除にGoogleへのログインが必要になります。"\n\n"<xliff:g id="NUMBER_2">%d</xliff:g>秒後にもう一度指定してください。"</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"指定したパターンは<xliff:g id="NUMBER_0">%d</xliff:g>回とも正しくありません。あと<xliff:g id="NUMBER_1">%d</xliff:g>回指定に失敗すると、携帯電話のロックの解除にGoogleへのログインが必要になります。"\n\n"<xliff:g id="NUMBER_2">%d</xliff:g>秒後にもう一度指定してください。"</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"<xliff:g id="NUMBER">%d</xliff:g>秒後にやり直してください。"</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"パターンを忘れた場合"</string>
@@ -662,6 +663,8 @@
<string name="save_password_label" msgid="6860261758665825069">"確認"</string>
<string name="double_tap_toast" msgid="1068216937244567247">"ヒント: ダブルタップで拡大/縮小できます。"</string>
<!-- outdated translation 8940110866775097494 --> <string name="autofill_this_form" msgid="1272247532604569872">"このフォームを自動入力"</string>
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 8fe117f..1ed8492 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -632,7 +632,8 @@
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 그렸습니다. "\n\n"<xliff:g id="NUMBER_1">%d</xliff:g>초 후에 다시 시도하세요."</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="4906034376425175381">"비밀번호를 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 입력했습니다. "\n\n"<xliff:g id="NUMBER_1">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6827749231465145590">"PIN을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 입력했습니다. "\n\n"<xliff:g id="NUMBER_1">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 그렸습니다. <xliff:g id="NUMBER_1">%d</xliff:g>회 더 실패하면 Google 로그인을 통해 휴대전화를 잠금해제하도록 요청됩니다. "\n\n" <xliff:g id="NUMBER_2">%d</xliff:g>초 후에 다시 시도하세요."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 그렸습니다. <xliff:g id="NUMBER_1">%d</xliff:g>회 더 실패하면 Google 로그인을 통해 휴대전화를 잠금해제하도록 요청됩니다. "\n\n" <xliff:g id="NUMBER_2">%d</xliff:g>초 후에 다시 시도하세요."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"<xliff:g id="NUMBER">%d</xliff:g>초 후에 다시 시도하세요."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"패턴을 잊으셨나요?"</string>
@@ -662,6 +663,8 @@
<string name="save_password_label" msgid="6860261758665825069">"확인"</string>
<string name="double_tap_toast" msgid="1068216937244567247">"도움말: 축소/확대하려면 두 번 누릅니다."</string>
<!-- outdated translation 8940110866775097494 --> <string name="autofill_this_form" msgid="1272247532604569872">"양식 자동완성"</string>
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
diff --git a/core/res/res/values-large/config.xml b/core/res/res/values-large/config.xml
new file mode 100644
index 0000000..05dd050
--- /dev/null
+++ b/core/res/res/values-large/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2010, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- see comment in values/config.xml -->
+ <dimen name="config_prefDialogWidth">440dp</dimen>
+</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 6378c62..41d9fbd 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -667,7 +667,8 @@
<skip />
<!-- no translation found for lockscreen_too_many_failed_pin_attempts_dialog_message (6827749231465145590) -->
<skip />
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"Neteisingai nurodėte savo atrakinimo modelį <xliff:g id="NUMBER_0">%d</xliff:g> kartus (-ų). Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkmingų bandymų būsite paprašyti atrakinti telefoną naudojant „Google“ prisijungimo duomenis."\n\n" Bandykite dar kartą po <xliff:g id="NUMBER_2">%d</xliff:g> sek."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"Neteisingai nurodėte savo atrakinimo modelį <xliff:g id="NUMBER_0">%d</xliff:g> kartus (-ų). Po dar <xliff:g id="NUMBER_1">%d</xliff:g> nesėkmingų bandymų būsite paprašyti atrakinti telefoną naudojant „Google“ prisijungimo duomenis."\n\n" Bandykite dar kartą po <xliff:g id="NUMBER_2">%d</xliff:g> sek."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Bandyti dar kartą po <xliff:g id="NUMBER">%d</xliff:g> sek."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Pamiršote modelį?"</string>
@@ -698,6 +699,8 @@
<string name="double_tap_toast" msgid="1068216937244567247">"Patarimas: bakstelėkite du kartus, kad padidintumėte ar sumažintumėte mastelį."</string>
<!-- no translation found for autofill_this_form (1272247532604569872) -->
<skip />
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<!-- no translation found for autofill_address_name_separator (2504700673286691795) -->
<skip />
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 35118ec..d706ed5 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -667,7 +667,8 @@
<skip />
<!-- no translation found for lockscreen_too_many_failed_pin_attempts_dialog_message (6827749231465145590) -->
<skip />
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"Atbloķēšanas kombinācija tika nepareizi uzzīmēta <xliff:g id="NUMBER_0">%d</xliff:g> reizi(-es). Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīgiem mēģinājumiem tālrunis būs jāatbloķē, izmantojot Google pierakstīšanos."\n\n" Lūdzu, mēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%d</xliff:g> sekundes(-ēm)."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"Atbloķēšanas kombinācija tika nepareizi uzzīmēta <xliff:g id="NUMBER_0">%d</xliff:g> reizi(-es). Pēc vēl <xliff:g id="NUMBER_1">%d</xliff:g> neveiksmīgiem mēģinājumiem tālrunis būs jāatbloķē, izmantojot Google pierakstīšanos."\n\n" Lūdzu, mēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%d</xliff:g> sekundes(-ēm)."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Mēģiniet vēlreiz pēc <xliff:g id="NUMBER">%d</xliff:g> sekundes(-ēm)."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Vai aizmirsāt kombināciju?"</string>
@@ -698,6 +699,8 @@
<string name="double_tap_toast" msgid="1068216937244567247">"Padoms: divreiz pieskarieties, lai tuvinātu un tālinātu."</string>
<!-- no translation found for autofill_this_form (1272247532604569872) -->
<skip />
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<!-- no translation found for autofill_address_name_separator (2504700673286691795) -->
<skip />
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index cdc3f0a..96d9c32 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -632,7 +632,8 @@
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. "\n\n"Please try again in <xliff:g id="NUMBER_1">%d</xliff:g> seconds."</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="4906034376425175381">"Du har oppgitt feil passord <xliff:g id="NUMBER_0">%d</xliff:g> ganger. "\n\n"Prøv igjen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6827749231465145590">"Du har oppgitt feil personlig kode <xliff:g id="NUMBER_0">%d</xliff:g> ganger. "\n\n"Prøv igjen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using your Google sign-in."\n\n" Please try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%d</xliff:g> times. After <xliff:g id="NUMBER_1">%d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using your Google sign-in."\n\n" Please try again in <xliff:g id="NUMBER_2">%d</xliff:g> seconds."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Prøv igjen om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Glemt mønsteret?"</string>
@@ -662,6 +663,8 @@
<string name="save_password_label" msgid="6860261758665825069">"Bekreft"</string>
<string name="double_tap_toast" msgid="1068216937244567247">"Dobbelttrykk for å zoome inn og ut."</string>
<!-- outdated translation 8940110866775097494 --> <string name="autofill_this_form" msgid="1272247532604569872">"Fyll ut dette skjemaet automatisk"</string>
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 12034f2..8998fba 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -632,7 +632,8 @@
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. "\n\n"Probeer het over <xliff:g id="NUMBER_1">%d</xliff:g> seconden opnieuw."</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="4906034376425175381">"U heeft uw wachtwoord <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist ingevoerd. "\n\n"Probeer het over <xliff:g id="NUMBER_1">%d</xliff:g> seconden opnieuw."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6827749231465145590">"U heeft uw PIN-code <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist ingevoerd. "\n\n"Probeer het over <xliff:g id="NUMBER_1">%d</xliff:g> seconden opnieuw."</string>
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen, wordt u gevraagd om uw telefoon te ontgrendelen met uw Google aanmelding."\n\n" Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"U heeft uw ontgrendelingspatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%d</xliff:g> mislukte pogingen, wordt u gevraagd om uw telefoon te ontgrendelen met uw Google aanmelding."\n\n" Probeer het over <xliff:g id="NUMBER_2">%d</xliff:g> seconden opnieuw."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Probeer het over <xliff:g id="NUMBER">%d</xliff:g> seconden opnieuw."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Patroon vergeten?"</string>
@@ -662,6 +663,8 @@
<string name="save_password_label" msgid="6860261758665825069">"Bevestigen"</string>
<string name="double_tap_toast" msgid="1068216937244567247">"Tip: tik tweemaal om in of uit te zoomen."</string>
<!-- outdated translation 8940110866775097494 --> <string name="autofill_this_form" msgid="1272247532604569872">"Dit formulier automatisch aanvullen"</string>
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 089026f..ec80f83 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -632,7 +632,8 @@
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Wzór odblokowania został nieprawidłowo narysowany <xliff:g id="NUMBER_0">%d</xliff:g> razy. "\n\n"Spróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> sekund."</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="4906034376425175381">"Hasło zostało nieprawidłowo wprowadzone <xliff:g id="NUMBER_0">%d</xliff:g> razy. "\n\n"Spróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6827749231465145590">"Niepoprawnie wprowadzono kod PIN <xliff:g id="NUMBER_0">%d</xliff:g> razy. "\n\n"Spróbuj ponownie za <xliff:g id="NUMBER_1">%d</xliff:g> s."</string>
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"Wzór odblokowania został narysowany nieprawidłowo <xliff:g id="NUMBER_0">%d</xliff:g> razy. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach telefon trzeba będzie odblokować przez zalogowanie na koncie Google."\n\n" Spróbuj ponownie za <xliff:g id="NUMBER_2">%d</xliff:g> sekund."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"Wzór odblokowania został narysowany nieprawidłowo <xliff:g id="NUMBER_0">%d</xliff:g> razy. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach telefon trzeba będzie odblokować przez zalogowanie na koncie Google."\n\n" Spróbuj ponownie za <xliff:g id="NUMBER_2">%d</xliff:g> sekund."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Spróbuj ponownie za <xliff:g id="NUMBER">%d</xliff:g> sekund."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Zapomniałeś wzoru?"</string>
@@ -662,6 +663,8 @@
<string name="save_password_label" msgid="6860261758665825069">"Potwierdź"</string>
<string name="double_tap_toast" msgid="1068216937244567247">"Wskazówka: dotknij dwukrotnie, aby powiększyć lub pomniejszyć."</string>
<!-- outdated translation 8940110866775097494 --> <string name="autofill_this_form" msgid="1272247532604569872">"Wypełnij ten formularz automatycznie"</string>
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 3f270a0..5e9b0a4 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -632,7 +632,8 @@
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Efectuou incorrectamente o seu padrão de desbloqueio <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="4906034376425175381">"Introduziu incorrectamente a palavra-passe <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6827749231465145590">"Introduziu incorrectamente o PIN <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente dentro de <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"Efectuou incorrectamente o seu padrão de desbloqueio <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após outras <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem sucesso, ser-lhe-á pedido para desbloquear o telefone utilizando o seu início de sessão no Google."\n\n" Tente novamente dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"Efectuou incorrectamente o seu padrão de desbloqueio <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Após outras <xliff:g id="NUMBER_1">%d</xliff:g> tentativas sem sucesso, ser-lhe-á pedido para desbloquear o telefone utilizando o seu início de sessão no Google."\n\n" Tente novamente dentro de <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Tente novamente dentro de <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Esqueceu-se do padrão?"</string>
@@ -662,6 +663,8 @@
<string name="save_password_label" msgid="6860261758665825069">"Confirmar"</string>
<string name="double_tap_toast" msgid="1068216937244567247">"Sugestão: toque duas vezes para aumentar ou diminuir o zoom."</string>
<!-- outdated translation 8940110866775097494 --> <string name="autofill_this_form" msgid="1272247532604569872">"Preenchimento automático deste formulário"</string>
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 368132e..ad8f64a 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -632,7 +632,8 @@
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Você desenhou incorretamente o seu padrão de desbloqueio <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="4906034376425175381">"Você inseriu incorretamente a sua senha <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6827749231465145590">"Você digitou incorretamente o seu PIN <xliff:g id="NUMBER_0">%d</xliff:g> vezes. "\n\n"Tente novamente em <xliff:g id="NUMBER_1">%d</xliff:g> segundos."</string>
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"Você desenhou o seu padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas e você receberá uma solicitação para desbloquear o seu telefone usando o seu login do Google."\n\n" Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"Você desenhou o seu padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas e você receberá uma solicitação para desbloquear o seu telefone usando o seu login do Google."\n\n" Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Tente novamente em <xliff:g id="NUMBER">%d</xliff:g> segundos."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Esqueceu o padrão?"</string>
@@ -662,6 +663,8 @@
<string name="save_password_label" msgid="6860261758665825069">"Confirmar"</string>
<string name="double_tap_toast" msgid="1068216937244567247">"Dica: toque duas vezes para aumentar e diminuir o zoom."</string>
<!-- outdated translation 8940110866775097494 --> <string name="autofill_this_form" msgid="1272247532604569872">"Preencher automaticamente este formulário"</string>
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index e8f7298..527e4e1 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -659,7 +659,8 @@
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Vus avais dissegnà fallà <xliff:g id="NUMBER_0">%d</xliff:g> giadas Voss schema da debloccaziun. "\n\n"Empruvai anc ina giada en <xliff:g id="NUMBER_1">%d</xliff:g> secundas."</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="4906034376425175381">"Vus avais endatà <xliff:g id="NUMBER_0">%d</xliff:g> giadas in pled-clav nuncorrect. "\n\n"Empruvai anc ina giada en <xliff:g id="NUMBER_1">%d</xliff:g> secundas."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6827749231465145590">"Vus avais endatà <xliff:g id="NUMBER_0">%d</xliff:g> giadas in code PIN nuncorrect. "\n\n"Empruvai anc ina giada en <xliff:g id="NUMBER_1">%d</xliff:g> secundas."</string>
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"Vus avais dissegnà <xliff:g id="NUMBER_0">%d</xliff:g> giadas in schema da debloccaziun nuncorrect. Suenter <xliff:g id="NUMBER_1">%d</xliff:g> ulteriuras emprovas senza success As dumonda il sistem da debloccar il telefonin cun agid da Vossas infurmaziuns d\'annunzia da Google."\n\n"Empruvai per plaschair anc ina giada en <xliff:g id="NUMBER_2">%d</xliff:g> secundas."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"Vus avais dissegnà <xliff:g id="NUMBER_0">%d</xliff:g> giadas in schema da debloccaziun nuncorrect. Suenter <xliff:g id="NUMBER_1">%d</xliff:g> ulteriuras emprovas senza success As dumonda il sistem da debloccar il telefonin cun agid da Vossas infurmaziuns d\'annunzia da Google."\n\n"Empruvai per plaschair anc ina giada en <xliff:g id="NUMBER_2">%d</xliff:g> secundas."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Empruvar anc ina giada en <xliff:g id="NUMBER">%d</xliff:g> secundas."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Emblidà il schema?"</string>
@@ -690,6 +691,8 @@
<string name="double_tap_toast" msgid="1068216937244567247">"Tip: Smatgar duas giadas per zoomar pli datiers u zoomar pli lontan."</string>
<!-- no translation found for autofill_this_form (1272247532604569872) -->
<skip />
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<!-- no translation found for autofill_address_name_separator (2504700673286691795) -->
<skip />
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index e1a31f0..486591c 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -667,7 +667,8 @@
<skip />
<!-- no translation found for lockscreen_too_many_failed_pin_attempts_dialog_message (6827749231465145590) -->
<skip />
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> de ori. După <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi telefonul cu ajutorul datelor de conectare la Google."\n\n" Încercaţi din nou în <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> de ori. După <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi telefonul cu ajutorul datelor de conectare la Google."\n\n" Încercaţi din nou în <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Încercaţi din nou peste <xliff:g id="NUMBER">%d</xliff:g> (de) secunde."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Aţi uitat modelul?"</string>
@@ -698,6 +699,8 @@
<string name="double_tap_toast" msgid="1068216937244567247">"Sfat: apăsaţi de două ori pentru a mări şi a micşora."</string>
<!-- no translation found for autofill_this_form (1272247532604569872) -->
<skip />
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<!-- no translation found for autofill_address_name_separator (2504700673286691795) -->
<skip />
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 0ef23ee..976a006 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -632,7 +632,8 @@
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Количество неудачных попыток ввода графического ключа разблокировки: <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n"Повторите попытку через <xliff:g id="NUMBER_1">%d</xliff:g> с."</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="4906034376425175381">"Количество неудачных попыток ввода пароля: <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n"Повторите попытку через <xliff:g id="NUMBER_1">%d</xliff:g> с."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6827749231465145590">"Количество неудачных попыток ввода PIN-кода: <xliff:g id="NUMBER_0">%d</xliff:g>. "\n\n"Повторите попытку через <xliff:g id="NUMBER_1">%d</xliff:g> с."</string>
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"Количество неудачных попыток ввода графического ключа разблокировки: <xliff:g id="NUMBER_0">%d</xliff:g>. После <xliff:g id="NUMBER_1">%d</xliff:g> неудачных попыток вам будет предложено разблокировать телефон с помощью учетных данных Google. "\n\n" Повторите попытку через <xliff:g id="NUMBER_2">%d</xliff:g> с."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"Количество неудачных попыток ввода графического ключа разблокировки: <xliff:g id="NUMBER_0">%d</xliff:g>. После <xliff:g id="NUMBER_1">%d</xliff:g> неудачных попыток вам будет предложено разблокировать телефон с помощью учетных данных Google. "\n\n" Повторите попытку через <xliff:g id="NUMBER_2">%d</xliff:g> с."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Повторите попытку через <xliff:g id="NUMBER">%d</xliff:g> с."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Забыли графический ключ?"</string>
@@ -656,12 +657,14 @@
<string name="factorytest_not_system" msgid="4435201656767276723">"Действие FACTORY_TEST поддерживается только для пакетов, установленных в /system/app."</string>
<string name="factorytest_no_action" msgid="872991874799998561">"Пакет, обеспечивающий действие FACTORY_TEST, не найден."</string>
<string name="factorytest_reboot" msgid="6320168203050791643">"Перезагрузка"</string>
- <string name="js_dialog_title" msgid="8143918455087008109">"На странице по адресу \"<xliff:g id="TITLE">%s</xliff:g>\" сказано:"</string>
+ <string name="js_dialog_title" msgid="8143918455087008109">"Подтвердите действие на <xliff:g id="TITLE">%s</xliff:g>"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
<string name="js_dialog_before_unload" msgid="1901675448179653089">"Перейти с этой страницы?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Нажмите \"ОК\", чтобы продолжить, или \"Отмена\", чтобы остаться на текущей странице."</string>
<string name="save_password_label" msgid="6860261758665825069">"Подтвердите"</string>
<string name="double_tap_toast" msgid="1068216937244567247">"Совет: нажмите дважды, чтобы увеличить и уменьшить масштаб."</string>
<!-- outdated translation 8940110866775097494 --> <string name="autofill_this_form" msgid="1272247532604569872">"Заполнить форму автоматически"</string>
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 77dc235..7e21ae5 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -667,7 +667,8 @@
<skip />
<!-- no translation found for lockscreen_too_many_failed_pin_attempts_dialog_message (6827749231465145590) -->
<skip />
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po ďalších neúspešných pokusoch (<xliff:g id="NUMBER_1">%d</xliff:g>) budete požiadaní o odblokovanie telefónu pomocou prihlásenia do služby Google."\n\n" Skúste to znova o niekoľko sekúnd (<xliff:g id="NUMBER_2">%d</xliff:g>)."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po ďalších neúspešných pokusoch (<xliff:g id="NUMBER_1">%d</xliff:g>) budete požiadaní o odblokovanie telefónu pomocou prihlásenia do služby Google."\n\n" Skúste to znova o niekoľko sekúnd (<xliff:g id="NUMBER_2">%d</xliff:g>)."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Počet sekúnd zostávajúcich do ďalšieho pokusu: <xliff:g id="NUMBER">%d</xliff:g>."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Zabudli ste vzor?"</string>
@@ -698,6 +699,8 @@
<string name="double_tap_toast" msgid="1068216937244567247">"Tip: Dvojitým klepnutím môžete zobrazenie priblížiť alebo oddialiť."</string>
<!-- no translation found for autofill_this_form (1272247532604569872) -->
<skip />
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<!-- no translation found for autofill_address_name_separator (2504700673286691795) -->
<skip />
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index fba50c0..68eb899 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -667,7 +667,8 @@
<skip />
<!-- no translation found for lockscreen_too_many_failed_pin_attempts_dialog_message (6827749231465145590) -->
<skip />
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"Vzorec za odklepanje ste nepravilno vnesli <xliff:g id="NUMBER_0">%d</xliff:g>-krat. Po <xliff:g id="NUMBER_1">%d</xliff:g> neuspešnih poskusih boste pozvani, da odklenete telefon z Googlovimi podatki za prijavo."\n\n" Poskusite znova čez <xliff:g id="NUMBER_2">%d</xliff:g> sekund."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"Vzorec za odklepanje ste nepravilno vnesli <xliff:g id="NUMBER_0">%d</xliff:g>-krat. Po <xliff:g id="NUMBER_1">%d</xliff:g> neuspešnih poskusih boste pozvani, da odklenete telefon z Googlovimi podatki za prijavo."\n\n" Poskusite znova čez <xliff:g id="NUMBER_2">%d</xliff:g> sekund."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Poskusite znova čez <xliff:g id="NUMBER">%d</xliff:g> sekund."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Ali ste pozabili vzorec?"</string>
@@ -698,6 +699,8 @@
<string name="double_tap_toast" msgid="1068216937244567247">"Namig: tapnite dvakrat, če želite povečati ali pomanjšati."</string>
<!-- no translation found for autofill_this_form (1272247532604569872) -->
<skip />
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<!-- no translation found for autofill_address_name_separator (2504700673286691795) -->
<skip />
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 58e4700..5cf7223 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -667,7 +667,8 @@
<skip />
<!-- no translation found for lockscreen_too_many_failed_pin_attempts_dialog_message (6827749231465145590) -->
<skip />
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"<xliff:g id="NUMBER_0">%d</xliff:g> пута сте нетачно унели шаблон за откључавање. Након још <xliff:g id="NUMBER_1">%d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате телефон помоћу података за пријављивање на Google."\n\n" Покушајте поново за <xliff:g id="NUMBER_2">%d</xliff:g> секунде(и)."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"<xliff:g id="NUMBER_0">%d</xliff:g> пута сте нетачно унели шаблон за откључавање. Након још <xliff:g id="NUMBER_1">%d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате телефон помоћу података за пријављивање на Google."\n\n" Покушајте поново за <xliff:g id="NUMBER_2">%d</xliff:g> секунде(и)."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Покушајте поново за <xliff:g id="NUMBER">%d</xliff:g> секунде(и)."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Заборавили сте шаблон?"</string>
@@ -698,6 +699,8 @@
<string name="double_tap_toast" msgid="1068216937244567247">"Савет: Додирните двапут да бисте увећали и умањили приказ."</string>
<!-- no translation found for autofill_this_form (1272247532604569872) -->
<skip />
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<!-- no translation found for autofill_address_name_separator (2504700673286691795) -->
<skip />
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 8ac9273..e5de6ad 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -632,7 +632,8 @@
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. "\n\n"Försök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="4906034376425175381">"Du har angett fel lösenord <xliff:g id="NUMBER_0">%d</xliff:g> gånger. "\n\n"Försök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6827749231465145590">"Du har angett din PIN-kod fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. "\n\n"Försök igen om <xliff:g id="NUMBER_1">%d</xliff:g> sekunder."</string>
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter <xliff:g id="NUMBER_1">%d</xliff:g> försök till kommer du att uppmanas att låsa upp telefonen med din Google-inloggning."\n\n" Försök igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter <xliff:g id="NUMBER_1">%d</xliff:g> försök till kommer du att uppmanas att låsa upp telefonen med din Google-inloggning."\n\n" Försök igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Försök igen om <xliff:g id="NUMBER">%d</xliff:g> sekunder."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Glömt ditt grafiska lösenord?"</string>
@@ -662,6 +663,8 @@
<string name="save_password_label" msgid="6860261758665825069">"Bekräfta"</string>
<string name="double_tap_toast" msgid="1068216937244567247">"Tips! Dubbelklicka om du vill zooma in eller ut."</string>
<!-- outdated translation 8940110866775097494 --> <string name="autofill_this_form" msgid="1272247532604569872">"Autofyll formuläret"</string>
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index ec7df1e..0113275 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -667,7 +667,8 @@
<skip />
<!-- no translation found for lockscreen_too_many_failed_pin_attempts_dialog_message (6827749231465145590) -->
<skip />
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งหากทำไม่สำเร็จอีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกโทรศัพท์โดยใช้การลงชื่อเข้าใช้ Google"\n\n"โปรดลองอีกครั้งในอีก <xliff:g id="NUMBER_2">%d</xliff:g> วินาที"</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งหากทำไม่สำเร็จอีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกโทรศัพท์โดยใช้การลงชื่อเข้าใช้ Google"\n\n"โปรดลองอีกครั้งในอีก <xliff:g id="NUMBER_2">%d</xliff:g> วินาที"</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"ลองใหม่อีกครั้งใน <xliff:g id="NUMBER">%d</xliff:g> วินาที"</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"ลืมรูปแบบหรือ"</string>
@@ -698,6 +699,8 @@
<string name="double_tap_toast" msgid="1068216937244567247">"เคล็ดลับ: แตะสองครั้งเพื่อขยายและย่อ"</string>
<!-- no translation found for autofill_this_form (1272247532604569872) -->
<skip />
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<!-- no translation found for autofill_address_name_separator (2504700673286691795) -->
<skip />
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 12581ed..0e28a1a 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -667,7 +667,8 @@
<skip />
<!-- no translation found for lockscreen_too_many_failed_pin_attempts_dialog_message (6827749231465145590) -->
<skip />
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"Naguhit mo nang mali ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> higit pang hindi matagumpay na pagtatangka, hihingin sa iyong i-unlock ang iyong telepono gamit ang iyong pag-sign-in sa Google."\n\n" Pakisubukang muli sa loob ng <xliff:g id="NUMBER_2">%d</xliff:g> (na) segundo."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"Naguhit mo nang mali ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> higit pang hindi matagumpay na pagtatangka, hihingin sa iyong i-unlock ang iyong telepono gamit ang iyong pag-sign-in sa Google."\n\n" Pakisubukang muli sa loob ng <xliff:g id="NUMBER_2">%d</xliff:g> (na) segundo."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Subukang muli sa loob ng <xliff:g id="NUMBER">%d</xliff:g> (na) segundo."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Nakalimutan ang pattern?"</string>
@@ -698,6 +699,8 @@
<string name="double_tap_toast" msgid="1068216937244567247">"Tip: mag-double-tap upang mag-zoom in at out."</string>
<!-- no translation found for autofill_this_form (1272247532604569872) -->
<skip />
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<!-- no translation found for autofill_address_name_separator (2504700673286691795) -->
<skip />
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 90dd16d..a1abbeb 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -632,7 +632,8 @@
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. "\n\n"Lütfen <xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde yeniden deneyin."</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="4906034376425175381">"Şifrenizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış girdiniz. "\n\n"Lütfen <xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde yeniden deneyin."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6827749231465145590">"PIN\'inizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış girdiniz. "\n\n"Lütfen <xliff:g id="NUMBER_1">%d</xliff:g> saniye içinde yeniden deneyin."</string>
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız denemeden sonra telefonunuzu Google oturum açma bilgilerinizi kullanarak açmanız istenir."\n\n" Lütfen <xliff:g id="NUMBER_2">%d</xliff:g> saniye içinde yeniden deneyin."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız denemeden sonra telefonunuzu Google oturum açma bilgilerinizi kullanarak açmanız istenir."\n\n" Lütfen <xliff:g id="NUMBER_2">%d</xliff:g> saniye içinde yeniden deneyin."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"<xliff:g id="NUMBER">%d</xliff:g> saniye içinde yeniden deneyin."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Deseni unuttunuz mu?"</string>
@@ -662,6 +663,8 @@
<string name="save_password_label" msgid="6860261758665825069">"Onayla"</string>
<string name="double_tap_toast" msgid="1068216937244567247">"İpucu: Yakınlaştırmak ve uzaklaştırmak için iki kez hafifçe vurun."</string>
<!-- outdated translation 8940110866775097494 --> <string name="autofill_this_form" msgid="1272247532604569872">"Bu formu otomatik doldur"</string>
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index a70f082..f9eacb9 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -667,7 +667,8 @@
<skip />
<!-- no translation found for lockscreen_too_many_failed_pin_attempts_dialog_message (6827749231465145590) -->
<skip />
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"Неправильно намал. ключ розблокування стільки разів: <xliff:g id="NUMBER_0">%d</xliff:g>. Ваш телефон потрібно буде розблок-ти за допомогою входу в Google після стількох додатк. неуспішних спроб: <xliff:g id="NUMBER_1">%d</xliff:g>."\n\n" Спробуйте ще через <xliff:g id="NUMBER_2">%d</xliff:g> сек."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"Неправильно намал. ключ розблокування стільки разів: <xliff:g id="NUMBER_0">%d</xliff:g>. Ваш телефон потрібно буде розблок-ти за допомогою входу в Google після стількох додатк. неуспішних спроб: <xliff:g id="NUMBER_1">%d</xliff:g>."\n\n" Спробуйте ще через <xliff:g id="NUMBER_2">%d</xliff:g> сек."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Спробуйте ще через <xliff:g id="NUMBER">%d</xliff:g> сек."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Забули ключ?"</string>
@@ -698,6 +699,8 @@
<string name="double_tap_toast" msgid="1068216937244567247">"Порада: двічі нат. для збіл. або змен."</string>
<!-- no translation found for autofill_this_form (1272247532604569872) -->
<skip />
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<!-- no translation found for autofill_address_name_separator (2504700673286691795) -->
<skip />
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 57d5ea1..e33b7be 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -667,7 +667,8 @@
<skip />
<!-- no translation found for lockscreen_too_many_failed_pin_attempts_dialog_message (6827749231465145590) -->
<skip />
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"Bạn đã vẽ không chính xác hình mở khoá của mình <xliff:g id="NUMBER_0">%d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần thử không thành công khác, bạn sẽ được yêu cầu mở khoá điện thoại bằng thông tin đăng nhập Google của mình."\n\n" Vui lòng thử lại trong <xliff:g id="NUMBER_2">%d</xliff:g> giây."</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"Bạn đã vẽ không chính xác hình mở khoá của mình <xliff:g id="NUMBER_0">%d</xliff:g> lần. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần thử không thành công khác, bạn sẽ được yêu cầu mở khoá điện thoại bằng thông tin đăng nhập Google của mình."\n\n" Vui lòng thử lại trong <xliff:g id="NUMBER_2">%d</xliff:g> giây."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Hãy thử lại sau <xliff:g id="NUMBER">%d</xliff:g> giây."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Đã quên hình?"</string>
@@ -698,6 +699,8 @@
<string name="double_tap_toast" msgid="1068216937244567247">"Mẹo: nhấn đúp để phóng to và thu nhỏ."</string>
<!-- no translation found for autofill_this_form (1272247532604569872) -->
<skip />
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<!-- no translation found for autofill_address_name_separator (2504700673286691795) -->
<skip />
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
diff --git a/core/res/res/values-xlarge/config.xml b/core/res/res/values-xlarge/config.xml
index 8ed1c3e..4c8bbe6 100644
--- a/core/res/res/values-xlarge/config.xml
+++ b/core/res/res/values-xlarge/config.xml
@@ -33,5 +33,8 @@
<!-- see comment in values/config.xml -->
<integer name="config_longPressOnHomeBehavior">0</integer>
+ <!-- see comment in values/config.xml -->
+ <dimen name="config_prefDialogWidth">580dp</dimen>
+
</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 9dc64a4..031d488 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -632,7 +632,8 @@
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次绘错了自己的解锁图案。"\n\n"请在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒后重试。"</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="4906034376425175381">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地输入了密码。"\n\n"请在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒后重试。"</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6827749231465145590">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地输入了 PIN。"\n\n"请在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒后重试。"</string>
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次绘错了自己的解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,系统会要求您使用自己的 Google 登录信息解锁手机。"\n\n"请在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒后重试。"</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次绘错了自己的解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,系统会要求您使用自己的 Google 登录信息解锁手机。"\n\n"请在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒后重试。"</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"<xliff:g id="NUMBER">%d</xliff:g> 秒后重试。"</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"忘记了图案?"</string>
@@ -662,6 +663,8 @@
<string name="save_password_label" msgid="6860261758665825069">"确认"</string>
<string name="double_tap_toast" msgid="1068216937244567247">"提示:点按两次可放大和缩小。"</string>
<!-- outdated translation 8940110866775097494 --> <string name="autofill_this_form" msgid="1272247532604569872">"自动填充此表单"</string>
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 37f9d58..c7cfe8e 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -632,7 +632,8 @@
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"畫出解鎖圖形已錯誤 <xliff:g id="NUMBER_0">%d</xliff:g> 次。"\n\n" 請在 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再嘗試。"</string>
<string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="4906034376425175381">"您已 <xliff:g id="NUMBER_0">%d</xliff:g> 次輸入不正確的密碼。"\n\n"請於 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6827749231465145590">"您已 <xliff:g id="NUMBER_0">%d</xliff:g> 次輸入不正確的 PIN。"\n\n"請於 <xliff:g id="NUMBER_1">%d</xliff:g> 秒後再試一次。"</string>
- <!-- outdated translation 3351013842320127827 --> <string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="8687762517114904651">"畫出解鎖圖形已錯誤 <xliff:g id="NUMBER_0">%d</xliff:g> 次。再錯誤 <xliff:g id="NUMBER_1">%d</xliff:g> 次後,系統會要求使用 Google 登入來解鎖。"\n\n" 請在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒後再試一次。"</string>
+ <!-- no translation found for lockscreen_failed_attempts_almost_glogin (8687762517114904651) -->
+ <skip />
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="3351013842320127827">"畫出解鎖圖形已錯誤 <xliff:g id="NUMBER_0">%d</xliff:g> 次。再錯誤 <xliff:g id="NUMBER_1">%d</xliff:g> 次後,系統會要求使用 Google 登入來解鎖。"\n\n" 請在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒後再試一次。"</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"<xliff:g id="NUMBER">%d</xliff:g> 秒後再試一次。"</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"忘記解鎖圖形?"</string>
@@ -662,6 +663,8 @@
<string name="save_password_label" msgid="6860261758665825069">"確認"</string>
<string name="double_tap_toast" msgid="1068216937244567247">"提示:輕按兩下可放大縮小。"</string>
<!-- outdated translation 8940110866775097494 --> <string name="autofill_this_form" msgid="1272247532604569872">"自動填寫此表單"</string>
+ <!-- no translation found for setup_autofill (8154593408885654044) -->
+ <skip />
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index a8099e3..cc6dc2a 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -503,6 +503,15 @@
<attr name="listPopupWindowStyle" format="reference" />
<!-- Default PopupMenu style. -->
<attr name="popupMenuStyle" format="reference" />
+ <!-- NumberPicker up button style -->
+ <attr name="numberPickerUpButtonStyle" format="reference" />
+ <!-- NumberPicker down button style -->
+ <attr name="numberPickerDownButtonStyle" format="reference" />
+ <!-- NumberPicker input text style -->
+ <attr name="numberPickerInputTextStyle" format="reference" />
+
+ <!-- NumberPicker the fading edge length of the selector wheel -->
+ <attr name="numberPickerStyle" format="reference" />
<!-- =================== -->
<!-- Action bar styles -->
@@ -625,6 +634,10 @@
<!-- Preference frame layout styles. -->
<attr name="preferenceFrameLayoutStyle" format="reference" />
+
+ <!-- Default style for the Switch widget. -->
+ <attr name="switchStyle" format="reference" />
+
</declare-styleable>
<!-- **************************************************************** -->
@@ -1661,6 +1674,42 @@
<!-- Never show over-scroll effects. -->
<enum name="never" value="2" />
</attr>
+
+ <!-- alpha property of the view, as a value between 0 (completely transparent) and 1
+ (completely opaque). -->
+ <attr name="alpha" format="float" />
+
+ <!-- translation in x of the view. This value is added post-layout to the left
+ property of the view, which is set by its layout. -->
+ <attr name="translationX" format="dimension" />
+
+ <!-- translation in y of the view. This value is added post-layout to the left
+ property of the view, which is set by its layout. -->
+ <attr name="translationY" format="dimension" />
+
+ <!-- x location of the pivot point around which the view will rotate and scale.
+ This xml attribute sets the pivotX property of the View. -->
+ <attr name="transformPivotX" format="dimension" />
+
+ <!-- y location of the pivot point around which the view will rotate and scale.
+ This xml attribute sets the pivotY property of the View. -->
+ <attr name="transformPivotY" format="dimension" />
+
+ <!-- rotation of the view, in degrees. -->
+ <attr name="rotation" format="float" />
+
+ <!-- rotation of the view around the x axis, in degrees. -->
+ <attr name="rotationX" format="float" />
+
+ <!-- rotation of the view around the y axis, in degrees. -->
+ <attr name="rotationY" format="float" />
+
+ <!-- scale of the view in the x direction. -->
+ <attr name="scaleX" format="float" />
+
+ <!-- scale of the view in the y direction. -->
+ <attr name="scaleY" format="float" />
+
</declare-styleable>
<!-- Attributes that can be used with a {@link android.view.ViewGroup} or any
@@ -2152,9 +2201,17 @@
</declare-styleable>
<declare-styleable name="PreferenceFrameLayout">
<!-- Padding to use at the top of the prefs content. -->
- <attr name="topPadding" format="dimension" />
+ <attr name="borderTop" format="dimension" />
<!-- Padding to use at the bottom of the prefs content. -->
- <attr name="bottomPadding" format="dimension" />
+ <attr name="borderBottom" format="dimension" />
+ <!-- Padding to use at the left of the prefs content. -->
+ <attr name="borderLeft" format="dimension" />
+ <!-- Padding to use at the right of the prefs content. -->
+ <attr name="borderRight" format="dimension" />
+ </declare-styleable>
+ <declare-styleable name="PreferenceFrameLayout_Layout">
+ <!-- Padding to use at the top of the prefs content. -->
+ <attr name="layout_removeBorders" format="boolean" />
</declare-styleable>
<declare-styleable name="MenuView">
<!-- Default appearance of menu item text. -->
@@ -2856,6 +2913,12 @@
<attr name="minorWeightMax" format="float" />
</declare-styleable>
+ <!-- @hide -->
+ <declare-styleable name="NumberPicker">
+ <attr name="orientation" />
+ <attr name="solidColor" format="color|reference" />
+ </declare-styleable>
+
<!-- ========================= -->
<!-- Drawable class attributes -->
<!-- ========================= -->
@@ -4497,4 +4560,23 @@
<declare-styleable name="ActionBar_LayoutParams">
<attr name="layout_gravity" />
</declare-styleable>
+
+ <declare-styleable name="Switch">
+ <!-- Drawable to use as the "thumb" that switches back and forth. -->
+ <attr name="switchThumb" format="reference" />
+ <!-- Drawable to use as the "track" that the switch thumb slides within. -->
+ <attr name="switchTrack" format="reference" />
+ <!-- Text to use when the switch is in the checked/"on" state. -->
+ <attr name="textOn" />
+ <!-- Text to use when the switch is in the unchecked/"off" state. -->
+ <attr name="textOff" />
+ <!-- Amount of padding on either side of text within the switch thumb. -->
+ <attr name="thumbTextPadding" format="dimension" />
+ <!-- TextAppearance style for text displayed on the switch thumb. -->
+ <attr name="switchTextAppearance" format="reference" />
+ <!-- Minimum width for the switch component -->
+ <attr name="switchMinWidth" format="dimension" />
+ <!-- Minimum space between the switch and caption text -->
+ <attr name="switchPadding" format="dimension" />
+ </declare-styleable>
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 03d581f..e655192 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -76,6 +76,11 @@
be an integer for a constant duration. -->
<fraction name="config_dimBehindFadeDuration">100%</fraction>
+ <!-- The maximum width we would prefer dialogs to be. 0 if there is no
+ maximum (let them grow as large as the screen). Actual values are
+ specified for -large and -xlarge configurations. -->
+ <dimen name="config_prefDialogWidth">0px</dimen>
+
<!-- The duration (in milliseconds) that the radio will scan for a signal
when there's no network connection. If the scan doesn't timeout, use zero -->
<integer name="config_radioScanningTimeout">0</integer>
diff --git a/core/res/res/values/donottranslate.xml b/core/res/res/values/donottranslate.xml
index d6d5dbb..bdcab39 100644
--- a/core/res/res/values/donottranslate.xml
+++ b/core/res/res/values/donottranslate.xml
@@ -24,4 +24,6 @@
<bool name="lockscreen_isPortrait">true</bool>
<!-- @hide DO NOT TRANSLATE. Control aspect ratio of lock pattern -->
<string name="lock_pattern_view_aspect">square</string>
+ <!-- @hide DO NOT TRANSLATE. Separator between the hour and minute elements in a TimePicker widget -->
+ <string name="time_picker_separator">:</string>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index f2ab5cd..e1460e1 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1382,6 +1382,16 @@
<public type="attr" name="baseline" />
<public type="attr" name="homeLayout" />
<public type="attr" name="opacity" />
+ <public type="attr" name="alpha"/>
+ <public type="attr" name="transformPivotX"/>
+ <public type="attr" name="transformPivotY"/>
+ <public type="attr" name="translationX"/>
+ <public type="attr" name="translationY"/>
+ <public type="attr" name="scaleX"/>
+ <public type="attr" name="scaleY"/>
+ <public type="attr" name="rotation"/>
+ <public type="attr" name="rotationX"/>
+ <public type="attr" name="rotationY"/>
<public type="anim" name="animator_fade_in" />
<public type="anim" name="animator_fade_out" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 0c3361d..eafa9b6 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2291,6 +2291,10 @@
<!-- See SMS_DIALOG. This is a button choice to disallow sending the SMSes.. -->
<string name="sms_control_no">Cancel</string>
+ <!-- Date/Time picker dialogs strings -->
+
+ <!-- The title of the time picker dialog. [CHAR LIMIT=NONE] -->
+ <string name="time_picker_dialog_title">Set time</string>
<!-- Name of the button in the date/time picker to accept the date/time change -->
<string name="date_time_set">Set</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 2754e73..f5f392d 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -50,8 +50,10 @@
</style>
<style name="Widget.PreferenceFrameLayout">
- <item name="android:topPadding">0dip</item>
- <item name="android:bottomPadding">0dip</item>
+ <item name="android:borderTop">0dip</item>
+ <item name="android:borderBottom">0dip</item>
+ <item name="android:borderLeft">0dip</item>
+ <item name="android:borderRight">0dip</item>
</style>
<!-- Base style for animations. This style specifies no animations. -->
@@ -460,6 +462,28 @@
<item name="android:background">@android:drawable/btn_default</item>
</style>
+ <style name="Widget.NumberPicker">
+ <item name="android:orientation">vertical</item>
+ <item name="android:fadingEdge">vertical</item>
+ <item name="android:fadingEdgeLength">50dip</item>
+ <item name="android:solidColor">?android:attr/colorBackground</item>
+ </style>
+
+ <style name="Widget.ImageButton.NumberPickerUpButton">
+ <item name="android:background">@android:drawable/timepicker_up_btn</item>
+ </style>
+
+ <style name="Widget.ImageButton.NumberPickerDownButton">
+ <item name="android:background">@android:drawable/timepicker_down_btn</item>
+ </style>
+
+ <style name="Widget.EditText.NumberPickerInputText">
+ <item name="android:textAppearance">@style/TextAppearance.Large.Inverse.NumberPickerInputText</item>
+ <item name="android:gravity">center</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:background">@drawable/timepicker_input</item>
+ </style>
+
<style name="Widget.AutoCompleteTextView" parent="Widget.EditText">
<item name="android:completionHintView">@android:layout/simple_dropdown_hint</item>
<item name="android:completionThreshold">2</item>
@@ -761,7 +785,7 @@
<style name="TextAppearance.Widget.TextView.SpinnerItem">
<item name="android:textColor">@android:color/primary_text_light_disable_only</item>
</style>
-
+
<!-- @hide -->
<style name="TextAppearance.SlidingTabNormal"
parent="@android:attr/textAppearanceMedium">
@@ -804,6 +828,11 @@
<item name="android:textStyle">bold</item>
</style>
+ <style name="TextAppearance.Large.Inverse.NumberPickerInputText">
+ <item name="android:textColor">@android:color/primary_text_light</item>
+ <item name="android:textSize">30sp</item>
+ </style>
+
<!-- Preference Styles -->
<style name="Preference">
@@ -1150,6 +1179,9 @@
<item name="android:textColor">?android:attr/textColorSecondary</item>
</style>
+ <style name="TextAppearance.Holo.Widget.Switch" parent="TextAppearance.Holo.Small">
+ </style>
+
<style name="TextAppearance.Holo.WindowTitle">
<item name="android:textColor">#fff</item>
<item name="android:textSize">14sp</item>
@@ -1326,6 +1358,9 @@
<item name="android:popupBackground">@android:drawable/menu_dropdown_panel_holo_dark</item>
</style>
+ <style name="Widget.Holo.CompoundButton" parent="Widget.CompoundButton">
+ </style>
+
<style name="Widget.Holo.CompoundButton.CheckBox" parent="Widget.CompoundButton.CheckBox">
</style>
@@ -1353,6 +1388,27 @@
<style name="Widget.Holo.ImageButton" parent="Widget.ImageButton">
</style>
+ <style name="Widget.Holo.ImageButton.NumberPickerUpButton">
+ <item name="android:background">@null</item>
+ <item name="android:paddingBottom">26sp</item>
+ <item name="android:src">@android:drawable/timepicker_up_btn_holo_dark</item>
+ </style>
+
+ <style name="Widget.Holo.ImageButton.NumberPickerDownButton">
+ <item name="android:background">@null</item>
+ <item name="android:paddingTop">26sp</item>
+ <item name="android:src">@android:drawable/timepicker_down_btn_holo_dark</item>
+ </style>
+
+ <style name="Widget.Holo.EditText.NumberPickerInputText">
+ <item name="android:paddingTop">13sp</item>
+ <item name="android:paddingBottom">13sp</item>
+ <item name="android:gravity">center</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:textSize">18sp</item>
+ <item name="android:background">@null</item>
+ </style>
+
<style name="Widget.Holo.ImageWell" parent="Widget.ImageWell">
</style>
@@ -1562,6 +1618,17 @@
<item name="android:progressBarPadding">32dip</item>
</style>
+ <style name="Widget.Holo.CompoundButton.Switch">
+ <item name="android:switchTrack">@android:drawable/switch_track_holo_dark</item>
+ <item name="android:switchThumb">@android:drawable/switch_inner_holo_dark</item>
+ <item name="android:switchTextAppearance">@android:style/TextAppearance.Holo.Widget.Switch</item>
+ <item name="android:textOn">@android:string/capital_on</item>
+ <item name="android:textOff">@android:string/capital_off</item>
+ <item name="android:thumbTextPadding">12dip</item>
+ <item name="android:switchMinWidth">96dip</item>
+ <item name="android:switchPadding">16dip</item>
+ </style>
+
<!-- Light widget styles -->
<style name="Widget.Holo.Light">
@@ -1655,6 +1722,17 @@
<style name="Widget.Holo.Light.ImageButton" parent="Widget.ImageButton">
</style>
+ <style name="Widget.Holo.Light.ImageButton.NumberPickerUpButton" parent="Widget.Holo.Light.ImageButton.NumberPickerUpButton">
+ <item name="android:background">@android:drawable/timepicker_up_btn_holo_light</item>
+ </style>
+
+ <style name="Widget.Holo.Light.ImageButton.NumberPickerDownButton" parent="Widget.Holo.ImageButton.NumberPickerDownButton">
+ <item name="android:background">@android:drawable/timepicker_down_btn_holo_light</item>
+ </style>
+
+ <style name="Widget.Holo.Light.EditText.NumberPickerInputText" parent="Widget.Holo.EditText.NumberPickerInputText">
+ </style>
+
<style name="Widget.Holo.Light.ImageWell" parent="Widget.ImageWell">
</style>
@@ -1886,7 +1964,9 @@
</style>
<style name="Widget.Holo.PreferenceFrameLayout">
- <item name="android:topPadding">48dip</item>
- <item name="android:bottomPadding">48dip</item>
+ <item name="android:borderTop">48dip</item>
+ <item name="android:borderBottom">48dip</item>
+ <item name="android:borderLeft">32dip</item>
+ <item name="android:borderRight">32dip</item>
</style>
</resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 0eec0df..e1040d9 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -267,8 +267,16 @@
<item name="searchViewGoIcon">@android:drawable/ic_go</item>
<item name="searchViewVoiceIcon">@android:drawable/ic_voice_search</item>
+
<!-- PreferenceFrameLayout attributes -->
<item name="preferenceFrameLayoutStyle">@android:style/Widget.PreferenceFrameLayout</item>
+
+ <!-- NumberPicker styles-->
+ <item name="numberPickerUpButtonStyle">@style/Widget.ImageButton.NumberPickerUpButton</item>
+ <item name="numberPickerDownButtonStyle">@style/Widget.ImageButton.NumberPickerDownButton</item>
+ <item name="numberPickerInputTextStyle">@style/Widget.EditText.NumberPickerInputText</item>
+ <item name="numberPickerStyle">@style/Widget.NumberPicker</item>
+
</style>
<!-- Variant of the default (dark) theme with no title bar -->
@@ -711,6 +719,7 @@
<item name="buttonStyleInset">@android:style/Widget.Holo.Button.Inset</item>
<item name="buttonStyleToggle">@android:style/Widget.Holo.Button.Toggle</item>
+ <item name="switchStyle">@android:style/Widget.Holo.CompoundButton.Switch</item>
<item name="groupButtonBackground">@android:drawable/group_button_background_holo_dark</item>
<item name="selectableItemBackground">@android:drawable/item_background_holo_dark</item>
@@ -881,6 +890,12 @@
<!-- PreferenceFrameLayout attributes -->
<item name="preferenceFrameLayoutStyle">@android:style/Widget.Holo.PreferenceFrameLayout</item>
+
+ <!-- NumberPicker styles-->
+ <item name="numberPickerUpButtonStyle">@style/Widget.Holo.ImageButton.NumberPickerUpButton</item>
+ <item name="numberPickerDownButtonStyle">@style/Widget.Holo.ImageButton.NumberPickerDownButton</item>
+ <item name="numberPickerInputTextStyle">@style/Widget.Holo.EditText.NumberPickerInputText</item>
+
</style>
<!-- New Honeycomb holographic theme. Light version. The widgets in the
@@ -1117,6 +1132,12 @@
<!-- SearchView attributes -->
<item name="searchDropdownBackground">@android:drawable/search_dropdown_light</item>
+
+ <!-- NumberPicker attributes and styles-->
+ <item name="numberPickerUpButtonStyle">@style/Widget.Holo.Light.ImageButton.NumberPickerUpButton</item>
+ <item name="numberPickerDownButtonStyle">@style/Widget.Holo.Light.ImageButton.NumberPickerDownButton</item>
+ <item name="numberPickerInputTextStyle">@style/Widget.Holo.Light.EditText.NumberPickerInputText</item>
+
</style>
<!-- Development legacy name; if you're using this, switch. -->
diff --git a/data/keyboards/Apple_Wireless_Keyboard.kl b/data/keyboards/Apple_Wireless_Keyboard.kl
new file mode 100644
index 0000000..5234d58
--- /dev/null
+++ b/data/keyboards/Apple_Wireless_Keyboard.kl
@@ -0,0 +1,119 @@
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Apple Wireless Keyboard
+#
+# Notes:
+# - Keys such as PAGE_UP and FORWARD_DEL are produced using the
+# function key.
+# - Special function keys for brightness control, etc. are not
+# implemented here.
+
+key 1 ESCAPE
+key 2 1
+key 3 2
+key 4 3
+key 5 4
+key 6 5
+key 7 6
+key 8 7
+key 9 8
+key 10 9
+key 11 0
+key 12 MINUS
+key 13 EQUALS
+key 14 DEL
+key 15 TAB
+key 16 Q
+key 17 W
+key 18 E
+key 19 R
+key 20 T
+key 21 Y
+key 22 U
+key 23 I
+key 24 O
+key 25 P
+key 26 LEFT_BRACKET
+key 27 RIGHT_BRACKET
+key 28 ENTER
+key 29 CTRL_LEFT
+key 30 A
+key 31 S
+key 32 D
+key 33 F
+key 34 G
+key 35 H
+key 36 J
+key 37 K
+key 38 L
+key 39 SEMICOLON
+key 40 APOSTROPHE
+key 41 GRAVE
+key 42 SHIFT_LEFT
+key 43 BACKSLASH
+key 44 Z
+key 45 X
+key 46 C
+key 47 V
+key 48 B
+key 49 N
+key 50 M
+key 51 COMMA
+key 52 PERIOD
+key 53 SLASH
+key 54 SHIFT_RIGHT
+key 56 ALT_LEFT
+key 57 SPACE
+key 58 CAPS_LOCK
+key 59 F1
+key 60 F2
+key 61 F3
+key 62 F4
+key 63 F5
+key 64 F6
+key 65 F7
+key 66 F8
+key 67 F9
+key 68 F10
+key 87 F11
+key 88 F12
+key 100 ALT_RIGHT
+key 102 MOVE_HOME
+key 103 DPAD_UP
+key 104 PAGE_UP
+key 105 DPAD_LEFT
+key 106 DPAD_RIGHT
+key 107 MOVE_END
+key 108 DPAD_DOWN
+key 109 PAGE_DOWN
+key 110 NUMPAD_ENTER
+key 111 FORWARD_DEL
+key 113 VOLUME_MUTE
+key 114 VOLUME_DOWN
+key 115 VOLUME_UP
+# key 120 switch applications
+key 125 META_LEFT
+key 126 META_RIGHT
+key 161 MEDIA_EJECT
+key 163 MEDIA_NEXT
+key 164 MEDIA_PLAY_PAUSE
+key 165 MEDIA_PREVIOUS
+# key 204 show gadgets
+# key 224 reduce brightness
+# key 225 increase brightness
+# key 229 blank special function on F5
+# key 230 blank special function on F6
+key 464 FUNCTION
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index e98000d..1ee121e 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -175,7 +175,7 @@ key 150 EXPLORER
# key 153 "KEY_DIRECTION"
# key 154 "KEY_CYCLEWINDOWS"
key 155 ENVELOPE
-# key 156 "KEY_BOOKMARKS"
+key 156 BOOKMARK
# key 157 "KEY_COMPUTER"
key 158 BACK WAKE_DROPPED
key 159 FORWARD
@@ -289,11 +289,11 @@ key 318 BUTTON_THUMBR
# key 359 "KEY_TIME"
# key 360 "KEY_VENDOR"
# key 361 "KEY_ARCHIVE"
-# key 362 "KEY_PROGRAM"
+key 362 GUIDE
# key 363 "KEY_CHANNEL"
# key 364 "KEY_FAVORITES"
# key 365 "KEY_EPG"
-# key 366 "KEY_PVR"
+key 366 DVR
# key 367 "KEY_MHP"
# key 368 "KEY_LANGUAGE"
# key 369 "KEY_TITLE"
@@ -304,7 +304,7 @@ key 318 BUTTON_THUMBR
# key 374 "KEY_KEYBOARD"
# key 375 "KEY_SCREEN"
# key 376 "KEY_PC"
-# key 377 "KEY_TV"
+key 377 TV
# key 378 "KEY_TV2"
# key 379 "KEY_VCR"
# key 380 "KEY_VCR2"
@@ -329,8 +329,8 @@ key 318 BUTTON_THUMBR
# key 399 "KEY_GREEN"
# key 400 "KEY_YELLOW"
# key 401 "KEY_BLUE"
-# key 402 "KEY_CHANNELUP"
-# key 403 "KEY_CHANNELDOWN"
+key 402 CHANNEL_UP
+key 403 CHANNEL_DOWN
# key 404 "KEY_FIRST"
# key 405 "KEY_LAST"
# key 406 "KEY_AB"
diff --git a/data/keyboards/Logitech_USB_Receiver.kl b/data/keyboards/Logitech_USB_Receiver.kl
new file mode 100644
index 0000000..aa7c0ee
--- /dev/null
+++ b/data/keyboards/Logitech_USB_Receiver.kl
@@ -0,0 +1,133 @@
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Logitech Revue keyboard
+#
+# Notes:
+# - The GRAVE key is emulated by the keyboard.
+# ALT + LEFT_BRACKET produces GRAVE.
+# ALT + RIGHT_BRACKET produces SHIFT + GRAVE.
+# - FORWARD_DEL is produced by fn + BACKSPACE
+# - PAGE_UP / PAGE_DOWN is produced by fn + CHANNEL_UP / CHANNEL_DOWN
+# - The AVR / STB / TV power and input buttons seem to be non-functional
+# as well as several of the other fn buttons and the PIP button?
+
+key 1 ESCAPE
+key 2 1
+key 3 2
+key 4 3
+key 5 4
+key 6 5
+key 7 6
+key 8 7
+key 9 8
+key 10 9
+key 11 0
+key 12 MINUS
+key 13 EQUALS
+key 14 DEL
+key 15 TAB
+key 16 Q
+key 17 W
+key 18 E
+key 19 R
+key 20 T
+key 21 Y
+key 22 U
+key 23 I
+key 24 O
+key 25 P
+key 26 LEFT_BRACKET
+key 27 RIGHT_BRACKET
+key 28 ENTER
+key 29 CTRL_LEFT
+key 30 A
+key 31 S
+key 32 D
+key 33 F
+key 34 G
+key 35 H
+key 36 J
+key 37 K
+key 38 L
+key 39 SEMICOLON
+key 40 APOSTROPHE
+key 41 GRAVE
+key 42 SHIFT_LEFT
+key 43 BACKSLASH
+key 44 Z
+key 45 X
+key 46 C
+key 47 V
+key 48 B
+key 49 N
+key 50 M
+key 51 COMMA
+key 52 PERIOD
+key 53 SLASH
+key 54 SHIFT_RIGHT
+key 56 ALT_RIGHT
+key 57 SPACE
+key 58 CAPS_LOCK
+key 59 F1
+key 60 F2
+key 61 F3
+key 62 F4
+key 63 F5
+key 64 F6
+key 65 F7
+key 66 F8
+key 67 F9
+key 68 F10
+key 87 F11
+key 88 F12
+key 96 DPAD_CENTER
+key 97 CTRL_RIGHT
+key 102 MOVE_HOME
+key 103 DPAD_UP
+key 104 PAGE_UP
+key 105 DPAD_LEFT
+key 106 DPAD_RIGHT
+key 107 MOVE_END
+key 108 DPAD_DOWN
+key 109 PAGE_DOWN
+key 110 NUMPAD_ENTER
+key 111 FORWARD_DEL
+key 113 VOLUME_MUTE
+key 114 VOLUME_DOWN
+key 115 VOLUME_UP
+key 119 MEDIA_PAUSE
+key 125 SEARCH
+key 127 MENU
+key 156 BOOKMARK
+key 158 BACK
+key 163 MEDIA_NEXT
+key 165 MEDIA_PREVIOUS
+key 166 MEDIA_STOP
+key 167 MEDIA_RECORD
+key 168 MEDIA_REWIND
+key 172 HOME
+key 207 MEDIA_PLAY
+key 208 MEDIA_FAST_FORWARD
+# key 288 left mouse button
+# key 289 right mouse button (fn + button)
+key 362 GUIDE
+key 366 DVR
+key 377 TV
+key 402 CHANNEL_UP
+key 403 CHANNEL_DOWN
+key 418 ZOOM_IN
+key 419 ZOOM_OUT
+
diff --git a/data/keyboards/Motorola_Bluetooth_Wireless_Keyboard.kcm b/data/keyboards/Motorola_Bluetooth_Wireless_Keyboard.kcm
deleted file mode 100644
index 73a04d0..0000000
--- a/data/keyboards/Motorola_Bluetooth_Wireless_Keyboard.kcm
+++ /dev/null
@@ -1,370 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-#
-# Generic key character map for full alphabetic US English PC style external keyboards.
-#
-# This file is intentionally very generic and is intended to support a broad rang of keyboards.
-# Do not edit the generic key character map to support a specific keyboard; instead, create
-# a new key character map file with the required keyboard configuration.
-#
-
-type FULL
-
-key A {
- label: 'A'
- base: 'a'
- shift, capslock: 'A'
- ctrl, alt, meta: none
-}
-
-key B {
- label: 'B'
- base: 'b'
- shift, capslock: 'B'
- ctrl, alt, meta: none
-}
-
-key C {
- label: 'C'
- base: 'c'
- shift, capslock: 'C'
- ctrl, alt, meta: none
-}
-
-key D {
- label: 'D'
- base: 'd'
- shift, capslock: 'D'
- ctrl, alt, meta: none
-}
-
-key E {
- label: 'E'
- base: 'e'
- shift, capslock: 'E'
- ctrl, alt, meta: none
-}
-
-key F {
- label: 'F'
- base: 'f'
- shift, capslock: 'F'
- ctrl, alt, meta: none
-}
-
-key G {
- label: 'G'
- base: 'g'
- shift, capslock: 'G'
- ctrl, alt, meta: none
-}
-
-key H {
- label: 'H'
- base: 'h'
- shift, capslock: 'H'
- ctrl, alt, meta: none
-}
-
-key I {
- label: 'I'
- base: 'i'
- shift, capslock: 'I'
- ctrl, alt, meta: none
-}
-
-key J {
- label: 'J'
- base: 'j'
- shift, capslock: 'J'
- ctrl, alt, meta: none
-}
-
-key K {
- label: 'K'
- base: 'k'
- shift, capslock: 'K'
- ctrl, alt, meta: none
-}
-
-key L {
- label: 'L'
- base: 'l'
- shift, capslock: 'L'
- ctrl, alt, meta: none
-}
-
-key M {
- label: 'M'
- base: 'm'
- shift, capslock: 'M'
- ctrl, alt, meta: none
-}
-
-key N {
- label: 'N'
- base: 'n'
- shift, capslock: 'N'
- ctrl, alt, meta: none
-}
-
-key O {
- label: 'O'
- base: 'o'
- shift, capslock: 'O'
- ctrl, alt, meta: none
-}
-
-key P {
- label: 'P'
- base: 'p'
- shift, capslock: 'P'
- ctrl, alt, meta: none
-}
-
-key Q {
- label: 'Q'
- base: 'q'
- shift, capslock: 'Q'
- ctrl, alt, meta: none
-}
-
-key R {
- label: 'R'
- base: 'r'
- shift, capslock: 'R'
- ctrl, alt, meta: none
-}
-
-key S {
- label: 'S'
- base: 's'
- shift, capslock: 'S'
- ctrl, alt, meta: none
-}
-
-key T {
- label: 'T'
- base: 't'
- shift, capslock: 'T'
- ctrl, alt, meta: none
-}
-
-key U {
- label: 'U'
- base: 'u'
- shift, capslock: 'U'
- ctrl, alt, meta: none
-}
-
-key V {
- label: 'V'
- base: 'v'
- shift, capslock: 'V'
- ctrl, alt, meta: none
-}
-
-key W {
- label: 'W'
- base: 'w'
- shift, capslock: 'W'
- ctrl, alt, meta: none
-}
-
-key X {
- label: 'X'
- base: 'x'
- shift, capslock: 'X'
- ctrl, alt, meta: none
-}
-
-key Y {
- label: 'Y'
- base: 'y'
- shift, capslock: 'Y'
- ctrl, alt, meta: none
-}
-
-key Z {
- label: 'Z'
- base: 'z'
- shift, capslock: 'Z'
- ctrl, alt, meta: none
-}
-
-key 0 {
- label, number: '0'
- base: '0'
- shift: ')'
- ctrl, alt, meta: none
-}
-
-key 1 {
- label, number: '1'
- base: '1'
- shift: '!'
- ctrl, alt, meta: none
-}
-
-key 2 {
- label, number: '2'
- base: '2'
- shift: '@'
- ctrl, alt, meta: none
-}
-
-key 3 {
- label, number: '3'
- base: '3'
- shift: '#'
- ctrl, alt, meta: none
-}
-
-key 4 {
- label, number: '4'
- base: '4'
- shift: '$'
- ctrl, alt, meta: none
-}
-
-key 5 {
- label, number: '5'
- base: '5'
- shift: '%'
- ctrl, alt, meta: none
-}
-
-key 6 {
- label, number: '6'
- base: '6'
- shift: '^'
- ctrl, alt, meta: none
-}
-
-key 7 {
- label, number: '7'
- base: '7'
- shift: '&'
- ctrl, alt, meta: none
-}
-
-key 8 {
- label, number: '8'
- base: '8'
- shift: '*'
- ctrl, alt, meta: none
-}
-
-key 9 {
- label, number: '9'
- base: '9'
- shift: '('
- ctrl, alt, meta: none
-}
-
-key SPACE {
- label: ' '
- base: ' '
- ctrl, alt, meta: none
-}
-
-key ENTER {
- label: '\n'
- base: '\n'
- ctrl, alt, meta: none
-}
-
-key TAB {
- label: '\t'
- base: '\t'
- ctrl, alt, meta: none
-}
-
-key COMMA {
- label, number: ','
- base: ','
- shift: '<'
- ctrl, alt, meta: none
-}
-
-key PERIOD {
- label, number: '.'
- base: '.'
- shift: '>'
- ctrl, alt, meta: none
-}
-
-key SLASH {
- label, number: '/'
- base: '/'
- shift: '?'
- ctrl, alt, meta: none
-}
-
-key GRAVE {
- label, number: '`'
- base: '`'
- shift: '~'
- ctrl, alt, meta: none
-}
-
-key MINUS {
- label, number: '-'
- base: '-'
- shift: '_'
- ctrl, alt, meta: none
-}
-
-key EQUALS {
- label, number: '='
- base: '='
- shift: '+'
- ctrl, alt, meta: none
-}
-
-key LEFT_BRACKET {
- label, number: '['
- base: '['
- shift: '{'
- ctrl, alt, meta: none
-}
-
-key RIGHT_BRACKET {
- label, number: ']'
- base: ']'
- shift: '}'
- ctrl, alt, meta: none
-}
-
-key BACKSLASH {
- label, number: '\\'
- base: '\\'
- shift: '|'
- ctrl, alt, meta: none
-}
-
-key SEMICOLON {
- label, number: ';'
- base: ';'
- shift: ':'
- ctrl, alt, meta: none
-}
-
-key APOSTROPHE {
- label, number: '\''
- base: '\''
- shift: '"'
- ctrl, alt, meta: none
-}
diff --git a/data/keyboards/Motorola_Bluetooth_Wireless_Keyboard.kl b/data/keyboards/Motorola_Bluetooth_Wireless_Keyboard.kl
index eab78a0..87b3c32 100644
--- a/data/keyboards/Motorola_Bluetooth_Wireless_Keyboard.kl
+++ b/data/keyboards/Motorola_Bluetooth_Wireless_Keyboard.kl
@@ -66,6 +66,7 @@ key 51 COMMA
key 52 PERIOD
key 53 SLASH
key 54 SHIFT_RIGHT
+key 56 ALT_LEFT
key 57 SPACE
key 58 CAPS_LOCK
key 59 F1
@@ -77,6 +78,9 @@ key 64 F6
key 65 F7
key 66 F8
key 67 F9
+key 68 F10
+key 87 F11
+key 88 F12
key 97 CTRL_RIGHT
key 102 HOME
key 103 DPAD_UP
@@ -84,7 +88,6 @@ key 105 DPAD_LEFT
key 106 DPAD_RIGHT
key 107 MOVE_END
key 108 DPAD_DOWN
-key 110 INSERT
key 111 FORWARD_DEL
key 113 VOLUME_MUTE
key 114 VOLUME_DOWN
@@ -95,3 +98,4 @@ key 163 MEDIA_NEXT
key 164 MEDIA_PLAY_PAUSE
key 165 MEDIA_PREVIOUS
key 166 MEDIA_STOP
+# key 226 tbd reserved key
diff --git a/data/keyboards/common.mk b/data/keyboards/common.mk
index 3f05edb..5c2a75d 100644
--- a/data/keyboards/common.mk
+++ b/data/keyboards/common.mk
@@ -16,15 +16,16 @@
# Used by Android.mk and keyboards.mk.
keylayouts := \
+ Apple_Wireless_Keyboard.kl \
AVRCP.kl \
Generic.kl \
+ Logitech_USB_Receiver.kl \
Motorola_Bluetooth_Wireless_Keyboard.kl \
qwerty.kl \
qwerty2.kl
keycharmaps := \
Generic.kcm \
- Virtual.kcm \
- Motorola_Bluetooth_Wireless_Keyboard.kcm \
qwerty.kcm \
- qwerty2.kcm
+ qwerty2.kcm \
+ Virtual.kcm
diff --git a/data/keyboards/qwerty.kcm b/data/keyboards/qwerty.kcm
index f31333e..f3e1524 100644
--- a/data/keyboards/qwerty.kcm
+++ b/data/keyboards/qwerty.kcm
@@ -259,9 +259,9 @@ key COMMA {
label: ','
number: ','
base: ','
- shift, capslock: ';'
+ shift: ';'
alt: ';'
- shift+alt, capslock+alt: '|'
+ shift+alt: '|'
}
key PERIOD {
diff --git a/data/sounds/notifications/alert01.ogg b/data/sounds/notifications/alert01.ogg
new file mode 100644
index 0000000..310424a
--- /dev/null
+++ b/data/sounds/notifications/alert01.ogg
Binary files differ
diff --git a/data/sounds/notifications/alert02.ogg b/data/sounds/notifications/alert02.ogg
new file mode 100644
index 0000000..6c6d5c7
--- /dev/null
+++ b/data/sounds/notifications/alert02.ogg
Binary files differ
diff --git a/data/sounds/notifications/alert03.ogg b/data/sounds/notifications/alert03.ogg
new file mode 100644
index 0000000..cd8811f
--- /dev/null
+++ b/data/sounds/notifications/alert03.ogg
Binary files differ
diff --git a/data/sounds/notifications/alert04.ogg b/data/sounds/notifications/alert04.ogg
new file mode 100644
index 0000000..3cdb0b1
--- /dev/null
+++ b/data/sounds/notifications/alert04.ogg
Binary files differ
diff --git a/data/sounds/notifications/alert05.ogg b/data/sounds/notifications/alert05.ogg
new file mode 100644
index 0000000..2022cc3
--- /dev/null
+++ b/data/sounds/notifications/alert05.ogg
Binary files differ
diff --git a/data/sounds/notifications/alert06.ogg b/data/sounds/notifications/alert06.ogg
new file mode 100644
index 0000000..8da9420
--- /dev/null
+++ b/data/sounds/notifications/alert06.ogg
Binary files differ
diff --git a/data/sounds/notifications/alert07.ogg b/data/sounds/notifications/alert07.ogg
new file mode 100644
index 0000000..1bb6370
--- /dev/null
+++ b/data/sounds/notifications/alert07.ogg
Binary files differ
diff --git a/data/sounds/notifications/alert08.ogg b/data/sounds/notifications/alert08.ogg
new file mode 100644
index 0000000..7ebd4aa
--- /dev/null
+++ b/data/sounds/notifications/alert08.ogg
Binary files differ
diff --git a/data/sounds/notifications/alert09.ogg b/data/sounds/notifications/alert09.ogg
new file mode 100644
index 0000000..dcf9c2b
--- /dev/null
+++ b/data/sounds/notifications/alert09.ogg
Binary files differ
diff --git a/data/sounds/notifications/alert10.ogg b/data/sounds/notifications/alert10.ogg
new file mode 100644
index 0000000..9960ad7
--- /dev/null
+++ b/data/sounds/notifications/alert10.ogg
Binary files differ
diff --git a/data/sounds/notifications/alert11.ogg b/data/sounds/notifications/alert11.ogg
new file mode 100644
index 0000000..0b907e1
--- /dev/null
+++ b/data/sounds/notifications/alert11.ogg
Binary files differ
diff --git a/data/sounds/notifications/alert12.ogg b/data/sounds/notifications/alert12.ogg
new file mode 100644
index 0000000..2ebadec
--- /dev/null
+++ b/data/sounds/notifications/alert12.ogg
Binary files differ
diff --git a/data/sounds/notifications/alert13.ogg b/data/sounds/notifications/alert13.ogg
new file mode 100644
index 0000000..6acc2df
--- /dev/null
+++ b/data/sounds/notifications/alert13.ogg
Binary files differ
diff --git a/data/sounds/notifications/alert14.ogg b/data/sounds/notifications/alert14.ogg
new file mode 100644
index 0000000..a34a1f0
--- /dev/null
+++ b/data/sounds/notifications/alert14.ogg
Binary files differ
diff --git a/data/sounds/notifications/alert15.ogg b/data/sounds/notifications/alert15.ogg
new file mode 100644
index 0000000..108aa45
--- /dev/null
+++ b/data/sounds/notifications/alert15.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ringtone18.ogg b/data/sounds/ringtones/ringtone18.ogg
new file mode 100644
index 0000000..00cd28f
--- /dev/null
+++ b/data/sounds/ringtones/ringtone18.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ringtone19.ogg b/data/sounds/ringtones/ringtone19.ogg
new file mode 100644
index 0000000..02acaa7
--- /dev/null
+++ b/data/sounds/ringtones/ringtone19.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ringtone20.ogg b/data/sounds/ringtones/ringtone20.ogg
new file mode 100644
index 0000000..e6d1051
--- /dev/null
+++ b/data/sounds/ringtones/ringtone20.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ringtone21.ogg b/data/sounds/ringtones/ringtone21.ogg
new file mode 100644
index 0000000..f8ef541
--- /dev/null
+++ b/data/sounds/ringtones/ringtone21.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ringtone22.ogg b/data/sounds/ringtones/ringtone22.ogg
new file mode 100644
index 0000000..cd349f5
--- /dev/null
+++ b/data/sounds/ringtones/ringtone22.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ringtone23.ogg b/data/sounds/ringtones/ringtone23.ogg
new file mode 100644
index 0000000..3b4f000
--- /dev/null
+++ b/data/sounds/ringtones/ringtone23.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ringtone24.ogg b/data/sounds/ringtones/ringtone24.ogg
new file mode 100644
index 0000000..e1c5c3b
--- /dev/null
+++ b/data/sounds/ringtones/ringtone24.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ringtone25.ogg b/data/sounds/ringtones/ringtone25.ogg
new file mode 100644
index 0000000..0f66463
--- /dev/null
+++ b/data/sounds/ringtones/ringtone25.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ringtone26.ogg b/data/sounds/ringtones/ringtone26.ogg
new file mode 100644
index 0000000..8cd4648
--- /dev/null
+++ b/data/sounds/ringtones/ringtone26.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ringtone27.ogg b/data/sounds/ringtones/ringtone27.ogg
new file mode 100644
index 0000000..9671d6e
--- /dev/null
+++ b/data/sounds/ringtones/ringtone27.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ringtone28.ogg b/data/sounds/ringtones/ringtone28.ogg
new file mode 100644
index 0000000..6139667
--- /dev/null
+++ b/data/sounds/ringtones/ringtone28.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ringtone29.ogg b/data/sounds/ringtones/ringtone29.ogg
new file mode 100644
index 0000000..042c82a
--- /dev/null
+++ b/data/sounds/ringtones/ringtone29.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ringtone30.ogg b/data/sounds/ringtones/ringtone30.ogg
new file mode 100644
index 0000000..eec8ebc
--- /dev/null
+++ b/data/sounds/ringtones/ringtone30.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ringtone31.ogg b/data/sounds/ringtones/ringtone31.ogg
new file mode 100644
index 0000000..0140a80
--- /dev/null
+++ b/data/sounds/ringtones/ringtone31.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ringtone32.ogg b/data/sounds/ringtones/ringtone32.ogg
new file mode 100644
index 0000000..4e12f5a
--- /dev/null
+++ b/data/sounds/ringtones/ringtone32.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ringtone33.ogg b/data/sounds/ringtones/ringtone33.ogg
new file mode 100644
index 0000000..1342066
--- /dev/null
+++ b/data/sounds/ringtones/ringtone33.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ringtone34.ogg b/data/sounds/ringtones/ringtone34.ogg
new file mode 100644
index 0000000..a16737b
--- /dev/null
+++ b/data/sounds/ringtones/ringtone34.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ringtone35.ogg b/data/sounds/ringtones/ringtone35.ogg
new file mode 100644
index 0000000..3407857
--- /dev/null
+++ b/data/sounds/ringtones/ringtone35.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ringtone36.ogg b/data/sounds/ringtones/ringtone36.ogg
new file mode 100644
index 0000000..bbd5263
--- /dev/null
+++ b/data/sounds/ringtones/ringtone36.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ringtone37.ogg b/data/sounds/ringtones/ringtone37.ogg
new file mode 100644
index 0000000..ae7b57e
--- /dev/null
+++ b/data/sounds/ringtones/ringtone37.ogg
Binary files differ
diff --git a/data/sounds/ringtones/ringtone38.ogg b/data/sounds/ringtones/ringtone38.ogg
new file mode 100644
index 0000000..fae20cd
--- /dev/null
+++ b/data/sounds/ringtones/ringtone38.ogg
Binary files differ
diff --git a/docs/html/guide/topics/ui/actionbar.jd b/docs/html/guide/topics/ui/actionbar.jd
index 2b942e7..c3d3482 100644
--- a/docs/html/guide/topics/ui/actionbar.jd
+++ b/docs/html/guide/topics/ui/actionbar.jd
@@ -8,9 +8,10 @@ parent.link=index.html
<h2>Quickview</h2>
<ul>
- <li>A replacement for the title bar for displaying global actions for the activity</li>
- <li>Provides toolbar actions and modes of navigating around the application</li>
- <li>Switches to contextual menu options when one or more items are selected</li>
+ <li>A replacement for the title bar that includes the application icon and activity title</li>
+ <li>Provides action items from the Options Menu and modes of navigating around the
+application</li>
+ <li>Supports custom views, including an embedded search box</li>
<li>Requires API Level HONEYCOMB</li>
</ul>
@@ -22,9 +23,9 @@ parent.link=index.html
<li><a href="#Home">Using the application icon as an action item</a></li>
</ol>
</li>
+ <li><a href="#ActionView">Adding an Action View</a></li>
<li><a href="#Tabs">Adding Tabs</a></li>
<li><a href="#Dropdown">Adding Drop-down Navigation</a></li>
- <li><a href="#Search">Adding Search</a></li>
</ol>
<h2>Key classes</h2>
@@ -40,62 +41,88 @@ parent.link=index.html
</div>
</div>
-<p>The action bar is a widget for activities that replaces the traditional title bar at
-the top of an activity. By default, the action bar includes the application logo on the left side,
-followed by the activity title. The action bar offers several useful features for
-applications&mdash;especially those targeted to tablet devices. The action bar features include
+<p>The Action Bar is a widget for activities that replaces the traditional title bar at
+the top of an activity. By default, the Action Bar includes the application logo on the left side,
+followed by the activity title. The Action Bar offers several useful features for
+applications&mdash;especially those targeted to tablet devices. The Action Bar features include
the ability to:</p>
<ul>
- <li>Display menu items from the <a
-href="{@docRoot}guide/topics/ui/menus.html#OptionsMenu">options menu</a> as "action
-items"&mdash;providing instant access to key user actions.</li>
+ <li>Display items from the <a
+href="{@docRoot}guide/topics/ui/menus.html#OptionsMenu">Options Menu</a> as "action
+items"&mdash;providing instant access to key user actions. (Menu items not appearing as action
+items are placed in the Overflow Menu, revealed by a drop-down in the Action Bar.)</li>
<li>Provide tabs for navigating between <a
href="{@docRoot}guide/topics/fragments/index.html">fragments</a>.</li>
<li>Provide drop-down navigation items.</li>
- <li>Embed a {@link android.widget.SearchView} for instant searching.</li>
+ <li>Provide interactive "action views" in place of action items.</li>
<li>Use the application logo as a "return home" or "up" navigation action.</li>
</ul>
<img src="{@docRoot}images/ui/actionbar.png" height="36" alt="" />
-<p class="img-caption"><strong>Figure 1.</strong> A screenshot of the action bar in the NotePad
+<p class="img-caption"><strong>Figure 1.</strong> A screenshot of the Action Bar in the NotePad
sample application, containing action items to save and delete the note.</p>
<h2 id="Adding">Adding the Action Bar</h2>
-<p>To add the Action Bar to your activity, apply the holographic theme&mdash;{@code
-Theme.Holo}&mdash;or the action bar theme&mdash;{@code Theme.WithActionBar}&mdash;in your manifest
-file. For example:</p>
+<p>To add the Action Bar to your activities, simply target your application for HONEYCOMB or later,
+using the <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html">{@code
+&lt;uses-sdk&gt;}</a> element. That is, by setting either the {@code android:minSdkVersion} or
+{@code android:targetSdkVersion} to HONEYCOMB or later, each activity in your application will
+include the Action Bar when running on devices with HONEYCOMB or later. For example:</p>
<pre>
-&lt;activity android:theme="@android:style/Theme.Holo" &gt;
+&lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.helloworld"
+ android:versionCode="1"
+ android:versionName="1.0"&gt;
+ <b>&lt;uses-sdk android:minSdkVersion="Froyo" /&gt;</b>
+ &lt;application ... &gt;
+ ...
+ &lt;/application&gt;
+&lt;/manifest&gt;
</pre>
-<p>The activity now appears with the action bar in place of the traditional title bar.</p>
+<p>This also enables the "Holographic" theme for all your activities, which is the new default
+application theme for HONEYCOMB and later.</p>
+
+<p class="note"><strong>Note:</strong> In order for the Holographic theme to be applied based on
+the target platform version, the <a
+href="{@docRoot}guide/topics/manifest/uses-sdk-element.html">{@code &lt;uses-sdk&gt;}</a>
+element must appear <em>before</em> the <a
+href="{@docRoot}guide/topics/manifest/application-element.html">{@code &lt;application&gt;}</a>
+element.</p>
+
+<h3>Hide the Action Bar</h3>
+
+<p>If you want to hide the Action Bar for a particular activity, set the activity theme to
+{@code android:style/Theme.NoTitleBar}. For example:</p>
+
+<pre>
+&lt;activity android:theme="@android:style/Theme.NoTitleBar"&gt;
+</pre>
<h2 id="ActionItems">Adding Action Items</h2>
-<p>For each action item you want to add to the action bar, you must add a menu item to the
-activity's <a href="{@docRoot}guide/topics/ui/menus.html#OptionsMenu">options menu</a> and declare
-that the item be shown as an action, using the {@code android:showAsAction} attribute in the menu
-XML or with {@link android.view.MenuItem#setShowAsAction setShowAsAction()} on the {@link
-android.view.MenuItem}.</p>
+<p>For each action item you want to add to the Action Bar, you must add a menu item to the
+activity's <a href="{@docRoot}guide/topics/ui/menus.html#OptionsMenu">Options Menu</a> and declare
+that the item be shown as an action.</p>
<div class="figure" style="width:359px">
<img src="{@docRoot}images/ui/actionbar-item-withtext.png" height="57" alt="" />
- <p class="img-caption"><strong>Figure 2.</strong> A screenshot from an action bar with two
+ <p class="img-caption"><strong>Figure 2.</strong> A screenshot from an Action Bar with two
action items.</p>
</div>
-<p>You can specify a menu item to appear as an action item in the action bar&mdash;if there is room
+<p>You can specify a menu item to appear as an action item&mdash;if there is room
for it&mdash;from the <a href="{@docRoot}guide/topics/resources/menu-resource.html">menu
resource</a> by declaring {@code
android:showAsAction="ifRoom"} for the {@code &lt;item&gt;} element. This way, the item will display
-in the action bar for quick access only if there is room available for it&mdash;if there's not
-enough room, the item is placed the options menu (revealed by the drop-down icon on the right side
-of the action bar). From your application code, you can specify the item to appear as an action item
+in the Action Bar for quick access only if there is room available for it&mdash;if there's not
+enough room, the item is placed the Overflow Menu (revealed by the menu icon on the right side
+of the Action Bar). From your application code, you can specify the item to appear as an action item
by calling {@link android.view.MenuItem#setShowAsAction setShowAsAction()} on the {@link
android.view.MenuItem} and passing {@link android.view.MenuItem#SHOW_AS_ACTION_IF_ROOM}.</p>
@@ -104,7 +131,7 @@ the icon by defult. If you want to include the text with the action item, add th
flag&mdash;in XML, add {@code withText} to the {@code android:showAsAction} attribute or, in
your application code, use the {@link android.view.MenuItem#SHOW_AS_ACTION_WITH_TEXT} flag when
calling {@link android.view.MenuItem#setShowAsAction setShowAsAction()}. Figure 2 shows a screenshot
-of an action bar with two action items that include text.</p>
+of an Action Bar with two action items that include text.</p>
<p>Here's an example of how you can declare a menu item as an action item in a <a
href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a> file:</p>
@@ -121,22 +148,21 @@ href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a> fil
<p>In this case, both the {@code ifRoom} and {@code withText} flags are set, so that when this
item appears as an action item, it includes the title text along with the icon.</p>
-<p>A menu item placed in the action bar triggers the same callback methods as other items in the
-options menu. When the user selects an item in the action bar, your activity receives a call to
+<p>A menu item placed in the Action Bar triggers the same callback methods as other items in the
+Options Menu. When the user selects an item in the Action Bar, your activity receives a call to
{@link android.app.Activity#onOptionsItemSelected(MenuItem) onOptionsItemSelected()}, passing the
item ID. (If you added the item from a fragment, then the respective {@link
android.app.Fragment#onOptionsItemSelected(MenuItem) onOptionsItemSelected()} method is called
for that fragment.)</p>
-<p class="note"><strong>Note:</strong> Even menu items that are contained in the options menu
-(and not shown as action items) will show an icon, so when using the action bar, you should
-provide an icon for every item in the options menu.</p>
+<p class="note"><strong>Note:</strong> Menu items that appear in the Overflow Menu (not as action
+items) also show an icon, so it's best if you provide an icon for every menu item.</p>
<p>You can also declare an item to <em>always</em> appear as an action item, but you should avoid
doing so. Most of the time, there will be enough room for several action items and they will appear
in the order you declare them. If you set items to always appear as action
items (instead of <em>if room</em>), then they are added without discrimination and there is a risk
-that they will collide with other elements in the action bar, such as tabs or custom views.</p>
+that they will collide with other elements in the Action Bar, such as tabs or custom views.</p>
<p>For more information about menus, see the <a
href="{@docRoot}guide/topics/ui/menus.html#options-menu">Creating Menus</a> developer guide.</p>
@@ -144,7 +170,7 @@ href="{@docRoot}guide/topics/ui/menus.html#options-menu">Creating Menus</a> deve
<h3 id="Home">Using the application icon as an action item</h3>
-<p>By default, the application icon appears in the action bar on the left side, but does nothing
+<p>By default, the application icon appears in the Action Bar on the left side, but does nothing
when tapped. To use the application icon as an action item when tapped, you simply need to add a
condition to your {@link android.app.Activity#onOptionsItemSelected onOptionsItemSelected()} method
that performs an action when the {@link android.view.MenuItem} ID is {@code android.R.id.home}.
@@ -158,7 +184,7 @@ onOptionsItemSelected()} that returns to the application's "home" activity:</p>
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
- // app icon in action bar clicked; go home
+ // app icon in Action Bar clicked; go home
Intent intent = new Intent(this, HomeActivity.class);
startActivity(intent);
break;
@@ -176,7 +202,7 @@ public boolean onOptionsItemSelected(MenuItem item) {
<p>You can also use the application icon to provide "up" navigation. The way you handle the event
when a user taps the icon is the same, but if the user experience for the event is to <em>navigate
up to the parent activity</em>, then you should indicate this behavior by setting the
-action bar to "show home as up." You can do so by calling {@link
+Action Bar to "show home as up." You can do so by calling {@link
android.app.ActionBar#setDisplayOptions setDisplayOptions()} on your activity's {@link
android.app.ActionBar}, and passing the {@link
android.app.ActionBar#DISPLAY_HOME_AS_UP} display option.</p>
@@ -186,7 +212,7 @@ your {@link android.app.Activity} during {@link android.app.Activity#onCreate on
sure you do so <em>after</em> you've called {@link android.app.Activity#setContentView
setContentView()}).</p>
-<p>For example, here's how you can change the action bar display mode to show the application
+<p>For example, here's how you can change the Action Bar display mode to show the application
icon as an "up" action:</p>
<pre>
@@ -198,24 +224,103 @@ protected void onStart() {
}
</pre>
-<p class="caution"><strong>Caution:</strong> If your activity does not have an action bar (if you
-did not set the theme of your activity or application to the holographic or action bar theme), then
+<p class="caution"><strong>Caution:</strong> If your activity does not have an Action Bar (if you
+did not set the theme of your activity or application to the holographic or Action Bar theme), then
{@link android.app.Activity#getActionBar} returns null.</p>
+
+<h2 id="ActionView">Adding an Action View</h2>
+
+<div class="figure" style="width:281px">
+ <img src="{@docRoot}images/ui/actionbar-actionview.png" alt="" />
+ <p class="img-caption"><strong>Figure 4.</strong> An action view with a search widget.</p>
+</div>
+
+<p>An action view is a customized view you can specify for an item in your Options Menu, to
+display in the Action Bar when the item is included as an action item. For example, you can
+include a menu item for "Search", which appears and behaves as a normal menu item in the Overflow
+Menu, but, when set as an action item, it provides an action view that is a {@link
+android.widget.SearchView}, so the user can initiate a search directly from the Action Bar.
+Figure 4 shows an example of this, in which a menu item for search provides an action view
+using the {@link android.widget.SearchView} widget.</p>
+
+<p>The best way to declare an action view for an item is in your <a
+href="{@docRoot}guide/topics/resources/menu-resource.html">menu resource</a>, using the {@code
+android:actionLayout} or {@code android:actionViewClass} attribute.</p>
+
+<ul>
+ <li>The value for {@code android:actionLayout} must be a resource pointer to a layout file.
+For example:
+<pre>
+&lt;item android:id="@+id/menu_search"
+ android:title="Search"
+ android:icon="@drawable/ic_menu_search"
+ android:showAsAction="ifRoom"
+ <b>android:actionLayout="@layout/searchview"</b> /&gt;
+</pre></li>
+ <li>The value for {@code android:actionViewClass} must be a fully-qualified class name for
+the {@link android.view.View} you want to use. For example:
+<pre>
+&lt;item android:id="@+id/menu_search"
+ android:title="Search"
+ android:icon="@drawable/ic_menu_search"
+ android:showAsAction="ifRoom"
+ <b>android:actionViewClass="android.widget.SearchView"</b> /&gt;
+</pre></li>
+</ul>
+
+<p>Now, when the menu item is displayed as an action item, it's action view appears instead of
+the item's traditional icon and/or text. Yet, if for some reason the item does not appear in the
+Action Bar, then it behaves like a normal menu item in the Overflow Menu and you must respond
+accordingly when the user taps it, from the {@link android.app.Activity#onOptionsItemSelected
+onOptionsItemSelected()} callback.</p>
+
+<p>When the activity first starts, the system populates the Action Bar and Overflow Menu by calling
+{@link android.app.Activity#onCreateOptionsMenu onCreateOptionsMenu()}.
+After you've inflated your menu in this method, you can acquire elements in an action view
+(perhaps in order to attach listeners) by calling {@link android.view.Menu#findItem
+findItem()} with the ID of the menu item, then {@link android.view.MenuItem#getActionView} on
+the returned {@link android.view.MenuItem}. For example, the search widget from the above samples is
+acquired like this:</p>
+
+<pre>
+&#64;Override
+public boolean onCreateOptionsMenu(Menu menu) {
+ getMenuInflater().inflate(R.menu.options, menu);
+ SearchView searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
+ // Set appropriate listeners for searchView
+ ...
+ return super.onCreateOptionsMenu(menu);
+}
+</pre>
+
+<p>For more information about enabling search in the Action Bar, see the <a
+href="{@docRoot}guide/topics/search/index.html">Search</a> developer guide.</p>
+
+
+
<h2 id="Tabs">Adding Tabs</h2>
-<p>The action bar can display tabs that allow the user navigate between different fragments in the
+<p>The Action Bar can display tabs that allow the user navigate between different fragments in the
activity. Each tab can include a title and/or an icon.</p>
+<!--
+<div class="figure" style="width:300px">
+ <img src="{@docRoot}images/ui/actionbar-tabs.png" alt="" />
+ <p class="img-caption"><strong>Figure 5.</strong> Screenshot of tabs in the
+Action Bar.</p>
+</div>
+-->
+
<p>To begin, your layout must include a {@link android.view.View} in which each {@link
android.app.Fragment} associated with a tab is displayed. Be sure the view has an ID that you
can use to reference it from your code.</p>
-<p>To add tabs to the action bar:</p>
+<p>To add tabs to the Action Bar:</p>
<ol>
<li>Create an implementation of {@link android.app.ActionBar.TabListener} to handle the
-interaction events on the action bar tabs. You must implement all methods: {@link
+interaction events on the Action Bar tabs. You must implement all methods: {@link
android.app.ActionBar.TabListener#onTabSelected onTabSelected()}, {@link
android.app.ActionBar.TabListener#onTabUnselected onTabUnselected()}, and {@link
android.app.ActionBar.TabListener#onTabReselected onTabReselected()}.
@@ -260,7 +365,7 @@ android.app.Activity#onCreate onCreate()} (but be sure you do so <em>after</em>
<li>Call {@link android.app.ActionBar#setNavigationMode(int)
setNavigationMode(NAVIGATION_MODE_TABS)} to enable tab mode for the {@link
android.app.ActionBar}.</li>
- <li>Create each tab for the action bar:
+ <li>Create each tab for the Action Bar:
<ol>
<li>Create a new {@link android.app.ActionBar.Tab} by calling {@link
android.app.ActionBar#newTab()} on the {@link android.app.ActionBar}.</li>
@@ -274,19 +379,19 @@ instance of your implementation to {@link android.app.ActionBar.Tab#setTabListen
setTabListener()}.
</ol>
</li>
- <li>Add each {@link android.app.ActionBar.Tab} to the action bar by calling {@link
+ <li>Add each {@link android.app.ActionBar.Tab} to the Action Bar by calling {@link
android.app.ActionBar#addTab addTab()} on the {@link android.app.ActionBar} and passing the
-{@link android.app.ActionBar.Tab}.</li>
+{@link android.app.ActionBar.Tab}.<>
</ol>
<p>For example, the following code combines steps 2 - 5 to create two tabs and add them to
-the action bar:</p>
+the Action Bar:</p>
<pre>
&#64;Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
- // setup action bar for tabs
+ // setup Action Bar for tabs
final ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// remove the activity title to make space for tabs
@@ -295,11 +400,11 @@ protected void onCreate(Bundle savedInstanceState) {
// instantiate fragment for the tab
Fragment artistsFragment = new ArtistsFragment();
// add a new tab and set its title text and tab listener
- bar.addTab(bar.newTab().setText(R.string.tab_artists)
+ actionBar.addTab(actionBar.newTab().setText(R.string.tab_artists)
.setTabListener(new TabListener(artistsFragment)));
Fragment albumsFragment = new AlbumsFragment();
- bar.addTab(bar.newTab().setText(R.string.tab_albums)
+ actionBar.addTab(actionBar.newTab().setText(R.string.tab_albums)
.setTabListener(new TabListener(albumsFragment)));
}
</pre>
@@ -330,3 +435,159 @@ the state of your fragment, see the <a
href="{@docRoot}guide/topics/fragments/index.html">Fragments</a> developer guide.</p>
+
+<h2 id="Dropdown">Adding Drop-down Navigation</h2>
+
+<p>As another mode of navigation within your activity, you can provide a drop-down list in the
+Action Bar. For example, the drop-down list can provide alternative modes for sorting the content in
+the activity or switching the user's account.</p>
+
+<!--
+<div class="figure" style="width:135px">
+ <img src="{@docRoot}images/ui/actionbar-dropdown.png" alt="" />
+ <p class="img-caption"><strong>Figure 5.</strong> Screenshot of a drop-down navigation list in the
+Action Bar.</p>
+</div>
+-->
+
+<p>Here's a quick list of what you must do to enable drop-down navigation:</p>
+
+<ol>
+ <li>Create a {@link android.widget.SpinnerAdapter} that provides the
+list of selectable items for the list and the layout to use when drawing each item in the list.</li>
+ <li>Implement {@link android.app.ActionBar.NavigationCallback} to define the behavior when the
+user selects an item from the list.</li>
+ <li>Turn on navigation mode for the Action Bar with {@link
+android.app.ActionBar#setNavigationMode setNavigationMode()}. For example:
+<pre>
+ActionBar actionBar = getActionBar();
+actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
+</pre>
+ <p>You should perform this during your activity's {@link android.app.Activity#onCreate
+onCreate()} method.</p>
+ </li>
+ <li>Following that, set the callback for your drop-down list with {@link
+android.app.ActionBar#setListNavigationCallbacks setListNavigationCallbacks()}. For example:
+<pre>
+actionBar.setListNavigationCallbacks(mSpinnerAdapter, mNavigationCallback);
+</pre>
+<p>This method takes your {@link android.widget.SpinnerAdapter} and {@link
+android.app.ActionBar.NavigationCallback}. More about these next.</p>
+</li>
+</ol>
+
+<p>That's the basic setup. The {@link android.widget.SpinnerAdapter} and {@link
+android.app.ActionBar.NavigationCallback} is where most of the work is done. There are many ways
+you can implement these to define the functionality for your drop-down navigation. Implementing
+various types of {@link android.widget.SpinnerAdapter} is beyond the scope of this
+document&mdash;you should refer to the class refrence for more information about implementing it or
+extending an existing implementation. However, below is a simple example for a {@link
+android.widget.SpinnerAdapter} and {@link android.app.ActionBar.NavigationCallback} to get you
+started.</p>
+
+
+<h3 id="Spinner">Example: simple SpinnerAdapter</h3>
+
+<p>{@link android.widget.SpinnerAdapter} is an interface that you can implement to provide
+content for the list and is where your implementation for the drop-down list can be heavily
+customized. Android includes some useful implementations that you can extend, such as {@link
+android.widget.ArrayAdapter} and {@link
+android.widget.SimpleCursorAdapter}. For example, here's an easy way to create a {@link
+android.widget.SpinnerAdapter} with {@link android.widget.ArrayAdapter}, using a string array
+from resources:</p>
+
+<pre>
+SpinnerAdapter mSpinnerAdapter = ArrayAdapter.createFromResource(this, R.array.action_list,
+ android.R.layout.simple_spinner_dropdown_item);
+</pre>
+
+<p>This is now ready to be given to {@link
+android.app.ActionBar#setListNavigationCallbacks setListNavigationCallbacks()}, in step 4 from
+above.</p>
+
+<p>A <a href="{@docRoot}guide/topics/resources/string-resource.html#StringArray">string array</a>
+defined as a resource looks like this:</p>
+
+<pre>
+&lt;?xml version="1.0" encoding="utf-8"?&gt;
+&lt;resources&gt;
+ &lt;string-array name="action_list"&gt;
+ &lt;item&gt;Mercury&lt;/item&gt;
+ &lt;item&gt;Venus&lt;/item&gt;
+ &lt;item&gt;Earth&lt;/item&gt;
+ &lt;/string-array&gt;
+&lt;/pre&gt;
+</pre>
+
+
+<h3 id="NavigationCallback">Example: simple NavigationCallback</h3>
+
+<p>Your implementation of {@link android.app.ActionBar.NavigationCallback} is where you handle
+fragment changes or other modifications to your activity when the user selects an item from the
+drop-down list. There's only one callback method to implement: {@link
+android.app.ActionBar.NavigationCallback#onNavigationItemSelected onNavigationItemSelected()}.</p>
+
+<p>The {@link
+android.app.ActionBar.NavigationCallback#onNavigationItemSelected onNavigationItemSelected()}
+method receives the position of the item in the list and an item ID provided by the {@link
+android.widget.SpinnerAdapter}.</p>
+
+<p>Here's an example that instantiates an anonymous implementation of {@link
+android.app.ActionBar.NavigationCallback}, which inserts a {@link android.app.Fragment} into the
+layout container identified by {@code R.id.fragment_container}:</p>
+
+<pre>
+mNavigationCallback = new NavigationCallback() {
+ // Get the same strings provided for the drop-down's ArrayAdapter
+ String[] strings = getResources().getStringArray(R.array.action_list);
+
+ &#64;Override
+ public boolean onNavigationItemSelected(int position, long itemId) {
+ // Create new fragment from our own Fragment class
+ ListContentFragment newFragment = new ListContentFragment();
+ FragmentTransaction ft = openFragmentTransaction();
+ // Replace whatever is in the fragment container with this fragment
+ // and give the fragment a tag name equal to the string at the position selected
+ ft.replace(R.id.fragment_container, newFragment, strings[position]);
+ // Apply changes
+ ft.commit();
+ return true;
+ }
+};
+</pre>
+
+<p>This instance of {@link android.app.ActionBar.NavigationCallback} can be given to {@link
+android.app.ActionBar#setListNavigationCallbacks setListNavigationCallbacks()}, in step 4 from
+above.</p>
+
+<p>In this example, the fragment added is given a tag that can uniquely identify the fragment.
+For this example, the {@code ListContentFragment} class used uses this tag as
+the text for a {@link android.widget.TextView} in the fragment's layout. Here's how it's done:</p>
+
+<pre>
+public class ListContentFragment extends Fragment {
+ private String mText;
+
+ &#64;Override
+ public void onAttach(Activity activity) {
+ // This is the first callback received; here we can set the text for
+ // the fragment as defined by the tag specified during the fragment transaction
+ super.onAttach(activity);
+ mText = getTag();
+ }
+
+ &#64;Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ // This is called to define the layout for the fragment;
+ // we just create a TextView and set its text to be the fragment tag
+ TextView text = new TextView(getActivity());
+ text.setText(mText);
+ return text;
+ }
+}
+</pre>
+
+
+
+
diff --git a/docs/html/images/preview_hc/actionbar.png b/docs/html/images/preview_hc/actionbar.png
new file mode 100644
index 0000000..31df2b2
--- /dev/null
+++ b/docs/html/images/preview_hc/actionbar.png
Binary files differ
diff --git a/docs/html/images/preview_hc/fragments_layout.png b/docs/html/images/preview_hc/fragments_layout.png
new file mode 100644
index 0000000..91c8929
--- /dev/null
+++ b/docs/html/images/preview_hc/fragments_layout.png
Binary files differ
diff --git a/docs/html/images/ui/actionbar-actionview.png b/docs/html/images/ui/actionbar-actionview.png
new file mode 100644
index 0000000..30edca0
--- /dev/null
+++ b/docs/html/images/ui/actionbar-actionview.png
Binary files differ
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index 8b77303..4153951 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -19,6 +19,7 @@ sdk.linux_checksum=TODO
@jd:body
+<div class="non-preview">
<p>Here's an overview of the steps you must follow to set up the Android SDK:</p>
<ol>
@@ -32,3 +33,4 @@ installer for help with the initial setup.)</li>
<p>To get started, download the appropriate package from the table above, then read the guide to <a
href="installing.html">Installing the SDK</a>.</p>
+</div>
diff --git a/docs/html/sdk/preview/features.jd b/docs/html/sdk/preview/features.jd
index 81b4ff6..55d0f8d 100644
--- a/docs/html/sdk/preview/features.jd
+++ b/docs/html/sdk/preview/features.jd
@@ -1,4 +1,185 @@
-sdk.redirect=true
-
+page.title=Introduction to Honeycomb
@jd:body
+<p>Welcome to the Honeycomb preview SDK. Honeycomb is the next major release of the Android
+platform and is optimized for tablet devices. This document provides an introduction to the new
+platform features and APIs available in Honeycomb.</p>
+
+
+<h2>Fragments</h2>
+
+<div class="figure" style="width:400px">
+ <img src="{@docRoot}images/preview_hc/fragments_layout.png" alt="" />
+ <p class="img-caption"><strong>Fragment Layout.</strong> An activity with two
+fragments: one with a list view, on the left, and one that displays selected content on the
+right. This demo is available in the samples package.</p>
+</div>
+
+
+<p>A new framework component that allows you to separate distinct elements of an activity into
+self-contained modules that define their own UI and lifecycle&mdash;defining what may be
+considered "sub-activities".</p>
+<ul>
+ <li>Multiple fragments can be combined in a single activity to build a multi-pane UI in which
+each pane manages its own lifecycle and user inputs</li>
+ <li>Fragments are self-contained and can be reused in multiple activities</li>
+ <li>Fragments can be added, removed, replaced and animated inside the activity</li>
+ <li>Fragment can be added to a back stack managed by the activity, preserving the state of
+fragments as they are changed and allowing the user to navigate backward through the different
+states</li>
+ <li>By <a
+href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">providing
+alternative resources</a>, you can mix and match fragments, based
+on the screen size and orientation</li>
+ <li>Fragments have direct access to their container activity and can contribute items to the
+activity's Options Menu</li>
+</ul>
+
+<p>For more information, see the <a
+href="{@docRoot}guide/topics/fragments/index.html">Fragments</a> developer guide.</p>
+
+
+<h2>Action Bar</h2>
+
+<p>A replacement for the traditional title bar, which provides users quick access to global
+actions and different navigation modes.</p>
+<ul>
+ <li>Provides quick access to items from the Options Menu ("action items") and interactive
+widgets ("action views")</li>
+ <li>Includes the application logo in the left corner, which can perform actions when tapped
+and can be replaced with a custom logo</li>
+ <li>Provides breadcumbs for navigating backward through fragments</li>
+ <li>Offers built in navigation modes, including tabs and a drop-down list</li>
+ <li>Can be customized with themes and custom backgrounds</li>
+ <li>And more</li>
+</ul>
+
+<img src="{@docRoot}images/preview_hc/actionbar.png" alt="" />
+<p class="img-caption"><strong>Action Bar.</strong> An action bar with a custom logo,
+tabs, and Options Menu. This demo is available in the samples package.</p>
+
+<p>For more information, see the <a
+href="{@docRoot}guide/topics/ui/actionbar.html">Action Bar</a> developer guide.</p>
+
+
+<h2>System Clipboard</h2>
+
+<p>Applications can copy and paste data (beyond mere text) to and from the system-wide
+clipboard.</p>
+
+<ul>
+ <li>Clipped data can be plain text, a URI, or an intent</li>
+ <li>The new {@link android.content.ClipData} class represents a complex data type for the
+clipboard</li>
+ <li>The new {@link android.content.ClipboardManager} class allows apps to add {@link
+android.content.ClipData} to the clipboard (copy) and read {@link
+android.content.ClipData} from the clipboard (paste)</li>
+ <li>The {@link android.content.ContentProvider} class has been extended to generate byte
+streams based on data types added to the clipboard and point to data hosted in a
+content provider</li>
+</ul>
+
+<p>See {@link android.content.ClipData} and {@link android.content.ClipboardManager}
+for more information. You can also see an example implementation of copy/paste in an updated
+version of the NotePad application (available in the samples package).</p>
+
+
+<h2>Drag and Drop</h2>
+
+<p>New APIs to perform drag and drop operations, leveraging the system clipboard APIs to
+transport data.</p>
+
+<ul>
+ <li>Any {@link android.view.View} can be used for a drag and drop event and a thumbnail of that
+view is generated and used during the drag</li>
+ <li>{@link android.view.ViewGroup}s that can receive the object are notified during hover and drop
+events</li>
+ <li>The new {@link android.view.DragEvent} class describes a drag event relating to a view,
+including the item's current coordinates, the type of action (whether the drag has entered the
+view, exited the view, started, dropped, etc.), and provides access to the {@link
+android.content.ClipData} being carried</li>
+ <li>The new {@link android.view.View.OnDragListener} interface defines a callback that views
+can register in order to be notified of drag events being dispatched to the view; view's can
+register a drag listener with {@link android.view.View#setOnDragListener setOnDragListener()}</li>
+</ul>
+
+<p>See {@link android.view.DragEvent} and {@link android.view.View.OnDragListener} for more
+information.</p>
+
+
+<h2>New Animations</h2>
+
+<p>An all new animation framework.</p>
+
+<ul>
+ <li>A flexible animation system that allows you to animate the properties of any object (View,
+Drawable, Fragment, Object, anything)</li>
+</ul>
+
+<p>See the {@link android.animation} package.</p>
+
+
+<h2>Extended App Widgets</h2>
+
+<p>App widgets can now be more interactive and accept finger gestures.</p>
+
+<ul>
+ <li>The complete list of supported widgets for an app widget is now: {@link
+android.widget.AnalogClock}, {@link android.widget.Button}, {@link android.widget.Chronometer},
+{@link android.widget.ImageButton}, {@link android.widget.ImageView}, {@link
+android.widget.ProgressBar}, {@link android.widget.TextView}, {@link
+android.widget.ViewFlipper}, {@link android.widget.AdapterViewFlipper}, {@link
+android.widget.StackView}, {@link android.widget.ListView}, and {@link
+android.widget.GridView}.</li>
+</ul>
+
+
+<h2>Extended Status Bar Notifications</h2>
+
+<p>The {@link android.app.Notification} class has been extended to support more content-rich
+status bar notifications when on xlarge screens.</p>
+
+<ul>
+ <li>New {@link android.app.Notification.Builder} class helps you easily create new {@link
+android.app.Notification} objects</li>
+ <li>Support for a title in the status bar ticker (in addition to the normal ticker text)</li>
+ <li>Support for a large "sender" icon in the notification&mdash;a second icon intended for
+social applications to show the contact photo of the person who is the source of the
+notification</li>
+ <li>Support for custom layouts in the status bar ticker</li>
+ <li>Support for buttons in the expanded notification that deliver custom intents
+(such as to control ongoing music in the background)</li>
+</ul>
+
+
+<h2>Plus Android 2.3</h2>
+
+<p>Honeycomb includes all platform changes introduced for Android 2.3.</p>
+
+<p>To take full advantage of Honeycomb, you should also be aware of the new features
+and APIs introduced for Android 2.3. To learn more, read the <a
+href="{@docRoot}sdk/android-2.3.html">Android 2.3 release notes</a>.</p>
+
+<div class="special">
+<p>To set up your preview SDK and start developing apps for Honeycomb, see the <a
+href="{@docRoot}sdk/preview/installing.html">Getting Started</a> guide.</p>
+</div>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/html/sdk/preview/installing.jd b/docs/html/sdk/preview/installing.jd
index 1e6b26b..c835c49 100644
--- a/docs/html/sdk/preview/installing.jd
+++ b/docs/html/sdk/preview/installing.jd
@@ -1,5 +1,62 @@
-sdk.redirect=true
-
+page.title=Getting Started with Honeycomb
@jd:body
+<p>First, you need to set up your development environment with the new SDK Tools and preview
+platform:</p>
+
+<ol>
+ <li>Unpack the SDK Tools r8 package you've received.
+ <p>If you have an existing Android SDK directory, simply replace your existing {@code
+tools/} directory with the one from the new package and add the {@code platform-tools/}
+directory along side it (at the root of the SDK directory).</p></li>
+ <li>Unpack the platform package ({@code android-Froyo}) and place it in your SDK's {@code
+platforms/} directory.</li>
+ <li>If you're using Eclipse, also update your Eclipse plugin using the provided archive file.
+ <ol>
+ <li>Select <strong>Help > Install new software</strong>.</li>
+ <li>Click <strong>Add</strong>.</li>
+ <li>Click <strong>Archive</strong>.</li>
+ <li>Locate and select the archive file. Click <strong>OK</strong>.
+ <p>Developer Tools now appear in the Available Software window and you can proceed
+to install the plugin.</p>
+ </li>
+ </ol>
+ </li>
+</ol>
+
+<p class="note"><strong>Note:</strong> Beginning with SDK Tools r8 (the version you've received),
+the {@code adb} tool is now located in the {@code &lt;sdk&gt;/platform-tools/} directory (instead
+of in {@code &lt;sdk&gt;/tools/}). Be sure to update your {@code PATH} environment variable and any
+build/debugging scripts you have.</p>
+
+
+
+<h2 id="Setup">Set Up Your AVD and Application</h2>
+
+<p>With your SDK now set up, follow these steps to start developing an application for
+Honeycomb.</p>
+
+<ol>
+
+ <li>Create a new AVD targeted to "Android Froyo (Preview)" and with a custom skin resolution of
+1280 x 800.</li>
+
+ <li>Set the build target of your application to "Android Froyo (Preview)".</li>
+ <li>Set your manifest file's {@code &lt;uses-sdk&gt;} element to use {@code
+android:minSdkVersion="Froyo"}. For example:
+<pre>
+&lt;manifest&gt;
+ &lt;uses-sdk android:minSdkVersion="Froyo" /&gt;
+ ...
+&lt;/manifest&gt;
+</pre>
+<p>"Froyo" is a provisional API Level for the Honeycomb release, used only during the preview
+period. When the APIs are
+finalized and the SDK is released publicly, you must update this with the appropriate API Level
+integer.</p>
+<p class="note"><strong>Note:</strong> By providing your {@code &lt;uses-sdk&gt;} element in the
+manifest file <em>before</em> the {@code &lt;application&gt;} element, your application will
+automatically apply the new Holographic theme.</p>
+</li>
+</ol>
diff --git a/docs/html/sdk/sdk_toc.cs b/docs/html/sdk/sdk_toc.cs
index 057d9e0..0b74bd6 100644
--- a/docs/html/sdk/sdk_toc.cs
+++ b/docs/html/sdk/sdk_toc.cs
@@ -37,6 +37,17 @@
</ul>
</li><?cs
/if ?>
+ <?cs
+ if:sdk.preview ?>
+ <li><h2>Android Preview SDK</h2></li>
+ <ul>
+ <li><a href="<?cs var:toroot ?>sdk/preview/features.html">Introduction
+to Honeycomb</a></li>
+ <li><a href="<?cs var:toroot ?>sdk/preview/installing.html">Getting
+Started</a></li>
+ </ul>
+ </li><?cs
+ /if ?>
<li>
<h2>
<span class="en">Downloadable SDK Components</span>
diff --git a/include/ui/EventHub.h b/include/ui/EventHub.h
index f4dc536..6c798a6 100644
--- a/include/ui/EventHub.h
+++ b/include/ui/EventHub.h
@@ -26,6 +26,7 @@
#include <utils/threads.h>
#include <utils/List.h>
#include <utils/Errors.h>
+#include <utils/PropertyMap.h>
#include <linux/input.h>
@@ -156,6 +157,8 @@ public:
virtual String8 getDeviceName(int32_t deviceId) const = 0;
+ virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const = 0;
+
virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
RawAbsoluteAxisInfo* outAxisInfo) const = 0;
@@ -205,6 +208,8 @@ public:
virtual String8 getDeviceName(int32_t deviceId) const;
+ virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const;
+
virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
RawAbsoluteAxisInfo* outAxisInfo) const;
@@ -247,6 +252,8 @@ private:
uint32_t classes;
uint8_t* keyBitmask;
KeyLayoutMap* layoutMap;
+ String8 configurationFile;
+ PropertyMap* configuration;
KeyMapInfo keyMapInfo;
int fd;
device_t* next;
@@ -264,6 +271,7 @@ private:
bool markSupportedKeyCodesLocked(device_t* device, size_t numCodes,
const int32_t* keyCodes, uint8_t* outFlags) const;
+ void loadConfiguration(device_t* device);
void configureKeyMap(device_t* device);
void setKeyboardProperties(device_t* device, bool firstKeyboard);
void clearKeyboardProperties(device_t* device, bool firstKeyboard);
diff --git a/include/ui/Input.h b/include/ui/Input.h
index 1355bab..4dc8f2a 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -497,6 +497,22 @@ private:
KeyedVector<int32_t, MotionRange> mMotionRanges;
};
+/* Types of input device configuration files. */
+enum InputDeviceConfigurationFileType {
+ INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION = 0, /* .idc file */
+ INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT = 1, /* .kl file */
+ INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP = 2, /* .kcm file */
+};
+
+/*
+ * Get the path of an input device configuration file, if one is available.
+ * Spaces in the name are replaced with underscores.
+ * Considers both system provided and user installed configuration files.
+ *
+ * Returns an empty string if not found.
+ */
+extern String8 getInputDeviceConfigurationFilePath(
+ const String8& name, InputDeviceConfigurationFileType type);
} // namespace android
diff --git a/include/ui/InputDispatcher.h b/include/ui/InputDispatcher.h
index d0812de..b621680 100644
--- a/include/ui/InputDispatcher.h
+++ b/include/ui/InputDispatcher.h
@@ -291,9 +291,7 @@ public:
* This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event
* should be dispatched to applications.
*/
- virtual void interceptKeyBeforeQueueing(nsecs_t when, int32_t deviceId,
- int32_t action, int32_t& flags, int32_t keyCode, int32_t scanCode,
- uint32_t& policyFlags) = 0;
+ virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) = 0;
/* Intercepts a generic touch, trackball or other event before queueing it.
* The policy can use this method as an opportunity to perform power management functions
@@ -894,9 +892,6 @@ private:
// Input channels that will receive a copy of all input events.
Vector<sp<InputChannel> > mMonitoringChannels;
- // Preallocated key event object used for policy inquiries.
- KeyEvent mReusableKeyEvent;
-
// Event injection and synchronization.
Condition mInjectionResultAvailableCondition;
bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid);
diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h
index f3a2dd2..cfceaab 100644
--- a/include/ui/InputReader.h
+++ b/include/ui/InputReader.h
@@ -47,23 +47,6 @@ struct VirtualKeyDefinition {
};
-/* Specifies input device calibration settings. */
-class InputDeviceCalibration {
-public:
- InputDeviceCalibration();
-
- void clear();
- void addProperty(const String8& key, const String8& value);
-
- bool tryGetProperty(const String8& key, String8& outValue) const;
- bool tryGetProperty(const String8& key, int32_t& outValue) const;
- bool tryGetProperty(const String8& key, float& outValue) const;
-
-private:
- KeyedVector<String8, String8> mProperties;
-};
-
-
/*
* Input reader policy interface.
*
@@ -107,10 +90,6 @@ public:
virtual void getVirtualKeyDefinitions(const String8& deviceName,
Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions) = 0;
- /* Gets the calibration for an input device. */
- virtual void getInputDeviceCalibration(const String8& deviceName,
- InputDeviceCalibration& outCalibration) = 0;
-
/* Gets the excluded device names for the platform. */
virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) = 0;
};
@@ -314,8 +293,8 @@ public:
int32_t getMetaState();
- inline const InputDeviceCalibration& getCalibration() {
- return mCalibration;
+ inline const PropertyMap& getConfiguration() {
+ return mConfiguration;
}
private:
@@ -330,7 +309,7 @@ private:
typedef int32_t (InputMapper::*GetStateFunc)(uint32_t sourceMask, int32_t code);
int32_t getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc);
- InputDeviceCalibration mCalibration;
+ PropertyMap mConfiguration;
};
@@ -389,13 +368,13 @@ private:
class KeyboardInputMapper : public InputMapper {
public:
- KeyboardInputMapper(InputDevice* device, int32_t associatedDisplayId, uint32_t sources,
- int32_t keyboardType);
+ KeyboardInputMapper(InputDevice* device, uint32_t sources, int32_t keyboardType);
virtual ~KeyboardInputMapper();
virtual uint32_t getSources();
virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
virtual void dump(String8& dump);
+ virtual void configure();
virtual void reset();
virtual void process(const RawEvent* rawEvent);
@@ -414,10 +393,15 @@ private:
int32_t scanCode;
};
- int32_t mAssociatedDisplayId;
uint32_t mSources;
int32_t mKeyboardType;
+ // Immutable configuration parameters.
+ struct Parameters {
+ int32_t associatedDisplayId;
+ bool orientationAware;
+ } mParameters;
+
struct LockedState {
Vector<KeyDown> keyDowns; // keys that are down
int32_t metaState;
@@ -435,6 +419,9 @@ private:
void initializeLocked();
void initializeLedStateLocked(LockedState::LedState& ledState, int32_t led);
+ void configureParameters();
+ void dumpParameters(String8& dump);
+
bool isKeyboardOrGamepadKey(int32_t scanCode);
void processKey(nsecs_t when, bool down, int32_t keyCode, int32_t scanCode,
@@ -450,12 +437,13 @@ private:
class TrackballInputMapper : public InputMapper {
public:
- TrackballInputMapper(InputDevice* device, int32_t associatedDisplayId);
+ TrackballInputMapper(InputDevice* device);
virtual ~TrackballInputMapper();
virtual uint32_t getSources();
virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
virtual void dump(String8& dump);
+ virtual void configure();
virtual void reset();
virtual void process(const RawEvent* rawEvent);
@@ -467,7 +455,11 @@ private:
Mutex mLock;
- int32_t mAssociatedDisplayId;
+ // Immutable configuration parameters.
+ struct Parameters {
+ int32_t associatedDisplayId;
+ bool orientationAware;
+ } mParameters;
struct Accumulator {
enum {
@@ -499,13 +491,16 @@ private:
void initializeLocked();
+ void configureParameters();
+ void dumpParameters(String8& dump);
+
void sync(nsecs_t when);
};
class TouchInputMapper : public InputMapper {
public:
- TouchInputMapper(InputDevice* device, int32_t associatedDisplayId);
+ TouchInputMapper(InputDevice* device);
virtual ~TouchInputMapper();
virtual uint32_t getSources();
@@ -591,10 +586,17 @@ protected:
}
};
- int32_t mAssociatedDisplayId;
-
// Immutable configuration parameters.
struct Parameters {
+ enum DeviceType {
+ DEVICE_TYPE_TOUCH_SCREEN,
+ DEVICE_TYPE_TOUCH_PAD,
+ };
+
+ DeviceType deviceType;
+ int32_t associatedDisplayId;
+ bool orientationAware;
+
bool useBadTouchFilter;
bool useJumpyTouchFilter;
bool useAveragingTouchFilter;
@@ -641,7 +643,7 @@ protected:
bool haveToolSizeAreaBias;
float toolSizeAreaBias;
bool haveToolSizeIsSummed;
- int32_t toolSizeIsSummed;
+ bool toolSizeIsSummed;
// Pressure
enum PressureCalibration {
@@ -846,7 +848,7 @@ private:
class SingleTouchInputMapper : public TouchInputMapper {
public:
- SingleTouchInputMapper(InputDevice* device, int32_t associatedDisplayId);
+ SingleTouchInputMapper(InputDevice* device);
virtual ~SingleTouchInputMapper();
virtual void reset();
@@ -892,7 +894,7 @@ private:
class MultiTouchInputMapper : public TouchInputMapper {
public:
- MultiTouchInputMapper(InputDevice* device, int32_t associatedDisplayId);
+ MultiTouchInputMapper(InputDevice* device);
virtual ~MultiTouchInputMapper();
virtual void reset();
diff --git a/include/ui/Keyboard.h b/include/ui/Keyboard.h
index 3b477c7..689607d 100644
--- a/include/ui/Keyboard.h
+++ b/include/ui/Keyboard.h
@@ -20,6 +20,7 @@
#include <ui/Input.h>
#include <utils/Errors.h>
#include <utils/String8.h>
+#include <utils/PropertyMap.h>
namespace android {
@@ -33,19 +34,23 @@ enum {
};
struct KeyMapInfo {
- String8 keyMapName;
String8 keyLayoutFile;
String8 keyCharacterMapFile;
bool isDefaultKeyMap;
KeyMapInfo() : isDefaultKeyMap(false) {
}
+
+ bool isComplete() {
+ return !keyLayoutFile.isEmpty() && !keyCharacterMapFile.isEmpty();
+ }
};
/**
* Resolves the key map to use for a particular keyboard device.
*/
-extern status_t resolveKeyMap(const String8& deviceName, KeyMapInfo& outKeyMapInfo);
+extern status_t resolveKeyMap(const String8& deviceName,
+ const PropertyMap* deviceConfiguration, KeyMapInfo& outKeyMapInfo);
/**
* Sets keyboard system properties.
diff --git a/include/utils/PropertyMap.h b/include/utils/PropertyMap.h
new file mode 100644
index 0000000..a54f819
--- /dev/null
+++ b/include/utils/PropertyMap.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _UTILS_PROPERTY_MAP_H
+#define _UTILS_PROPERTY_MAP_H
+
+#include <utils/KeyedVector.h>
+#include <utils/String8.h>
+#include <utils/Errors.h>
+#include <utils/Tokenizer.h>
+
+namespace android {
+
+/*
+ * Provides a mechanism for passing around string-based property key / value pairs
+ * and loading them from property files.
+ *
+ * The property files have the following simple structure:
+ *
+ * # Comment
+ * key = value
+ *
+ * Keys and values are any sequence of printable ASCII characters.
+ * The '=' separates the key from the value.
+ * The key and value may not contain whitespace.
+ *
+ * The '\' character is reserved for escape sequences and is not currently supported.
+ * The '"" character is reserved for quoting and is not currently supported.
+ * Files that contain the '\' or '"' character will fail to parse.
+ *
+ * The file must not contain duplicate keys.
+ *
+ * TODO Support escape sequences and quoted values when needed.
+ */
+class PropertyMap {
+public:
+ /* Creates an empty property map. */
+ PropertyMap();
+ ~PropertyMap();
+
+ /* Clears the property map. */
+ void clear();
+
+ /* Adds a property.
+ * Replaces the property with the same key if it is already present.
+ */
+ void addProperty(const String8& key, const String8& value);
+
+ /* Returns true if the property map contains the specified key. */
+ bool hasProperty(const String8& key) const;
+
+ /* Gets the value of a property and parses it.
+ * Returns true and sets outValue if the key was found and its value was parsed successfully.
+ * Otherwise returns false and does not modify outValue. (Also logs a warning.)
+ */
+ bool tryGetProperty(const String8& key, String8& outValue) const;
+ bool tryGetProperty(const String8& key, bool& outValue) const;
+ bool tryGetProperty(const String8& key, int32_t& outValue) const;
+ bool tryGetProperty(const String8& key, float& outValue) const;
+
+ /* Loads a property map from a file. */
+ static status_t load(const String8& filename, PropertyMap** outMap);
+
+private:
+ class Parser {
+ PropertyMap* mMap;
+ Tokenizer* mTokenizer;
+
+ public:
+ Parser(PropertyMap* map, Tokenizer* tokenizer);
+ ~Parser();
+ status_t parse();
+
+ private:
+ status_t parseType();
+ status_t parseKey();
+ status_t parseKeyProperty();
+ status_t parseModifier(const String8& token, int32_t* outMetaState);
+ status_t parseCharacterLiteral(char16_t* outCharacter);
+ };
+
+ KeyedVector<String8, String8> mProperties;
+};
+
+} // namespace android
+
+#endif // _UTILS_PROPERTY_MAP_H
diff --git a/libs/binder/CursorWindow.cpp b/libs/binder/CursorWindow.cpp
index fbba281..47bbd04 100644
--- a/libs/binder/CursorWindow.cpp
+++ b/libs/binder/CursorWindow.cpp
@@ -219,7 +219,8 @@ LOG_WINDOW("follwing 'pointer' to next chunk, offset of next pointer is %d", chu
field_slot_t * CursorWindow::getFieldSlotWithCheck(int row, int column)
{
if (row < 0 || row >= mHeader->numRows || column < 0 || column >= mHeader->numColumns) {
- LOGE("Bad request for field slot %d,%d. numRows = %d, numColumns = %d", row, column, mHeader->numRows, mHeader->numColumns);
+ LOGE("Failed to read row# %d, column# from a CursorWindow which has %d rows, %d columns.",
+ row, column, mHeader->numRows, mHeader->numColumns);
return NULL;
}
row_slot_t * rowSlot = getRowSlot(row);
@@ -238,7 +239,8 @@ field_slot_t * CursorWindow::getFieldSlotWithCheck(int row, int column)
uint32_t CursorWindow::read_field_slot(int row, int column, field_slot_t * slotOut)
{
if (row < 0 || row >= mHeader->numRows || column < 0 || column >= mHeader->numColumns) {
- LOGE("Bad request for field slot %d,%d. numRows = %d, numColumns = %d", row, column, mHeader->numRows, mHeader->numColumns);
+ LOGE("Can't read row# %d, col# %d from CursorWindow. Make sure your Cursor is initialized correctly.",
+ row, column);
return -1;
}
row_slot_t * rowSlot = getRowSlot(row);
diff --git a/libs/hwui/Line.h b/libs/hwui/Line.h
index 5c6f3d8..264fd19 100644
--- a/libs/hwui/Line.h
+++ b/libs/hwui/Line.h
@@ -58,6 +58,8 @@ public:
mXDivs[0] = mYDivs[0] = 2;
mXDivs[1] = mYDivs[1] = 3;
+ mPatch->copy(mXDivs, mYDivs);
+
glGenTextures(1, &mTexture);
glBindTexture(GL_TEXTURE_2D, mTexture);
@@ -89,8 +91,7 @@ public:
const float half = lineWidth * 0.5f;
mPatch->updateVertices(gLineTextureWidth, gLineTextureHeight,
- -gLineAABias, -half - gLineAABias, length + gLineAABias, half + gLineAABias,
- mXDivs, mYDivs, mXDivsCount, mYDivsCount);
+ -gLineAABias, -half - gLineAABias, length + gLineAABias, half + gLineAABias);
tx = -gLineAABias;
ty = lineWidth <= 1.0f ? -gLineAABias : -half - gLineAABias;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index ad72584..60343e0 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -952,6 +952,9 @@ void OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int
mode, texture->blend, (GLvoid*) 0, (GLvoid*) gMeshTextureOffset,
GL_TRIANGLES, mesh->verticesCount, false, false, mesh->meshBuffer,
true, !mesh->hasEmptyQuads);
+ } else {
+ PATCH_LOGD("Invisible 9patch, ignoring (%.2f, %.2f, %.2f, %.2f)",
+ left, top, right, bottom);
}
}
diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp
index 9b2d476..7ca289d 100644
--- a/libs/hwui/Patch.cpp
+++ b/libs/hwui/Patch.cpp
@@ -30,32 +30,81 @@ namespace uirenderer {
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
-Patch::Patch(const uint32_t xCount, const uint32_t yCount, const int8_t emptyQuads) {
+Patch::Patch(const uint32_t xCount, const uint32_t yCount, const int8_t emptyQuads):
+ mXCount(xCount), mYCount(yCount) {
// 2 triangles per patch, 3 vertices per triangle
verticesCount = ((xCount + 1) * (yCount + 1) - emptyQuads) * 2 * 3;
mVertices = new TextureVertex[verticesCount];
hasEmptyQuads = emptyQuads > 0;
+ mUploaded = false;
+
+ mColorKey = 0;
+ mXDivs = new int32_t[mXCount];
+ mYDivs = new int32_t[mYCount];
glGenBuffers(1, &meshBuffer);
}
Patch::~Patch() {
delete[] mVertices;
+ delete[] mXDivs;
+ delete[] mYDivs;
glDeleteBuffers(1, &meshBuffer);
}
///////////////////////////////////////////////////////////////////////////////
+// Patch management
+///////////////////////////////////////////////////////////////////////////////
+
+void Patch::copy(const int32_t* xDivs, const int32_t* yDivs) {
+ memcpy(mXDivs, xDivs, mXCount * sizeof(int32_t));
+ memcpy(mYDivs, yDivs, mYCount * sizeof(int32_t));
+}
+
+void Patch::copy(const int32_t* yDivs) {
+ memcpy(mYDivs, yDivs, mYCount * sizeof(int32_t));
+}
+
+void Patch::updateColorKey(const uint32_t colorKey) {
+ mColorKey = colorKey;
+}
+
+bool Patch::matches(const int32_t* xDivs, const int32_t* yDivs, const uint32_t colorKey) {
+ if (mColorKey != colorKey) {
+ updateColorKey(colorKey);
+ copy(xDivs, yDivs);
+ return false;
+ }
+
+ for (uint32_t i = 0; i < mXCount; i++) {
+ if (mXDivs[i] != xDivs[i]) {
+ // The Y divs may or may not match, copy everything
+ copy(xDivs, yDivs);
+ return false;
+ }
+ }
+
+ for (uint32_t i = 0; i < mYCount; i++) {
+ if (mYDivs[i] != yDivs[i]) {
+ // We know all the X divs match, copy only Y divs
+ copy(yDivs);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
// Vertices management
///////////////////////////////////////////////////////////////////////////////
void Patch::updateVertices(const float bitmapWidth, const float bitmapHeight,
- float left, float top, float right, float bottom,
- const int32_t* xDivs, const int32_t* yDivs,
- const uint32_t width, const uint32_t height, const uint32_t colorKey) {
+ float left, float top, float right, float bottom) {
if (hasEmptyQuads) quads.clear();
- const uint32_t xStretchCount = (width + 1) >> 1;
- const uint32_t yStretchCount = (height + 1) >> 1;
+ const uint32_t xStretchCount = (mXCount + 1) >> 1;
+ const uint32_t yStretchCount = (mYCount + 1) >> 1;
float stretchX = 0.0f;
float stretchY = 0.0;
@@ -64,8 +113,8 @@ void Patch::updateVertices(const float bitmapWidth, const float bitmapHeight,
if (xStretchCount > 0) {
uint32_t stretchSize = 0;
- for (uint32_t i = 1; i < width; i += 2) {
- stretchSize += xDivs[i] - xDivs[i - 1];
+ for (uint32_t i = 1; i < mXCount; i += 2) {
+ stretchSize += mXDivs[i] - mXDivs[i - 1];
}
const float xStretchTex = stretchSize;
const float fixed = bitmapWidth - stretchSize;
@@ -75,8 +124,8 @@ void Patch::updateVertices(const float bitmapWidth, const float bitmapHeight,
if (yStretchCount > 0) {
uint32_t stretchSize = 0;
- for (uint32_t i = 1; i < height; i += 2) {
- stretchSize += yDivs[i] - yDivs[i - 1];
+ for (uint32_t i = 1; i < mYCount; i += 2) {
+ stretchSize += mYDivs[i] - mYDivs[i - 1];
}
const float yStretchTex = stretchSize;
const float fixed = bitmapHeight - stretchSize;
@@ -92,8 +141,8 @@ void Patch::updateVertices(const float bitmapWidth, const float bitmapHeight,
float y1 = 0.0f;
float v1 = 0.0f;
- for (uint32_t i = 0; i < height; i++) {
- float stepY = yDivs[i];
+ for (uint32_t i = 0; i < mYCount; i++) {
+ float stepY = mYDivs[i];
float y2 = 0.0f;
if (i & 1) {
@@ -104,8 +153,7 @@ void Patch::updateVertices(const float bitmapWidth, const float bitmapHeight,
}
float v2 = fmax(0.0f, stepY - 0.5f) / bitmapHeight;
- generateRow(vertex, y1, y2, v1, v2, xDivs, width, stretchX,
- right - left, bitmapWidth, quadCount, colorKey);
+ generateRow(vertex, y1, y2, v1, v2, stretchX, right - left, bitmapWidth, quadCount);
y1 = y2;
v1 = (stepY + 0.5f) / bitmapHeight;
@@ -113,25 +161,30 @@ void Patch::updateVertices(const float bitmapWidth, const float bitmapHeight,
previousStepY = stepY;
}
- generateRow(vertex, y1, bottom - top, v1, 1.0f, xDivs, width, stretchX,
- right - left, bitmapWidth, quadCount, colorKey);
+ generateRow(vertex, y1, bottom - top, v1, 1.0f, stretchX, right - left,
+ bitmapWidth, quadCount);
Caches::getInstance().bindMeshBuffer(meshBuffer);
- glBufferData(GL_ARRAY_BUFFER, sizeof(TextureVertex) * verticesCount,
- mVertices, GL_STATIC_DRAW);
+ if (!mUploaded) {
+ glBufferData(GL_ARRAY_BUFFER, sizeof(TextureVertex) * verticesCount,
+ mVertices, GL_DYNAMIC_DRAW);
+ mUploaded = true;
+ } else {
+ glBufferSubData(GL_ARRAY_BUFFER, 0,
+ sizeof(TextureVertex) * verticesCount, mVertices);
+ }
}
void Patch::generateRow(TextureVertex*& vertex, float y1, float y2, float v1, float v2,
- const int32_t xDivs[], uint32_t xCount, float stretchX, float width, float bitmapWidth,
- uint32_t& quadCount, const uint32_t colorKey) {
+ float stretchX, float width, float bitmapWidth, uint32_t& quadCount) {
float previousStepX = 0.0f;
float x1 = 0.0f;
float u1 = 0.0f;
// Generate the row quad by quad
- for (uint32_t i = 0; i < xCount; i++) {
- float stepX = xDivs[i];
+ for (uint32_t i = 0; i < mXCount; i++) {
+ float stepX = mXDivs[i];
float x2 = 0.0f;
if (i & 1) {
@@ -142,7 +195,7 @@ void Patch::generateRow(TextureVertex*& vertex, float y1, float y2, float v1, fl
}
float u2 = fmax(0.0f, stepX - 0.5f) / bitmapWidth;
- generateQuad(vertex, x1, y1, x2, y2, u1, v1, u2, v2, quadCount, colorKey);
+ generateQuad(vertex, x1, y1, x2, y2, u1, v1, u2, v2, quadCount);
x1 = x2;
u1 = (stepX + 0.5f) / bitmapWidth;
@@ -150,12 +203,12 @@ void Patch::generateRow(TextureVertex*& vertex, float y1, float y2, float v1, fl
previousStepX = stepX;
}
- generateQuad(vertex, x1, y1, width, y2, u1, v1, 1.0f, v2, quadCount, colorKey);
+ generateQuad(vertex, x1, y1, width, y2, u1, v1, 1.0f, v2, quadCount);
}
void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2,
- float u1, float v1, float u2, float v2, uint32_t& quadCount, const uint32_t colorKey) {
- if (((colorKey >> quadCount++) & 0x1) == 1) {
+ float u1, float v1, float u2, float v2, uint32_t& quadCount) {
+ if (((mColorKey >> quadCount++) & 0x1) == 1) {
return;
}
diff --git a/libs/hwui/Patch.h b/libs/hwui/Patch.h
index 1e78b2f..2cb8ecb 100644
--- a/libs/hwui/Patch.h
+++ b/libs/hwui/Patch.h
@@ -35,55 +35,6 @@ namespace uirenderer {
///////////////////////////////////////////////////////////////////////////////
/**
- * Description of a patch.
- */
-struct PatchDescription {
- PatchDescription(): bitmapWidth(0), bitmapHeight(0), pixelWidth(0), pixelHeight(0),
- xCount(0), yCount(0), emptyCount(0), colorKey(0) { }
- PatchDescription(const float bitmapWidth, const float bitmapHeight,
- const float pixelWidth, const float pixelHeight,
- const uint32_t xCount, const uint32_t yCount,
- const int8_t emptyCount, const uint32_t colorKey):
- bitmapWidth(bitmapWidth), bitmapHeight(bitmapHeight),
- pixelWidth(pixelWidth), pixelHeight(pixelHeight),
- xCount(xCount), yCount(yCount),
- emptyCount(emptyCount), colorKey(colorKey) { }
- PatchDescription(const PatchDescription& description):
- bitmapWidth(description.bitmapWidth), bitmapHeight(description.bitmapHeight),
- pixelWidth(description.pixelWidth), pixelHeight(description.pixelHeight),
- xCount(description.xCount), yCount(description.yCount),
- emptyCount(description.emptyCount), colorKey(description.colorKey) { }
-
- float bitmapWidth;
- float bitmapHeight;
- float pixelWidth;
- float pixelHeight;
- uint32_t xCount;
- uint32_t yCount;
- int8_t emptyCount;
- uint32_t colorKey;
-
- bool operator<(const PatchDescription& rhs) const {
- LTE_FLOAT(bitmapWidth) {
- LTE_FLOAT(bitmapHeight) {
- LTE_FLOAT(pixelWidth) {
- LTE_FLOAT(pixelHeight) {
- LTE_INT(xCount) {
- LTE_INT(yCount) {
- LTE_INT(emptyCount) {
- LTE_INT(colorKey) return false;
- }
- }
- }
- }
- }
- }
- }
- return false;
- }
-}; // struct PatchDescription
-
-/**
* An OpenGL patch. This contains an array of vertices and an array of
* indices to render the vertices.
*/
@@ -92,10 +43,11 @@ struct Patch {
~Patch();
void updateVertices(const float bitmapWidth, const float bitmapHeight,
- float left, float top, float right, float bottom,
- const int32_t* xDivs, const int32_t* yDivs,
- const uint32_t width, const uint32_t height,
- const uint32_t colorKey = 0);
+ float left, float top, float right, float bottom);
+
+ void updateColorKey(const uint32_t colorKey);
+ void copy(const int32_t* xDivs, const int32_t* yDivs);
+ bool matches(const int32_t* xDivs, const int32_t* yDivs, const uint32_t colorKey);
GLuint meshBuffer;
uint32_t verticesCount;
@@ -104,15 +56,23 @@ struct Patch {
private:
TextureVertex* mVertices;
+ bool mUploaded;
+
+ uint32_t mXCount;
+ int32_t* mXDivs;
+ uint32_t mYCount;
+ int32_t* mYDivs;
+ uint32_t mColorKey;
+
+ void copy(const int32_t* yDivs);
void generateRow(TextureVertex*& vertex, float y1, float y2,
- float v1, float v2, const int32_t xDivs[], uint32_t xCount,
- float stretchX, float width, float bitmapWidth,
- uint32_t& quadCount, const uint32_t colorKey);
+ float v1, float v2, float stretchX, float width, float bitmapWidth,
+ uint32_t& quadCount);
void generateQuad(TextureVertex*& vertex,
float x1, float y1, float x2, float y2,
float u1, float v1, float u2, float v2,
- uint32_t& quadCount, const uint32_t colorKey);
+ uint32_t& quadCount);
}; // struct Patch
}; // namespace uirenderer
diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp
index 71bab91..9702c3d 100644
--- a/libs/hwui/PatchCache.cpp
+++ b/libs/hwui/PatchCache.cpp
@@ -87,8 +87,9 @@ Patch* PatchCache::get(const float bitmapWidth, const float bitmapHeight,
width, height, pixelWidth, pixelHeight, bitmapWidth, bitmapHeight);
mesh = new Patch(width, height, transparentQuads);
- mesh->updateVertices(bitmapWidth, bitmapHeight, 0.0f, 0.0f,
- pixelWidth, pixelHeight, xDivs, yDivs, width, height, colorKey);
+ mesh->updateColorKey(colorKey);
+ mesh->copy(xDivs, yDivs);
+ mesh->updateVertices(bitmapWidth, bitmapHeight, 0.0f, 0.0f, pixelWidth, pixelHeight);
if (mCache.size() >= mMaxEntries) {
delete mCache.valueAt(mCache.size() - 1);
@@ -96,6 +97,9 @@ Patch* PatchCache::get(const float bitmapWidth, const float bitmapHeight,
}
mCache.add(description, mesh);
+ } else if (!mesh->matches(xDivs, yDivs, colorKey)) {
+ PATCH_LOGD("Patch mesh does not match, refreshing vertices");
+ mesh->updateVertices(bitmapWidth, bitmapHeight, 0.0f, 0.0f, pixelWidth, pixelHeight);
}
return mesh;
diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h
index c38cd99..951fba3 100644
--- a/libs/hwui/PatchCache.h
+++ b/libs/hwui/PatchCache.h
@@ -61,8 +61,65 @@ public:
}
private:
+ /**
+ * Description of a patch.
+ */
+ struct PatchDescription {
+ PatchDescription(): bitmapWidth(0), bitmapHeight(0), pixelWidth(0), pixelHeight(0),
+ xCount(0), yCount(0), emptyCount(0), colorKey(0) {
+ }
+
+ PatchDescription(const float bitmapWidth, const float bitmapHeight,
+ const float pixelWidth, const float pixelHeight,
+ const uint32_t xCount, const uint32_t yCount,
+ const int8_t emptyCount, const uint32_t colorKey):
+ bitmapWidth(bitmapWidth), bitmapHeight(bitmapHeight),
+ pixelWidth(pixelWidth), pixelHeight(pixelHeight),
+ xCount(xCount), yCount(yCount),
+ emptyCount(emptyCount), colorKey(colorKey) {
+ }
+
+ PatchDescription(const PatchDescription& description):
+ bitmapWidth(description.bitmapWidth), bitmapHeight(description.bitmapHeight),
+ pixelWidth(description.pixelWidth), pixelHeight(description.pixelHeight),
+ xCount(description.xCount), yCount(description.yCount),
+ emptyCount(description.emptyCount), colorKey(description.colorKey) {
+ }
+
+ bool operator<(const PatchDescription& rhs) const {
+ LTE_FLOAT(bitmapWidth) {
+ LTE_FLOAT(bitmapHeight) {
+ LTE_FLOAT(pixelWidth) {
+ LTE_FLOAT(pixelHeight) {
+ LTE_INT(xCount) {
+ LTE_INT(yCount) {
+ LTE_INT(emptyCount) {
+ LTE_INT(colorKey) return false;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ private:
+ float bitmapWidth;
+ float bitmapHeight;
+ float pixelWidth;
+ float pixelHeight;
+ uint32_t xCount;
+ uint32_t yCount;
+ int8_t emptyCount;
+ uint32_t colorKey;
+
+ }; // struct PatchDescription
+
uint32_t mMaxEntries;
KeyedVector<PatchDescription, Patch*> mCache;
+
}; // class PatchCache
}; // namespace uirenderer
diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h
index 4f0dff3..ab2db5c8 100644
--- a/libs/rs/rsScriptC.h
+++ b/libs/rs/rsScriptC.h
@@ -21,7 +21,9 @@
#include "RenderScriptEnv.h"
-struct BCCscript;
+namespace bcc {
+class BCCscript;
+}
// ---------------------------------------------------------------------------
namespace android {
@@ -46,7 +48,7 @@ public:
Program_t mProgram;
- BCCscript* mBccScript;
+ bcc::BCCscript* mBccScript;
const Allocation *ptrToAllocation(const void *) const;
diff --git a/libs/ui/EventHub.cpp b/libs/ui/EventHub.cpp
index f468217..b312cda 100644
--- a/libs/ui/EventHub.cpp
+++ b/libs/ui/EventHub.cpp
@@ -93,12 +93,13 @@ static inline const char* toString(bool value) {
EventHub::device_t::device_t(int32_t _id, const char* _path, const char* name)
: id(_id), path(_path), name(name), classes(0)
- , keyBitmask(NULL), layoutMap(NULL), fd(-1), next(NULL) {
+ , keyBitmask(NULL), layoutMap(NULL), configuration(NULL), fd(-1), next(NULL) {
}
EventHub::device_t::~device_t() {
delete [] keyBitmask;
delete layoutMap;
+ delete configuration;
}
EventHub::EventHub(void)
@@ -144,6 +145,16 @@ uint32_t EventHub::getDeviceClasses(int32_t deviceId) const
return device->classes;
}
+void EventHub::getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const {
+ AutoMutex _l(mLock);
+ device_t* device = getDeviceLocked(deviceId);
+ if (device && device->configuration) {
+ *outConfiguration = *device->configuration;
+ } else {
+ outConfiguration->clear();
+ }
+}
+
status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis,
RawAbsoluteAxisInfo* outAxisInfo) const {
outAxisInfo->clear();
@@ -716,6 +727,9 @@ int EventHub::openDevice(const char *deviceName) {
mFDs[mFDCount].events = POLLIN;
mFDs[mFDCount].revents = 0;
+ // Load the configuration file for the device.
+ loadConfiguration(device);
+
// Figure out the kinds of events the device reports.
uint8_t key_bitmask[sizeof_bit_array(KEY_MAX + 1)];
@@ -803,7 +817,6 @@ int EventHub::openDevice(const char *deviceName) {
device->name = name;
// Configure the keymap for the device.
-
configureKeyMap(device);
// Tell the world about the devname (the descriptive name)
@@ -868,9 +881,11 @@ int EventHub::openDevice(const char *deviceName) {
return -1;
}
- LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x\n",
- deviceName, name, device->id, mNumDevicesById, mFDCount, fd, device->classes);
-
+ LOGI("New device: path=%s name=%s id=0x%x (of 0x%x) index=%d fd=%d classes=0x%x "
+ "configuration='%s'\n",
+ deviceName, name, device->id, mNumDevicesById, mFDCount, fd, device->classes,
+ device->configurationFile.string());
+
LOGV("Adding device %s %p at %d, id = %d, classes = 0x%x\n",
deviceName, device, mFDCount, devid, device->classes);
@@ -883,8 +898,24 @@ int EventHub::openDevice(const char *deviceName) {
return 0;
}
+void EventHub::loadConfiguration(device_t* device) {
+ device->configurationFile = getInputDeviceConfigurationFilePath(device->name,
+ INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION);
+ if (device->configurationFile.isEmpty()) {
+ LOGI("No input device configuration file found for device '%s'.",
+ device->name.string());
+ } else {
+ status_t status = PropertyMap::load(device->configurationFile,
+ &device->configuration);
+ if (status) {
+ LOGE("Error loading input device configuration file for device '%s'.",
+ device->name.string());
+ }
+ }
+}
+
void EventHub::configureKeyMap(device_t* device) {
- android::resolveKeyMap(device->name, device->keyMapInfo);
+ android::resolveKeyMap(device->name, device->configuration, device->keyMapInfo);
}
void EventHub::setKeyboardProperties(device_t* device, bool firstKeyboard) {
@@ -1058,12 +1089,12 @@ void EventHub::dump(String8& dump) {
dump.appendFormat(INDENT3 "Path: %s\n", device->path.string());
dump.appendFormat(INDENT3 "IsDefaultKeyMap: %s\n",
toString(device->keyMapInfo.isDefaultKeyMap));
- dump.appendFormat(INDENT3 "KeyMapName: %s\n",
- device->keyMapInfo.keyMapName.string());
dump.appendFormat(INDENT3 "KeyLayoutFile: %s\n",
device->keyMapInfo.keyLayoutFile.string());
dump.appendFormat(INDENT3 "KeyCharacterMapFile: %s\n",
device->keyMapInfo.keyCharacterMapFile.string());
+ dump.appendFormat(INDENT3 "ConfigurationFile: %s\n",
+ device->configurationFile.string());
}
}
} // release lock
diff --git a/libs/ui/Input.cpp b/libs/ui/Input.cpp
index 944a79b..9e697db 100644
--- a/libs/ui/Input.cpp
+++ b/libs/ui/Input.cpp
@@ -7,11 +7,82 @@
//#define LOG_NDEBUG 0
+#define DEBUG_PROBE 0
+
+#include <stdlib.h>
+#include <unistd.h>
+
#include <ui/Input.h>
namespace android {
-// class InputEvent
+static const char* CONFIGURATION_FILE_DIR[] = {
+ "idc/",
+ "keylayout/",
+ "keychars/",
+};
+
+static const char* CONFIGURATION_FILE_EXTENSION[] = {
+ ".idc",
+ ".kl",
+ ".kcm",
+};
+
+static void appendInputDeviceConfigurationFileRelativePath(String8& path,
+ const String8& name, InputDeviceConfigurationFileType type) {
+ path.append(CONFIGURATION_FILE_DIR[type]);
+ for (size_t i = 0; i < name.length(); i++) {
+ char ch = name[i];
+ if (ch == ' ') {
+ ch = '_';
+ }
+ path.append(&ch, 1);
+ }
+ path.append(CONFIGURATION_FILE_EXTENSION[type]);
+}
+
+extern String8 getInputDeviceConfigurationFilePath(
+ const String8& name, InputDeviceConfigurationFileType type) {
+ // Search system repository.
+ String8 path;
+ path.setTo(getenv("ANDROID_ROOT"));
+ path.append("/usr/");
+ appendInputDeviceConfigurationFileRelativePath(path, name, type);
+#if DEBUG_PROBE
+ LOGD("Probing for system provided input device configuration file: path='%s'", path.string());
+#endif
+ if (!access(path.string(), R_OK)) {
+#if DEBUG_PROBE
+ LOGD("Found");
+#endif
+ return path;
+ }
+
+ // Search user repository.
+ // TODO Should only look here if not in safe mode.
+ path.setTo(getenv("ANDROID_DATA"));
+ path.append("/system/devices/");
+ appendInputDeviceConfigurationFileRelativePath(path, name, type);
+#if DEBUG_PROBE
+ LOGD("Probing for system user input device configuration file: path='%s'", path.string());
+#endif
+ if (!access(path.string(), R_OK)) {
+#if DEBUG_PROBE
+ LOGD("Found");
+#endif
+ return path;
+ }
+
+ // Not found.
+#if DEBUG_PROBE
+ LOGD("Probe failed to find input device configuration file: name='%s', type=%d",
+ name.string(), type);
+#endif
+ return String8();
+}
+
+
+// --- InputEvent ---
void InputEvent::initialize(int32_t deviceId, int32_t source) {
mDeviceId = deviceId;
@@ -23,7 +94,7 @@ void InputEvent::initialize(const InputEvent& from) {
mSource = from.mSource;
}
-// class KeyEvent
+// --- KeyEvent ---
bool KeyEvent::hasDefaultAction(int32_t keyCode) {
switch (keyCode) {
@@ -131,7 +202,7 @@ void KeyEvent::initialize(const KeyEvent& from) {
mEventTime = from.mEventTime;
}
-// class MotionEvent
+// --- MotionEvent ---
void MotionEvent::initialize(
int32_t deviceId,
@@ -178,7 +249,7 @@ void MotionEvent::offsetLocation(float xOffset, float yOffset) {
mYOffset += yOffset;
}
-// class InputDeviceInfo
+// --- InputDeviceInfo ---
InputDeviceInfo::InputDeviceInfo() {
initialize(-1, String8("uninitialized device info"));
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index db7d448..0708223 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -2081,9 +2081,22 @@ void InputDispatcher::notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t sou
return;
}
+ if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) {
+ policyFlags |= POLICY_FLAG_VIRTUAL;
+ flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
+ }
+
policyFlags |= POLICY_FLAG_TRUSTED;
- mPolicy->interceptKeyBeforeQueueing(eventTime, deviceId, action, /*byref*/ flags,
- keyCode, scanCode, /*byref*/ policyFlags);
+
+ KeyEvent event;
+ event.initialize(deviceId, source, action, flags, keyCode, scanCode,
+ metaState, 0, downTime, eventTime);
+
+ mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
+
+ if (policyFlags & POLICY_FLAG_WOKE_HERE) {
+ flags |= AKEY_EVENT_FLAG_WOKE_HERE;
+ }
bool needWake;
{ // acquire lock
@@ -2289,17 +2302,22 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event,
return INPUT_EVENT_INJECTION_FAILED;
}
- nsecs_t eventTime = keyEvent->getEventTime();
- int32_t deviceId = keyEvent->getDeviceId();
int32_t flags = keyEvent->getFlags();
- int32_t keyCode = keyEvent->getKeyCode();
- int32_t scanCode = keyEvent->getScanCode();
- mPolicy->interceptKeyBeforeQueueing(eventTime, deviceId, action, /*byref*/ flags,
- keyCode, scanCode, /*byref*/ policyFlags);
+ if (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY) {
+ policyFlags |= POLICY_FLAG_VIRTUAL;
+ }
+
+ mPolicy->interceptKeyBeforeQueueing(keyEvent, /*byref*/ policyFlags);
+
+ if (policyFlags & POLICY_FLAG_WOKE_HERE) {
+ flags |= AKEY_EVENT_FLAG_WOKE_HERE;
+ }
mLock.lock();
- injectedEntry = mAllocator.obtainKeyEntry(eventTime, deviceId, keyEvent->getSource(),
- policyFlags, action, flags, keyCode, scanCode, keyEvent->getMetaState(),
+ injectedEntry = mAllocator.obtainKeyEntry(keyEvent->getEventTime(),
+ keyEvent->getDeviceId(), keyEvent->getSource(),
+ policyFlags, action, flags,
+ keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(),
keyEvent->getRepeatCount(), keyEvent->getDownTime());
break;
}
@@ -2999,12 +3017,14 @@ void InputDispatcher::doNotifyANRLockedInterruptible(
void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
CommandEntry* commandEntry) {
KeyEntry* entry = commandEntry->keyEntry;
- initializeKeyEvent(&mReusableKeyEvent, entry);
+
+ KeyEvent event;
+ initializeKeyEvent(&event, entry);
mLock.unlock();
bool consumed = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputChannel,
- & mReusableKeyEvent, entry->policyFlags);
+ &event, entry->policyFlags);
mLock.lock();
@@ -3025,12 +3045,13 @@ void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(
&& dispatchEntry->hasForegroundTarget()
&& dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) {
KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry);
- initializeKeyEvent(&mReusableKeyEvent, keyEntry);
+ KeyEvent event;
+ initializeKeyEvent(&event, keyEntry);
mLock.unlock();
mPolicy->dispatchUnhandledKey(connection->inputChannel,
- & mReusableKeyEvent, keyEntry->policyFlags);
+ &event, keyEntry->policyFlags);
mLock.lock();
}
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index daff2d0..aa690e5 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -98,64 +98,6 @@ static inline bool sourcesMatchMask(uint32_t sources, uint32_t sourceMask) {
}
-// --- InputDeviceCalibration ---
-
-InputDeviceCalibration::InputDeviceCalibration() {
-}
-
-void InputDeviceCalibration::clear() {
- mProperties.clear();
-}
-
-void InputDeviceCalibration::addProperty(const String8& key, const String8& value) {
- mProperties.add(key, value);
-}
-
-bool InputDeviceCalibration::tryGetProperty(const String8& key, String8& outValue) const {
- ssize_t index = mProperties.indexOfKey(key);
- if (index < 0) {
- return false;
- }
-
- outValue = mProperties.valueAt(index);
- return true;
-}
-
-bool InputDeviceCalibration::tryGetProperty(const String8& key, int32_t& outValue) const {
- String8 stringValue;
- if (! tryGetProperty(key, stringValue) || stringValue.length() == 0) {
- return false;
- }
-
- char* end;
- int value = strtol(stringValue.string(), & end, 10);
- if (*end != '\0') {
- LOGW("Input device calibration key '%s' has invalid value '%s'. Expected an integer.",
- key.string(), stringValue.string());
- return false;
- }
- outValue = value;
- return true;
-}
-
-bool InputDeviceCalibration::tryGetProperty(const String8& key, float& outValue) const {
- String8 stringValue;
- if (! tryGetProperty(key, stringValue) || stringValue.length() == 0) {
- return false;
- }
-
- char* end;
- float value = strtof(stringValue.string(), & end);
- if (*end != '\0') {
- LOGW("Input device calibration key '%s' has invalid value '%s'. Expected a float.",
- key.string(), stringValue.string());
- return false;
- }
- outValue = value;
- return true;
-}
-
-
// --- InputReader ---
InputReader::InputReader(const sp<EventHubInterface>& eventHub,
@@ -274,8 +216,6 @@ void InputReader::removeDevice(int32_t deviceId) {
InputDevice* InputReader::createDevice(int32_t deviceId, const String8& name, uint32_t classes) {
InputDevice* device = new InputDevice(this, deviceId, name);
- const int32_t associatedDisplayId = 0; // FIXME: hardcoded for current single-display devices
-
// Switch-like devices.
if (classes & INPUT_DEVICE_CLASS_SWITCH) {
device->addMapper(new SwitchInputMapper(device));
@@ -295,20 +235,19 @@ InputDevice* InputReader::createDevice(int32_t deviceId, const String8& name, ui
}
if (keyboardSources != 0) {
- device->addMapper(new KeyboardInputMapper(device,
- associatedDisplayId, keyboardSources, keyboardType));
+ device->addMapper(new KeyboardInputMapper(device, keyboardSources, keyboardType));
}
// Trackball-like devices.
if (classes & INPUT_DEVICE_CLASS_TRACKBALL) {
- device->addMapper(new TrackballInputMapper(device, associatedDisplayId));
+ device->addMapper(new TrackballInputMapper(device));
}
// Touchscreen-like devices.
if (classes & INPUT_DEVICE_CLASS_TOUCHSCREEN_MT) {
- device->addMapper(new MultiTouchInputMapper(device, associatedDisplayId));
+ device->addMapper(new MultiTouchInputMapper(device));
} else if (classes & INPUT_DEVICE_CLASS_TOUCHSCREEN) {
- device->addMapper(new SingleTouchInputMapper(device, associatedDisplayId));
+ device->addMapper(new SingleTouchInputMapper(device));
}
return device;
@@ -626,7 +565,7 @@ void InputDevice::addMapper(InputMapper* mapper) {
void InputDevice::configure() {
if (! isIgnored()) {
- mContext->getPolicy()->getInputDeviceCalibration(mName, mCalibration);
+ mContext->getEventHub()->getConfiguration(mId, &mConfiguration);
}
mSources = 0;
@@ -792,9 +731,9 @@ int32_t SwitchInputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCod
// --- KeyboardInputMapper ---
-KeyboardInputMapper::KeyboardInputMapper(InputDevice* device, int32_t associatedDisplayId,
+KeyboardInputMapper::KeyboardInputMapper(InputDevice* device,
uint32_t sources, int32_t keyboardType) :
- InputMapper(device), mAssociatedDisplayId(associatedDisplayId), mSources(sources),
+ InputMapper(device), mSources(sources),
mKeyboardType(keyboardType) {
initializeLocked();
}
@@ -832,7 +771,7 @@ void KeyboardInputMapper::dump(String8& dump) {
{ // acquire lock
AutoMutex _l(mLock);
dump.append(INDENT2 "Keyboard Input Mapper:\n");
- dump.appendFormat(INDENT3 "AssociatedDisplayId: %d\n", mAssociatedDisplayId);
+ dumpParameters(dump);
dump.appendFormat(INDENT3 "KeyboardType: %d\n", mKeyboardType);
dump.appendFormat(INDENT3 "KeyDowns: %d keys currently down\n", mLocked.keyDowns.size());
dump.appendFormat(INDENT3 "MetaState: 0x%0x\n", mLocked.metaState);
@@ -840,6 +779,30 @@ void KeyboardInputMapper::dump(String8& dump) {
} // release lock
}
+
+void KeyboardInputMapper::configure() {
+ InputMapper::configure();
+
+ // Configure basic parameters.
+ configureParameters();
+}
+
+void KeyboardInputMapper::configureParameters() {
+ mParameters.orientationAware = false;
+ getDevice()->getConfiguration().tryGetProperty(String8("keyboard.orientationAware"),
+ mParameters.orientationAware);
+
+ mParameters.associatedDisplayId = mParameters.orientationAware ? 0 : -1;
+}
+
+void KeyboardInputMapper::dumpParameters(String8& dump) {
+ dump.append(INDENT3 "Parameters:\n");
+ dump.appendFormat(INDENT4 "AssociatedDisplayId: %d\n",
+ mParameters.associatedDisplayId);
+ dump.appendFormat(INDENT4 "OrientationAware: %s\n",
+ toString(mParameters.orientationAware));
+}
+
void KeyboardInputMapper::reset() {
for (;;) {
int32_t keyCode, scanCode;
@@ -896,9 +859,10 @@ void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,
if (down) {
// Rotate key codes according to orientation if needed.
// Note: getDisplayInfo is non-reentrant so we can continue holding the lock.
- if (mAssociatedDisplayId >= 0) {
+ if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0) {
int32_t orientation;
- if (!getPolicy()->getDisplayInfo(mAssociatedDisplayId, NULL, NULL, & orientation)) {
+ if (!getPolicy()->getDisplayInfo(mParameters.associatedDisplayId,
+ NULL, NULL, & orientation)) {
orientation = InputReaderPolicyInterface::ROTATION_0;
}
@@ -1011,8 +975,8 @@ void KeyboardInputMapper::updateLedStateForModifierLocked(LockedState::LedState&
// --- TrackballInputMapper ---
-TrackballInputMapper::TrackballInputMapper(InputDevice* device, int32_t associatedDisplayId) :
- InputMapper(device), mAssociatedDisplayId(associatedDisplayId) {
+TrackballInputMapper::TrackballInputMapper(InputDevice* device) :
+ InputMapper(device) {
mXPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
mYPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
mXScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD;
@@ -1039,7 +1003,7 @@ void TrackballInputMapper::dump(String8& dump) {
{ // acquire lock
AutoMutex _l(mLock);
dump.append(INDENT2 "Trackball Input Mapper:\n");
- dump.appendFormat(INDENT3 "AssociatedDisplayId: %d\n", mAssociatedDisplayId);
+ dumpParameters(dump);
dump.appendFormat(INDENT3 "XPrecision: %0.3f\n", mXPrecision);
dump.appendFormat(INDENT3 "YPrecision: %0.3f\n", mYPrecision);
dump.appendFormat(INDENT3 "Down: %s\n", toString(mLocked.down));
@@ -1047,6 +1011,29 @@ void TrackballInputMapper::dump(String8& dump) {
} // release lock
}
+void TrackballInputMapper::configure() {
+ InputMapper::configure();
+
+ // Configure basic parameters.
+ configureParameters();
+}
+
+void TrackballInputMapper::configureParameters() {
+ mParameters.orientationAware = false;
+ getDevice()->getConfiguration().tryGetProperty(String8("trackball.orientationAware"),
+ mParameters.orientationAware);
+
+ mParameters.associatedDisplayId = mParameters.orientationAware ? 0 : -1;
+}
+
+void TrackballInputMapper::dumpParameters(String8& dump) {
+ dump.append(INDENT3 "Parameters:\n");
+ dump.appendFormat(INDENT4 "AssociatedDisplayId: %d\n",
+ mParameters.associatedDisplayId);
+ dump.appendFormat(INDENT4 "OrientationAware: %s\n",
+ toString(mParameters.orientationAware));
+}
+
void TrackballInputMapper::initializeLocked() {
mAccumulator.clear();
@@ -1155,11 +1142,13 @@ void TrackballInputMapper::sync(nsecs_t when) {
pointerCoords.toolMinor = 0;
pointerCoords.orientation = 0;
- if (mAssociatedDisplayId >= 0 && (x != 0.0f || y != 0.0f)) {
+ if (mParameters.orientationAware && mParameters.associatedDisplayId >= 0
+ && (x != 0.0f || y != 0.0f)) {
// Rotate motion based on display orientation if needed.
// Note: getDisplayInfo is non-reentrant so we can continue holding the lock.
int32_t orientation;
- if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, NULL, NULL, & orientation)) {
+ if (! getPolicy()->getDisplayInfo(mParameters.associatedDisplayId,
+ NULL, NULL, & orientation)) {
orientation = InputReaderPolicyInterface::ROTATION_0;
}
@@ -1205,8 +1194,8 @@ int32_t TrackballInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scan
// --- TouchInputMapper ---
-TouchInputMapper::TouchInputMapper(InputDevice* device, int32_t associatedDisplayId) :
- InputMapper(device), mAssociatedDisplayId(associatedDisplayId) {
+TouchInputMapper::TouchInputMapper(InputDevice* device) :
+ InputMapper(device) {
mLocked.surfaceOrientation = -1;
mLocked.surfaceWidth = -1;
mLocked.surfaceHeight = -1;
@@ -1218,7 +1207,15 @@ TouchInputMapper::~TouchInputMapper() {
}
uint32_t TouchInputMapper::getSources() {
- return mAssociatedDisplayId >= 0 ? AINPUT_SOURCE_TOUCHSCREEN : AINPUT_SOURCE_TOUCHPAD;
+ switch (mParameters.deviceType) {
+ case Parameters::DEVICE_TYPE_TOUCH_SCREEN:
+ return AINPUT_SOURCE_TOUCHSCREEN;
+ case Parameters::DEVICE_TYPE_TOUCH_PAD:
+ return AINPUT_SOURCE_TOUCHPAD;
+ default:
+ assert(false);
+ return AINPUT_SOURCE_UNKNOWN;
+ }
}
void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
@@ -1269,7 +1266,6 @@ void TouchInputMapper::dump(String8& dump) {
{ // acquire lock
AutoMutex _l(mLock);
dump.append(INDENT2 "Touch Input Mapper:\n");
- dump.appendFormat(INDENT3 "AssociatedDisplayId: %d\n", mAssociatedDisplayId);
dumpParameters(dump);
dumpVirtualKeysLocked(dump);
dumpRawAxes(dump);
@@ -1339,14 +1335,50 @@ void TouchInputMapper::configureParameters() {
mParameters.useBadTouchFilter = getPolicy()->filterTouchEvents();
mParameters.useAveragingTouchFilter = getPolicy()->filterTouchEvents();
mParameters.useJumpyTouchFilter = getPolicy()->filterJumpyTouchEvents();
+
+ String8 deviceTypeString;
+ mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN;
+ if (getDevice()->getConfiguration().tryGetProperty(String8("touch.deviceType"),
+ deviceTypeString)) {
+ if (deviceTypeString == "touchPad") {
+ mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD;
+ } else if (deviceTypeString != "touchScreen") {
+ LOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string());
+ }
+ }
+ bool isTouchScreen = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN;
+
+ mParameters.orientationAware = isTouchScreen;
+ getDevice()->getConfiguration().tryGetProperty(String8("touch.orientationAware"),
+ mParameters.orientationAware);
+
+ mParameters.associatedDisplayId = mParameters.orientationAware || isTouchScreen ? 0 : -1;
}
void TouchInputMapper::dumpParameters(String8& dump) {
- dump.appendFormat(INDENT3 "UseBadTouchFilter: %s\n",
+ dump.append(INDENT3 "Parameters:\n");
+
+ switch (mParameters.deviceType) {
+ case Parameters::DEVICE_TYPE_TOUCH_SCREEN:
+ dump.append(INDENT4 "DeviceType: touchScreen\n");
+ break;
+ case Parameters::DEVICE_TYPE_TOUCH_PAD:
+ dump.append(INDENT4 "DeviceType: touchPad\n");
+ break;
+ default:
+ assert(false);
+ }
+
+ dump.appendFormat(INDENT4 "AssociatedDisplayId: %d\n",
+ mParameters.associatedDisplayId);
+ dump.appendFormat(INDENT4 "OrientationAware: %s\n",
+ toString(mParameters.orientationAware));
+
+ dump.appendFormat(INDENT4 "UseBadTouchFilter: %s\n",
toString(mParameters.useBadTouchFilter));
- dump.appendFormat(INDENT3 "UseAveragingTouchFilter: %s\n",
+ dump.appendFormat(INDENT4 "UseAveragingTouchFilter: %s\n",
toString(mParameters.useAveragingTouchFilter));
- dump.appendFormat(INDENT3 "UseJumpyTouchFilter: %s\n",
+ dump.appendFormat(INDENT4 "UseJumpyTouchFilter: %s\n",
toString(mParameters.useJumpyTouchFilter));
}
@@ -1384,17 +1416,20 @@ void TouchInputMapper::dumpRawAxes(String8& dump) {
bool TouchInputMapper::configureSurfaceLocked() {
// Update orientation and dimensions if needed.
- int32_t orientation;
- int32_t width, height;
- if (mAssociatedDisplayId >= 0) {
+ int32_t orientation = InputReaderPolicyInterface::ROTATION_0;
+ int32_t width = mRawAxes.x.getRange();
+ int32_t height = mRawAxes.y.getRange();
+
+ if (mParameters.associatedDisplayId >= 0) {
+ bool wantSize = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN;
+ bool wantOrientation = mParameters.orientationAware;
+
// Note: getDisplayInfo is non-reentrant so we can continue holding the lock.
- if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, & width, & height, & orientation)) {
+ if (! getPolicy()->getDisplayInfo(mParameters.associatedDisplayId,
+ wantSize ? &width : NULL, wantSize ? &height : NULL,
+ wantOrientation ? &orientation : NULL)) {
return false;
}
- } else {
- orientation = InputReaderPolicyInterface::ROTATION_0;
- width = mRawAxes.x.getRange();
- height = mRawAxes.y.getRange();
}
bool orientationChanged = mLocked.surfaceOrientation != orientation;
@@ -1686,7 +1721,7 @@ void TouchInputMapper::dumpVirtualKeysLocked(String8& dump) {
}
void TouchInputMapper::parseCalibration() {
- const InputDeviceCalibration& in = getDevice()->getCalibration();
+ const PropertyMap& in = getDevice()->getConfiguration();
Calibration& out = mCalibration;
// Position
@@ -1972,8 +2007,8 @@ void TouchInputMapper::dumpCalibration(String8& dump) {
}
if (mCalibration.haveToolSizeIsSummed) {
- dump.appendFormat(INDENT4 "touch.toolSize.isSummed: %d\n",
- mCalibration.toolSizeIsSummed);
+ dump.appendFormat(INDENT4 "touch.toolSize.isSummed: %s\n",
+ toString(mCalibration.toolSizeIsSummed));
}
// Pressure
@@ -3157,8 +3192,8 @@ bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCode
// --- SingleTouchInputMapper ---
-SingleTouchInputMapper::SingleTouchInputMapper(InputDevice* device, int32_t associatedDisplayId) :
- TouchInputMapper(device, associatedDisplayId) {
+SingleTouchInputMapper::SingleTouchInputMapper(InputDevice* device) :
+ TouchInputMapper(device) {
initialize();
}
@@ -3286,8 +3321,8 @@ void SingleTouchInputMapper::configureRawAxes() {
// --- MultiTouchInputMapper ---
-MultiTouchInputMapper::MultiTouchInputMapper(InputDevice* device, int32_t associatedDisplayId) :
- TouchInputMapper(device, associatedDisplayId) {
+MultiTouchInputMapper::MultiTouchInputMapper(InputDevice* device) :
+ TouchInputMapper(device) {
initialize();
}
diff --git a/libs/ui/Keyboard.cpp b/libs/ui/Keyboard.cpp
index de76e25..a4cc22d 100644
--- a/libs/ui/Keyboard.cpp
+++ b/libs/ui/Keyboard.cpp
@@ -28,74 +28,79 @@
namespace android {
-static void selectKeyMap(KeyMapInfo& keyMapInfo, const String8& keyMapName, bool defaultKeyMap) {
- if (keyMapInfo.keyMapName.isEmpty()) {
- keyMapInfo.keyMapName.setTo(keyMapName);
- keyMapInfo.isDefaultKeyMap = defaultKeyMap;
- }
-}
-
static bool probeKeyMap(KeyMapInfo& keyMapInfo, const String8& keyMapName, bool defaultKeyMap) {
- const char* root = getenv("ANDROID_ROOT");
-
- // TODO Consider also looking somewhere in a writeable partition like /data for a
- // custom keymap supplied by the user for this device.
- bool haveKeyLayout = !keyMapInfo.keyLayoutFile.isEmpty();
- if (!haveKeyLayout) {
- keyMapInfo.keyLayoutFile.setTo(root);
- keyMapInfo.keyLayoutFile.append("/usr/keylayout/");
- keyMapInfo.keyLayoutFile.append(keyMapName);
- keyMapInfo.keyLayoutFile.append(".kl");
- if (access(keyMapInfo.keyLayoutFile.string(), R_OK)) {
- keyMapInfo.keyLayoutFile.clear();
- } else {
- haveKeyLayout = true;
+ bool foundOne = false;
+ if (keyMapInfo.keyLayoutFile.isEmpty()) {
+ keyMapInfo.keyLayoutFile.setTo(getInputDeviceConfigurationFilePath(keyMapName,
+ INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT));
+ if (!keyMapInfo.keyLayoutFile.isEmpty()) {
+ foundOne = true;
}
}
- bool haveKeyCharacterMap = !keyMapInfo.keyCharacterMapFile.isEmpty();
- if (!haveKeyCharacterMap) {
- keyMapInfo.keyCharacterMapFile.setTo(root);
- keyMapInfo.keyCharacterMapFile.append("/usr/keychars/");
- keyMapInfo.keyCharacterMapFile.append(keyMapName);
- keyMapInfo.keyCharacterMapFile.append(".kcm");
- if (access(keyMapInfo.keyCharacterMapFile.string(), R_OK)) {
- keyMapInfo.keyCharacterMapFile.clear();
- } else {
- haveKeyCharacterMap = true;
+ if (keyMapInfo.keyCharacterMapFile.isEmpty()) {
+ keyMapInfo.keyCharacterMapFile.setTo(getInputDeviceConfigurationFilePath(keyMapName,
+ INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP));
+ if (!keyMapInfo.keyCharacterMapFile.isEmpty()) {
+ foundOne = true;
}
}
- if (haveKeyLayout || haveKeyCharacterMap) {
- selectKeyMap(keyMapInfo, keyMapName, defaultKeyMap);
+ if (foundOne && defaultKeyMap) {
+ keyMapInfo.isDefaultKeyMap = true;
}
- return haveKeyLayout && haveKeyCharacterMap;
+ return keyMapInfo.isComplete();
}
-status_t resolveKeyMap(const String8& deviceName, KeyMapInfo& outKeyMapInfo) {
- // As an initial key map name, try using the device name.
- String8 keyMapName(deviceName);
- char* p = keyMapName.lockBuffer(keyMapName.size());
- while (*p) {
- if (*p == ' ') *p = '_';
- p++;
- }
- keyMapName.unlockBuffer();
+status_t resolveKeyMap(const String8& deviceName,
+ const PropertyMap* deviceConfiguration, KeyMapInfo& outKeyMapInfo) {
+ // Use the configured key layout if available.
+ if (deviceConfiguration) {
+ String8 keyLayoutName;
+ if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"),
+ keyLayoutName)) {
+ outKeyMapInfo.keyLayoutFile.setTo(getInputDeviceConfigurationFilePath(
+ keyLayoutName, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT));
+ if (outKeyMapInfo.keyLayoutFile.isEmpty()) {
+ LOGW("Configuration for keyboard device '%s' requested keyboard layout '%s' but "
+ "it was not found.",
+ deviceName.string(), keyLayoutName.string());
+ }
+ }
- if (probeKeyMap(outKeyMapInfo, keyMapName, false)) return OK;
+ String8 keyCharacterMapName;
+ if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"),
+ keyCharacterMapName)) {
+ outKeyMapInfo.keyCharacterMapFile.setTo(getInputDeviceConfigurationFilePath(
+ keyCharacterMapName, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP));
+ if (outKeyMapInfo.keyCharacterMapFile.isEmpty()) {
+ LOGW("Configuration for keyboard device '%s' requested keyboard character "
+ "map '%s' but it was not found.",
+ deviceName.string(), keyCharacterMapName.string());
+ }
+ }
- // TODO Consider allowing the user to configure a specific key map somehow.
+ if (outKeyMapInfo.isComplete()) {
+ return OK;
+ }
+ }
+
+ // Try searching by device name.
+ if (probeKeyMap(outKeyMapInfo, deviceName, false)) {
+ return OK;
+ }
- // Try the Generic key map.
+ // Fall back on the Generic key map.
// TODO Apply some additional heuristics here to figure out what kind of
// generic key map to use (US English, etc.).
- keyMapName.setTo("Generic");
- if (probeKeyMap(outKeyMapInfo, keyMapName, true)) return OK;
+ if (probeKeyMap(outKeyMapInfo, String8("Generic"), true)) {
+ return OK;
+ }
// Give up!
- keyMapName.setTo("unknown");
- selectKeyMap(outKeyMapInfo, keyMapName, true);
- LOGE("Could not determine key map for device '%s'.", deviceName.string());
+ LOGE("Could not determine key map for device '%s' and the Generic key map was not found!",
+ deviceName.string());
+ outKeyMapInfo.isDefaultKeyMap = true;
return NAME_NOT_FOUND;
}
@@ -104,8 +109,6 @@ void setKeyboardProperties(int32_t deviceId, const String8& deviceName,
char propName[PROPERTY_KEY_MAX];
snprintf(propName, sizeof(propName), "hw.keyboards.%u.devname", deviceId);
property_set(propName, deviceName.string());
- snprintf(propName, sizeof(propName), "hw.keyboards.%u.keymap", deviceId);
- property_set(propName, keyMapInfo.keyMapName.string());
snprintf(propName, sizeof(propName), "hw.keyboards.%u.klfile", deviceId);
property_set(propName, keyMapInfo.keyLayoutFile.string());
snprintf(propName, sizeof(propName), "hw.keyboards.%u.kcmfile", deviceId);
@@ -116,8 +119,6 @@ void clearKeyboardProperties(int32_t deviceId) {
char propName[PROPERTY_KEY_MAX];
snprintf(propName, sizeof(propName), "hw.keyboards.%u.devname", deviceId);
property_set(propName, "");
- snprintf(propName, sizeof(propName), "hw.keyboards.%u.keymap", deviceId);
- property_set(propName, "");
snprintf(propName, sizeof(propName), "hw.keyboards.%u.klfile", deviceId);
property_set(propName, "");
snprintf(propName, sizeof(propName), "hw.keyboards.%u.kcmfile", deviceId);
@@ -125,6 +126,14 @@ void clearKeyboardProperties(int32_t deviceId) {
}
status_t getKeyCharacterMapFile(int32_t deviceId, String8& outKeyCharacterMapFile) {
+ if (deviceId == DEVICE_ID_VIRTUAL_KEYBOARD) {
+ outKeyCharacterMapFile.setTo(getInputDeviceConfigurationFilePath(String8("Virtual"),
+ INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP));
+ if (!outKeyCharacterMapFile.isEmpty()) {
+ return OK;
+ }
+ }
+
char propName[PROPERTY_KEY_MAX];
char fn[PROPERTY_VALUE_MAX];
snprintf(propName, sizeof(propName), "hw.keyboards.%u.kcmfile", deviceId);
@@ -133,23 +142,13 @@ status_t getKeyCharacterMapFile(int32_t deviceId, String8& outKeyCharacterMapFil
return OK;
}
- const char* root = getenv("ANDROID_ROOT");
- char path[PATH_MAX];
- if (deviceId == DEVICE_ID_VIRTUAL_KEYBOARD) {
- snprintf(path, sizeof(path), "%s/usr/keychars/Virtual.kcm", root);
- if (!access(path, R_OK)) {
- outKeyCharacterMapFile.setTo(path);
- return OK;
- }
- }
-
- snprintf(path, sizeof(path), "%s/usr/keychars/Generic.kcm", root);
- if (!access(path, R_OK)) {
- outKeyCharacterMapFile.setTo(path);
+ outKeyCharacterMapFile.setTo(getInputDeviceConfigurationFilePath(String8("Generic"),
+ INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP));
+ if (!outKeyCharacterMapFile.isEmpty()) {
return OK;
}
- LOGE("Can't find any key character map files (also tried %s)", path);
+ LOGE("Can't find any key character map files (also tried Virtual and Generic key maps)");
return NAME_NOT_FOUND;
}
diff --git a/libs/ui/tests/InputDispatcher_test.cpp b/libs/ui/tests/InputDispatcher_test.cpp
index f352dbf..68f9037 100644
--- a/libs/ui/tests/InputDispatcher_test.cpp
+++ b/libs/ui/tests/InputDispatcher_test.cpp
@@ -54,9 +54,7 @@ private:
return 60;
}
- virtual void interceptKeyBeforeQueueing(nsecs_t when, int32_t deviceId,
- int32_t action, int32_t& flags, int32_t keyCode, int32_t scanCode,
- uint32_t& policyFlags) {
+ virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) {
}
virtual void interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags) {
diff --git a/libs/ui/tests/InputReader_test.cpp b/libs/ui/tests/InputReader_test.cpp
index ded0225..05bebc5 100644
--- a/libs/ui/tests/InputReader_test.cpp
+++ b/libs/ui/tests/InputReader_test.cpp
@@ -43,7 +43,6 @@ class FakeInputReaderPolicy : public InputReaderPolicyInterface {
bool mFilterTouchEvents;
bool mFilterJumpyTouchEvents;
KeyedVector<String8, Vector<VirtualKeyDefinition> > mVirtualKeyDefinitions;
- KeyedVector<String8, InputDeviceCalibration> mInputDeviceCalibrations;
Vector<String8> mExcludedDeviceNames;
protected:
@@ -76,20 +75,6 @@ public:
mFilterJumpyTouchEvents = enabled;
}
- void addInputDeviceCalibration(const String8& deviceName,
- const InputDeviceCalibration& calibration) {
- mInputDeviceCalibrations.add(deviceName, calibration);
- }
-
- void addInputDeviceCalibrationProperty(const String8& deviceName,
- const String8& key, const String8& value) {
- ssize_t index = mInputDeviceCalibrations.indexOfKey(deviceName);
- if (index < 0) {
- index = mInputDeviceCalibrations.add(deviceName, InputDeviceCalibration());
- }
- mInputDeviceCalibrations.editValueAt(index).addProperty(key, value);
- }
-
void addVirtualKeyDefinition(const String8& deviceName,
const VirtualKeyDefinition& definition) {
if (mVirtualKeyDefinitions.indexOfKey(deviceName) < 0) {
@@ -139,14 +124,6 @@ private:
}
}
- virtual void getInputDeviceCalibration(const String8& deviceName,
- InputDeviceCalibration& outCalibration) {
- ssize_t index = mInputDeviceCalibrations.indexOfKey(deviceName);
- if (index >= 0) {
- outCalibration = mInputDeviceCalibrations.valueAt(index);
- }
- }
-
virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) {
outExcludedDeviceNames.appendVector(mExcludedDeviceNames);
}
@@ -371,6 +348,7 @@ class FakeEventHub : public EventHubInterface {
struct Device {
String8 name;
uint32_t classes;
+ PropertyMap configuration;
KeyedVector<int, RawAbsoluteAxisInfo> axes;
KeyedVector<int32_t, int32_t> keyCodeStates;
KeyedVector<int32_t, int32_t> scanCodeStates;
@@ -415,6 +393,11 @@ public:
enqueueEvent(ARBITRARY_TIME, 0, EventHubInterface::FINISHED_DEVICE_SCAN, 0, 0, 0, 0);
}
+ void addConfigurationProperty(int32_t deviceId, const String8& key, const String8& value) {
+ Device* device = getDevice(deviceId);
+ device->configuration.addProperty(key, value);
+ }
+
void addAxis(int32_t deviceId, int axis,
int32_t minValue, int32_t maxValue, int flat, int fuzz) {
Device* device = getDevice(deviceId);
@@ -499,6 +482,13 @@ private:
return device ? device->name : String8("unknown");
}
+ virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const {
+ Device* device = getDevice(deviceId);
+ if (device) {
+ *outConfiguration = device->configuration;
+ }
+ }
+
virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
RawAbsoluteAxisInfo* outAxisInfo) const {
Device* device = getDevice(deviceId);
@@ -1208,9 +1198,7 @@ TEST_F(InputDeviceTest, WhenNoMappersAreRegistered_DeviceIsIgnored) {
TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRequestsToMappers) {
// Configuration.
- InputDeviceCalibration calibration;
- calibration.addProperty(String8("key"), String8("value"));
- mFakePolicy->addInputDeviceCalibration(String8(DEVICE_NAME), calibration);
+ mFakeEventHub->addConfigurationProperty(DEVICE_ID, String8("key"), String8("value"));
FakeInputMapper* mapper1 = new FakeInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD);
mapper1->setKeyboardType(AINPUT_KEYBOARD_TYPE_ALPHABETIC);
@@ -1231,8 +1219,8 @@ TEST_F(InputDeviceTest, WhenMappersAreRegistered_DeviceIsNotIgnoredAndForwardsRe
mDevice->configure();
String8 propertyValue;
- ASSERT_TRUE(mDevice->getCalibration().tryGetProperty(String8("key"), propertyValue))
- << "Device should have read calibration during configuration phase.";
+ ASSERT_TRUE(mDevice->getConfiguration().tryGetProperty(String8("key"), propertyValue))
+ << "Device should have read configuration during configuration phase.";
ASSERT_STREQ("value", propertyValue.string());
ASSERT_NO_FATAL_FAILURE(mapper1->assertConfigureWasCalled());
@@ -1329,9 +1317,8 @@ protected:
mFakeEventHub.clear();
}
- void prepareCalibration(const char* key, const char* value) {
- mFakePolicy->addInputDeviceCalibrationProperty(String8(DEVICE_NAME),
- String8(key), String8(value));
+ void addConfigurationProperty(const char* key, const char* value) {
+ mFakeEventHub->addConfigurationProperty(DEVICE_ID, String8(key), String8(value));
}
void addMapperAndConfigure(InputMapper* mapper) {
@@ -1448,7 +1435,7 @@ void KeyboardInputMapperTest::testDPadKeyRotation(KeyboardInputMapper* mapper,
TEST_F(KeyboardInputMapperTest, GetSources) {
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1,
+ KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
addMapperAndConfigure(mapper);
@@ -1456,7 +1443,7 @@ TEST_F(KeyboardInputMapperTest, GetSources) {
}
TEST_F(KeyboardInputMapperTest, Process_SimpleKeyPress) {
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1,
+ KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
addMapperAndConfigure(mapper);
@@ -1493,7 +1480,7 @@ TEST_F(KeyboardInputMapperTest, Process_SimpleKeyPress) {
}
TEST_F(KeyboardInputMapperTest, Reset_WhenKeysAreNotDown_DoesNotSynthesizeKeyUp) {
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1,
+ KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
addMapperAndConfigure(mapper);
@@ -1513,7 +1500,7 @@ TEST_F(KeyboardInputMapperTest, Reset_WhenKeysAreNotDown_DoesNotSynthesizeKeyUp)
}
TEST_F(KeyboardInputMapperTest, Reset_WhenKeysAreDown_SynthesizesKeyUps) {
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1,
+ KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
addMapperAndConfigure(mapper);
@@ -1558,7 +1545,7 @@ TEST_F(KeyboardInputMapperTest, Reset_WhenKeysAreDown_SynthesizesKeyUps) {
}
TEST_F(KeyboardInputMapperTest, Process_ShouldUpdateMetaState) {
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1,
+ KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
addMapperAndConfigure(mapper);
@@ -1597,11 +1584,14 @@ TEST_F(KeyboardInputMapperTest, Process_ShouldUpdateMetaState) {
ASSERT_NO_FATAL_FAILURE(mFakeContext->assertUpdateGlobalMetaStateWasCalled());
}
-TEST_F(KeyboardInputMapperTest, Process_WhenNotAttachedToDisplay_ShouldNotRotateDPad) {
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1,
+TEST_F(KeyboardInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateDPad) {
+ KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
addMapperAndConfigure(mapper);
+ mFakePolicy->setDisplayInfo(DISPLAY_ID,
+ DISPLAY_WIDTH, DISPLAY_HEIGHT,
+ InputReaderPolicyInterface::ROTATION_90);
ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP));
ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
@@ -1612,9 +1602,10 @@ TEST_F(KeyboardInputMapperTest, Process_WhenNotAttachedToDisplay_ShouldNotRotate
KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_LEFT));
}
-TEST_F(KeyboardInputMapperTest, Process_WhenAttachedToDisplay_ShouldRotateDPad) {
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, DISPLAY_ID,
+TEST_F(KeyboardInputMapperTest, Process_WhenOrientationAware_ShouldRotateDPad) {
+ KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+ addConfigurationProperty("keyboard.orientationAware", "1");
addMapperAndConfigure(mapper);
mFakePolicy->setDisplayInfo(DISPLAY_ID,
@@ -1689,7 +1680,7 @@ TEST_F(KeyboardInputMapperTest, Process_WhenAttachedToDisplay_ShouldRotateDPad)
}
TEST_F(KeyboardInputMapperTest, GetKeyCodeState) {
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1,
+ KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
addMapperAndConfigure(mapper);
@@ -1701,7 +1692,7 @@ TEST_F(KeyboardInputMapperTest, GetKeyCodeState) {
}
TEST_F(KeyboardInputMapperTest, GetScanCodeState) {
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1,
+ KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
addMapperAndConfigure(mapper);
@@ -1713,7 +1704,7 @@ TEST_F(KeyboardInputMapperTest, GetScanCodeState) {
}
TEST_F(KeyboardInputMapperTest, MarkSupportedKeyCodes) {
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1,
+ KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
addMapperAndConfigure(mapper);
@@ -1731,7 +1722,7 @@ TEST_F(KeyboardInputMapperTest, Process_LockedKeysShouldToggleMetaStateAndLeds)
mFakeEventHub->addLed(DEVICE_ID, LED_NUML, false /*initially off*/);
mFakeEventHub->addLed(DEVICE_ID, LED_SCROLLL, false /*initially off*/);
- KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, -1,
+ KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
addMapperAndConfigure(mapper);
@@ -1830,14 +1821,14 @@ void TrackballInputMapperTest::testMotionRotation(TrackballInputMapper* mapper,
}
TEST_F(TrackballInputMapperTest, GetSources) {
- TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1);
+ TrackballInputMapper* mapper = new TrackballInputMapper(mDevice);
addMapperAndConfigure(mapper);
ASSERT_EQ(AINPUT_SOURCE_TRACKBALL, mapper->getSources());
}
TEST_F(TrackballInputMapperTest, PopulateDeviceInfo) {
- TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1);
+ TrackballInputMapper* mapper = new TrackballInputMapper(mDevice);
addMapperAndConfigure(mapper);
InputDeviceInfo info;
@@ -1850,7 +1841,7 @@ TEST_F(TrackballInputMapperTest, PopulateDeviceInfo) {
}
TEST_F(TrackballInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaState) {
- TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1);
+ TrackballInputMapper* mapper = new TrackballInputMapper(mDevice);
addMapperAndConfigure(mapper);
mFakeContext->setGlobalMetaState(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_ON);
@@ -1898,7 +1889,7 @@ TEST_F(TrackballInputMapperTest, Process_ShouldSetAllFieldsAndIncludeGlobalMetaS
}
TEST_F(TrackballInputMapperTest, Process_ShouldHandleIndependentXYUpdates) {
- TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1);
+ TrackballInputMapper* mapper = new TrackballInputMapper(mDevice);
addMapperAndConfigure(mapper);
FakeInputDispatcher::NotifyMotionArgs args;
@@ -1922,7 +1913,7 @@ TEST_F(TrackballInputMapperTest, Process_ShouldHandleIndependentXYUpdates) {
}
TEST_F(TrackballInputMapperTest, Process_ShouldHandleIndependentButtonUpdates) {
- TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1);
+ TrackballInputMapper* mapper = new TrackballInputMapper(mDevice);
addMapperAndConfigure(mapper);
FakeInputDispatcher::NotifyMotionArgs args;
@@ -1943,7 +1934,7 @@ TEST_F(TrackballInputMapperTest, Process_ShouldHandleIndependentButtonUpdates) {
}
TEST_F(TrackballInputMapperTest, Process_ShouldHandleCombinedXYAndButtonUpdates) {
- TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1);
+ TrackballInputMapper* mapper = new TrackballInputMapper(mDevice);
addMapperAndConfigure(mapper);
FakeInputDispatcher::NotifyMotionArgs args;
@@ -1978,7 +1969,7 @@ TEST_F(TrackballInputMapperTest, Process_ShouldHandleCombinedXYAndButtonUpdates)
}
TEST_F(TrackballInputMapperTest, Reset_WhenButtonIsNotDown_ShouldNotSynthesizeButtonUp) {
- TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1);
+ TrackballInputMapper* mapper = new TrackballInputMapper(mDevice);
addMapperAndConfigure(mapper);
FakeInputDispatcher::NotifyMotionArgs args;
@@ -1998,7 +1989,7 @@ TEST_F(TrackballInputMapperTest, Reset_WhenButtonIsNotDown_ShouldNotSynthesizeBu
}
TEST_F(TrackballInputMapperTest, Reset_WhenButtonIsDown_ShouldSynthesizeButtonUp) {
- TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1);
+ TrackballInputMapper* mapper = new TrackballInputMapper(mDevice);
addMapperAndConfigure(mapper);
FakeInputDispatcher::NotifyMotionArgs args;
@@ -2016,10 +2007,13 @@ TEST_F(TrackballInputMapperTest, Reset_WhenButtonIsDown_ShouldSynthesizeButtonUp
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
}
-TEST_F(TrackballInputMapperTest, Process_WhenNotAttachedToDisplay_ShouldNotRotateMotions) {
- TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, -1);
+TEST_F(TrackballInputMapperTest, Process_WhenNotOrientationAware_ShouldNotRotateMotions) {
+ TrackballInputMapper* mapper = new TrackballInputMapper(mDevice);
addMapperAndConfigure(mapper);
+ mFakePolicy->setDisplayInfo(DISPLAY_ID,
+ DISPLAY_WIDTH, DISPLAY_HEIGHT,
+ InputReaderPolicyInterface::ROTATION_90);
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 0, 1, 0, 1));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 1, 1, 1));
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, 1, 0, 1, 0));
@@ -2030,8 +2024,9 @@ TEST_F(TrackballInputMapperTest, Process_WhenNotAttachedToDisplay_ShouldNotRotat
ASSERT_NO_FATAL_FAILURE(testMotionRotation(mapper, -1, 1, -1, 1));
}
-TEST_F(TrackballInputMapperTest, Process_WhenAttachedToDisplay_ShouldRotateMotions) {
- TrackballInputMapper* mapper = new TrackballInputMapper(mDevice, DISPLAY_ID);
+TEST_F(TrackballInputMapperTest, Process_WhenOrientationAware_ShouldRotateMotions) {
+ TrackballInputMapper* mapper = new TrackballInputMapper(mDevice);
+ addConfigurationProperty("trackball.orientationAware", "1");
addMapperAndConfigure(mapper);
mFakePolicy->setDisplayInfo(DISPLAY_ID,
@@ -2232,24 +2227,26 @@ void SingleTouchInputMapperTest::processSync(SingleTouchInputMapper* mapper) {
}
-TEST_F(SingleTouchInputMapperTest, GetSources_WhenNotAttachedToADisplay_ReturnsTouchPad) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, -1);
+TEST_F(SingleTouchInputMapperTest, GetSources_WhenDisplayTypeIsTouchPad_ReturnsTouchPad) {
+ SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
prepareAxes(POSITION);
+ addConfigurationProperty("touch.displayType", "touchPad");
addMapperAndConfigure(mapper);
ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper->getSources());
}
-TEST_F(SingleTouchInputMapperTest, GetSources_WhenAttachedToADisplay_ReturnsTouchScreen) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID);
+TEST_F(SingleTouchInputMapperTest, GetSources_WhenDisplayTypeIsTouchScreen_ReturnsTouchScreen) {
+ SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
prepareAxes(POSITION);
+ addConfigurationProperty("touch.displayType", "touchScreen");
addMapperAndConfigure(mapper);
ASSERT_EQ(AINPUT_SOURCE_TOUCHSCREEN, mapper->getSources());
}
TEST_F(SingleTouchInputMapperTest, GetKeyCodeState) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID);
+ SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
@@ -2276,7 +2273,7 @@ TEST_F(SingleTouchInputMapperTest, GetKeyCodeState) {
}
TEST_F(SingleTouchInputMapperTest, GetScanCodeState) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID);
+ SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
@@ -2303,7 +2300,7 @@ TEST_F(SingleTouchInputMapperTest, GetScanCodeState) {
}
TEST_F(SingleTouchInputMapperTest, MarkSupportedKeyCodes) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID);
+ SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
@@ -2319,7 +2316,7 @@ TEST_F(SingleTouchInputMapperTest, MarkSupportedKeyCodes) {
TEST_F(SingleTouchInputMapperTest, Reset_WhenVirtualKeysAreDown_SendsUp) {
// Note: Ideally we should send cancels but the implementation is more straightforward
// with up and this will only happen if a device is forcibly removed.
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID);
+ SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
@@ -2352,7 +2349,7 @@ TEST_F(SingleTouchInputMapperTest, Reset_WhenVirtualKeysAreDown_SendsUp) {
}
TEST_F(SingleTouchInputMapperTest, Reset_WhenNothingIsPressed_NothingMuchHappens) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID);
+ SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
@@ -2378,7 +2375,7 @@ TEST_F(SingleTouchInputMapperTest, Reset_WhenNothingIsPressed_NothingMuchHappens
}
TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndReleasedNormally_SendsKeyDownAndKeyUp) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID);
+ SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
@@ -2427,7 +2424,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndReleasedNor
}
TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndMovedOutOfBounds_SendsKeyDownAndKeyCancel) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID);
+ SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
@@ -2541,7 +2538,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenVirtualKeyIsPressedAndMovedOutOfB
}
TEST_F(SingleTouchInputMapperTest, Process_WhenTouchStartsOutsideDisplayAndMovesIn_SendsDownAsTouchEntersDisplay) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID);
+ SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
@@ -2609,7 +2606,7 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenTouchStartsOutsideDisplayAndMoves
}
TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID);
+ SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
@@ -2691,8 +2688,30 @@ TEST_F(SingleTouchInputMapperTest, Process_NormalSingleTouchGesture) {
ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasNotCalled());
}
-TEST_F(SingleTouchInputMapperTest, Process_Rotation) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID);
+TEST_F(SingleTouchInputMapperTest, Process_WhenNotOrientationAware_DoesNotRotateMotions) {
+ SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
+ prepareAxes(POSITION);
+ addConfigurationProperty("touch.orientationAware", "0");
+ addMapperAndConfigure(mapper);
+
+ FakeInputDispatcher::NotifyMotionArgs args;
+
+ // Rotation 90.
+ prepareDisplay(InputReaderPolicyInterface::ROTATION_90);
+ processDown(mapper, toRawX(50), toRawY(75));
+ processSync(mapper);
+
+ ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args));
+ ASSERT_NEAR(50, args.pointerCoords[0].x, 1);
+ ASSERT_NEAR(75, args.pointerCoords[0].y, 1);
+
+ processUp(mapper);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled());
+}
+
+TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_RotatesMotions) {
+ SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
prepareAxes(POSITION);
addMapperAndConfigure(mapper);
@@ -2752,7 +2771,7 @@ TEST_F(SingleTouchInputMapperTest, Process_Rotation) {
}
TEST_F(SingleTouchInputMapperTest, Process_AllAxes_DefaultCalibration) {
- SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice, DISPLAY_ID);
+ SingleTouchInputMapper* mapper = new SingleTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION | PRESSURE | TOOL);
addMapperAndConfigure(mapper);
@@ -2884,7 +2903,7 @@ void MultiTouchInputMapperTest::processSync(MultiTouchInputMapper* mapper) {
TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackingIds) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice, DISPLAY_ID);
+ MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION);
prepareVirtualKeys();
@@ -3135,7 +3154,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithoutTrackin
}
TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingIds) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice, DISPLAY_ID);
+ MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION | ID);
prepareVirtualKeys();
@@ -3295,7 +3314,7 @@ TEST_F(MultiTouchInputMapperTest, Process_NormalMultiTouchGesture_WithTrackingId
}
TEST_F(MultiTouchInputMapperTest, Process_AllAxes_WithDefaultCalibration) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice, DISPLAY_ID);
+ MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION | TOUCH | TOOL | PRESSURE | ORIENTATION | ID | MINOR);
addMapperAndConfigure(mapper);
@@ -3340,11 +3359,11 @@ TEST_F(MultiTouchInputMapperTest, Process_AllAxes_WithDefaultCalibration) {
}
TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_GeometricCalibration) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice, DISPLAY_ID);
+ MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION | TOUCH | TOOL | MINOR);
- prepareCalibration("touch.touchSize.calibration", "geometric");
- prepareCalibration("touch.toolSize.calibration", "geometric");
+ addConfigurationProperty("touch.touchSize.calibration", "geometric");
+ addConfigurationProperty("touch.toolSize.calibration", "geometric");
addMapperAndConfigure(mapper);
// These calculations are based on the input device calibration documentation.
@@ -3381,17 +3400,17 @@ TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_GeometricCalibration)
}
TEST_F(MultiTouchInputMapperTest, Process_TouchToolPressureSizeAxes_SummedLinearCalibration) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice, DISPLAY_ID);
+ MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION | TOUCH | TOOL);
- prepareCalibration("touch.touchSize.calibration", "pressure");
- prepareCalibration("touch.toolSize.calibration", "linear");
- prepareCalibration("touch.toolSize.linearScale", "10");
- prepareCalibration("touch.toolSize.linearBias", "160");
- prepareCalibration("touch.toolSize.isSummed", "1");
- prepareCalibration("touch.pressure.calibration", "amplitude");
- prepareCalibration("touch.pressure.source", "touch");
- prepareCalibration("touch.pressure.scale", "0.01");
+ addConfigurationProperty("touch.touchSize.calibration", "pressure");
+ addConfigurationProperty("touch.toolSize.calibration", "linear");
+ addConfigurationProperty("touch.toolSize.linearScale", "10");
+ addConfigurationProperty("touch.toolSize.linearBias", "160");
+ addConfigurationProperty("touch.toolSize.isSummed", "1");
+ addConfigurationProperty("touch.pressure.calibration", "amplitude");
+ addConfigurationProperty("touch.pressure.source", "touch");
+ addConfigurationProperty("touch.pressure.scale", "0.01");
addMapperAndConfigure(mapper);
// These calculations are based on the input device calibration documentation.
@@ -3437,18 +3456,18 @@ TEST_F(MultiTouchInputMapperTest, Process_TouchToolPressureSizeAxes_SummedLinear
}
TEST_F(MultiTouchInputMapperTest, Process_TouchToolPressureSizeAxes_AreaCalibration) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice, DISPLAY_ID);
+ MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
prepareDisplay(InputReaderPolicyInterface::ROTATION_0);
prepareAxes(POSITION | TOUCH | TOOL);
- prepareCalibration("touch.touchSize.calibration", "pressure");
- prepareCalibration("touch.toolSize.calibration", "area");
- prepareCalibration("touch.toolSize.areaScale", "22");
- prepareCalibration("touch.toolSize.areaBias", "1");
- prepareCalibration("touch.toolSize.linearScale", "9.2");
- prepareCalibration("touch.toolSize.linearBias", "3");
- prepareCalibration("touch.pressure.calibration", "amplitude");
- prepareCalibration("touch.pressure.source", "touch");
- prepareCalibration("touch.pressure.scale", "0.01");
+ addConfigurationProperty("touch.touchSize.calibration", "pressure");
+ addConfigurationProperty("touch.toolSize.calibration", "area");
+ addConfigurationProperty("touch.toolSize.areaScale", "22");
+ addConfigurationProperty("touch.toolSize.areaBias", "1");
+ addConfigurationProperty("touch.toolSize.linearScale", "9.2");
+ addConfigurationProperty("touch.toolSize.linearBias", "3");
+ addConfigurationProperty("touch.pressure.calibration", "amplitude");
+ addConfigurationProperty("touch.pressure.source", "touch");
+ addConfigurationProperty("touch.pressure.scale", "0.01");
addMapperAndConfigure(mapper);
// These calculations are based on the input device calibration documentation.
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index 9c01aea..8bd833b 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -28,6 +28,7 @@ commonSources:= \
Flattenable.cpp \
ObbFile.cpp \
Pool.cpp \
+ PropertyMap.cpp \
RefBase.cpp \
ResourceTypes.cpp \
SharedBuffer.cpp \
diff --git a/libs/utils/PropertyMap.cpp b/libs/utils/PropertyMap.cpp
new file mode 100644
index 0000000..fd7edec
--- /dev/null
+++ b/libs/utils/PropertyMap.cpp
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "PropertyMap"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <utils/PropertyMap.h>
+#include <utils/Log.h>
+
+// Enables debug output for the parser.
+#define DEBUG_PARSER 0
+
+// Enables debug output for parser performance.
+#define DEBUG_PARSER_PERFORMANCE 0
+
+
+namespace android {
+
+static const char* WHITESPACE = " \t\r";
+static const char* WHITESPACE_OR_PROPERTY_DELIMITER = " \t\r=";
+
+
+// --- PropertyMap ---
+
+PropertyMap::PropertyMap() {
+}
+
+PropertyMap::~PropertyMap() {
+}
+
+void PropertyMap::clear() {
+ mProperties.clear();
+}
+
+void PropertyMap::addProperty(const String8& key, const String8& value) {
+ mProperties.add(key, value);
+}
+
+bool PropertyMap::hasProperty(const String8& key) const {
+ return mProperties.indexOfKey(key) >= 0;
+}
+
+bool PropertyMap::tryGetProperty(const String8& key, String8& outValue) const {
+ ssize_t index = mProperties.indexOfKey(key);
+ if (index < 0) {
+ return false;
+ }
+
+ outValue = mProperties.valueAt(index);
+ return true;
+}
+
+bool PropertyMap::tryGetProperty(const String8& key, bool& outValue) const {
+ int32_t intValue;
+ if (!tryGetProperty(key, intValue)) {
+ return false;
+ }
+
+ outValue = intValue;
+ return true;
+}
+
+bool PropertyMap::tryGetProperty(const String8& key, int32_t& outValue) const {
+ String8 stringValue;
+ if (! tryGetProperty(key, stringValue) || stringValue.length() == 0) {
+ return false;
+ }
+
+ char* end;
+ int value = strtol(stringValue.string(), & end, 10);
+ if (*end != '\0') {
+ LOGW("Property key '%s' has invalid value '%s'. Expected an integer.",
+ key.string(), stringValue.string());
+ return false;
+ }
+ outValue = value;
+ return true;
+}
+
+bool PropertyMap::tryGetProperty(const String8& key, float& outValue) const {
+ String8 stringValue;
+ if (! tryGetProperty(key, stringValue) || stringValue.length() == 0) {
+ return false;
+ }
+
+ char* end;
+ float value = strtof(stringValue.string(), & end);
+ if (*end != '\0') {
+ LOGW("Property key '%s' has invalid value '%s'. Expected a float.",
+ key.string(), stringValue.string());
+ return false;
+ }
+ outValue = value;
+ return true;
+}
+
+status_t PropertyMap::load(const String8& filename, PropertyMap** outMap) {
+ *outMap = NULL;
+
+ Tokenizer* tokenizer;
+ status_t status = Tokenizer::open(filename, &tokenizer);
+ if (status) {
+ LOGE("Error %d opening property file %s.", status, filename.string());
+ } else {
+ PropertyMap* map = new PropertyMap();
+ if (!map) {
+ LOGE("Error allocating property map.");
+ status = NO_MEMORY;
+ } else {
+#if DEBUG_PARSER_PERFORMANCE
+ nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
+#endif
+ Parser parser(map, tokenizer);
+ status = parser.parse();
+#if DEBUG_PARSER_PERFORMANCE
+ nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
+ LOGD("Parsed property file '%s' %d lines in %0.3fms.",
+ tokenizer->getFilename().string(), tokenizer->getLineNumber(),
+ elapsedTime / 1000000.0);
+#endif
+ if (status) {
+ delete map;
+ } else {
+ *outMap = map;
+ }
+ }
+ delete tokenizer;
+ }
+ return status;
+}
+
+
+// --- PropertyMap::Parser ---
+
+PropertyMap::Parser::Parser(PropertyMap* map, Tokenizer* tokenizer) :
+ mMap(map), mTokenizer(tokenizer) {
+}
+
+PropertyMap::Parser::~Parser() {
+}
+
+status_t PropertyMap::Parser::parse() {
+ while (!mTokenizer->isEof()) {
+#if DEBUG_PARSER
+ LOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(),
+ mTokenizer->peekRemainderOfLine().string());
+#endif
+
+ mTokenizer->skipDelimiters(WHITESPACE);
+
+ if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') {
+ String8 keyToken = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER);
+ if (keyToken.isEmpty()) {
+ LOGE("%s: Expected non-empty property key.", mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
+
+ mTokenizer->skipDelimiters(WHITESPACE);
+
+ if (mTokenizer->nextChar() != '=') {
+ LOGE("%s: Expected '=' between property key and value.",
+ mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
+
+ mTokenizer->skipDelimiters(WHITESPACE);
+
+ String8 valueToken = mTokenizer->nextToken(WHITESPACE);
+ if (valueToken.find("\\", 0) >= 0 || valueToken.find("\"", 0) >= 0) {
+ LOGE("%s: Found reserved character '\\' or '\"' in property value.",
+ mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
+
+ mTokenizer->skipDelimiters(WHITESPACE);
+ if (!mTokenizer->isEol()) {
+ LOGE("%s: Expected end of line, got '%s'.",
+ mTokenizer->getLocation().string(),
+ mTokenizer->peekRemainderOfLine().string());
+ return BAD_VALUE;
+ }
+
+ if (mMap->hasProperty(keyToken)) {
+ LOGE("%s: Duplicate property value for key '%s'.",
+ mTokenizer->getLocation().string(), keyToken.string());
+ return BAD_VALUE;
+ }
+
+ mMap->addProperty(keyToken, valueToken);
+ }
+
+ mTokenizer->nextLine();
+ }
+ return NO_ERROR;
+}
+
+} // namespace android
diff --git a/media/java/android/media/MtpDatabase.java b/media/java/android/media/MtpDatabase.java
index 250ec44..0387989 100644
--- a/media/java/android/media/MtpDatabase.java
+++ b/media/java/android/media/MtpDatabase.java
@@ -169,11 +169,6 @@ public class MtpDatabase {
// handle abstract playlists separately
// they do not exist in the file system so don't use the media scanner here
if (format == MtpConstants.FORMAT_ABSTRACT_AV_PLAYLIST) {
- // Strip Windows Media Player file extension
- if (path.endsWith(".pla")) {
- path = path.substring(0, path.length() - 4);
- }
-
// extract name from path
String name = path;
int lastSlash = name.lastIndexOf('/');
@@ -1005,7 +1000,7 @@ public class MtpDatabase {
valuesList[i] = values;
}
try {
- if (count == mMediaProvider.bulkInsert(uri, valuesList)) {
+ if (mMediaProvider.bulkInsert(uri, valuesList) > 0) {
return MtpConstants.RESPONSE_OK;
}
} catch (RemoteException e) {
diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp
index 68f2e9b..a660429 100644
--- a/media/libmedia/Visualizer.cpp
+++ b/media/libmedia/Visualizer.cpp
@@ -209,8 +209,8 @@ status_t Visualizer::doFft(uint8_t *fft, uint8_t *waveform)
int32_t nonzero = 0;
for (uint32_t i = 0; i < mCaptureSize; i += 2) {
- workspace[i >> 1] = (waveform[i] ^ 0x80) << 23;
- workspace[i >> 1] |= (waveform[i + 1] ^ 0x80) << 7;
+ workspace[i >> 1] =
+ ((waveform[i] ^ 0x80) << 24) | ((waveform[i + 1] ^ 0x80) << 8);
nonzero |= workspace[i >> 1];
}
@@ -219,8 +219,8 @@ status_t Visualizer::doFft(uint8_t *fft, uint8_t *waveform)
}
for (uint32_t i = 0; i < mCaptureSize; i += 2) {
- fft[i] = workspace[i >> 1] >> 23;
- fft[i + 1] = workspace[i >> 1] >> 7;
+ fft[i] = workspace[i >> 1] >> 24;
+ fft[i + 1] = workspace[i >> 1] >> 8;
}
return NO_ERROR;
diff --git a/media/mtp/MtpDataPacket.cpp b/media/mtp/MtpDataPacket.cpp
index e1d1a92..eac1f7e 100644
--- a/media/mtp/MtpDataPacket.cpp
+++ b/media/mtp/MtpDataPacket.cpp
@@ -351,6 +351,7 @@ int MtpDataPacket::read(int fd) {
return -1;
// then the following data
int total = MtpPacket::getUInt32(MTP_CONTAINER_LENGTH_OFFSET);
+ allocate(total);
int remaining = total - MTP_CONTAINER_HEADER_SIZE;
ret = ::read(fd, &mBuffer[0] + MTP_CONTAINER_HEADER_SIZE, remaining);
if (ret != remaining)
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java
index 7174e2b..484f6e7 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java
@@ -25,11 +25,6 @@ import com.android.mediaframeworktest.MediaNames;
import com.android.mediaframeworktest.MediaProfileReader;
import android.test.suitebuilder.annotation.*;
-/**
- * WARNING:
- * Currently, captureFrame() does not work, due to hardware access permission problem.
- * We are currently only testing the metadata/album art retrieval features.
- */
public class MediaMetadataRetrieverTest extends AndroidTestCase {
private static final String TAG = "MediaMetadataRetrieverTest";
@@ -101,6 +96,7 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
} catch (Exception e) {
Log.e(TAG, "Fails to convert the bitmap to a JPEG file for " + MediaNames.THUMBNAIL_CAPTURE_TEST_FILES[i]);
hasFailed = true;
+ Log.e(TAG, e.toString());
}
} catch(Exception e) {
Log.e(TAG, "Fails to setDataSource for file " + MediaNames.THUMBNAIL_CAPTURE_TEST_FILES[i]);
@@ -148,11 +144,8 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
public static void testBasicNormalMethodCallSequence() throws Exception {
boolean hasFailed = false;
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
- retriever.setMode(MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
try {
retriever.setDataSource(MediaNames.TEST_PATH_1);
- /*
- * captureFrame() fails due to lack of permission to access hardware decoder devices
Bitmap bitmap = retriever.captureFrame();
assertTrue(bitmap != null);
try {
@@ -162,7 +155,6 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
} catch (Exception e) {
throw new Exception("Fails to convert the bitmap to a JPEG file for " + MediaNames.TEST_PATH_1, e);
}
- */
extractAllSupportedMetadataValues(retriever);
} catch(Exception e) {
Log.e(TAG, "Fails to setDataSource for " + MediaNames.TEST_PATH_1, e);
@@ -251,17 +243,14 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
assertTrue(!hasFailed);
}
- // Due to the lack of permission to access hardware decoder, any calls
- // attempting to capture a frame will fail. These are commented out for now
- // until we find a solution to this access permission problem.
@MediumTest
public static void testIntendedUsage() {
// By default, capture frame and retrieve metadata
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
boolean hasFailed = false;
- // retriever.setDataSource(MediaNames.TEST_PATH_1);
- // assertTrue(retriever.captureFrame() != null);
- // assertTrue(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS) != null);
+ retriever.setDataSource(MediaNames.TEST_PATH_1);
+ assertTrue(retriever.captureFrame() != null);
+ assertTrue(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS) != null);
// Do not capture frame or retrieve metadata
retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY & MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
@@ -276,9 +265,9 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
}
// Capture frame only
- // retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY);
- // retriever.setDataSource(MediaNames.TEST_PATH_1);
- // assertTrue(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS) == null);
+ retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY);
+ retriever.setDataSource(MediaNames.TEST_PATH_1);
+ assertTrue(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS) == null);
// Retriever metadata only
retriever.setMode(MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
@@ -289,10 +278,10 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
}
// Capture frame and retrieve metadata
- // retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY | MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
- // retriever.setDataSource(MediaNames.TEST_PATH_1);
- // assertTrue(retriever.captureFrame() != null);
- // assertTrue(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS) != null);
+ retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY | MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
+ retriever.setDataSource(MediaNames.TEST_PATH_1);
+ assertTrue(retriever.captureFrame() != null);
+ assertTrue(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS) != null);
retriever.release();
assertTrue(!hasFailed);
}
diff --git a/opengl/tests/hwc/Android.mk b/opengl/tests/hwc/Android.mk
new file mode 100644
index 0000000..743dbf1
--- /dev/null
+++ b/opengl/tests/hwc/Android.mk
@@ -0,0 +1,27 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES:= hwc_stress.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libEGL \
+ libGLESv2 \
+ libui \
+ libhardware \
+
+LOCAL_STATIC_LIBRARIES := \
+ libtestUtil \
+
+LOCAL_C_INCLUDES += \
+ system/extras/tests/include \
+ hardware/libhardware/include \
+
+LOCAL_MODULE:= hwc_stress
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativestresstest
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_CFLAGS := -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+
+include $(BUILD_NATIVE_TEST)
diff --git a/opengl/tests/hwc/hwc_stress.cpp b/opengl/tests/hwc/hwc_stress.cpp
new file mode 100644
index 0000000..d119734
--- /dev/null
+++ b/opengl/tests/hwc/hwc_stress.cpp
@@ -0,0 +1,1193 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/*
+ * Hardware Composer stress test
+ *
+ * Performs a pseudo-random (prandom) sequence of operations to the
+ * Hardware Composer (HWC), for a specified number of passes or for
+ * a specified period of time. By default the period of time is FLT_MAX,
+ * so that the number of passes will take precedence.
+ *
+ * The passes are grouped together, where (pass / passesPerGroup) specifies
+ * which group a particular pass is in. This causes every passesPerGroup
+ * worth of sequential passes to be within the same group. Computationally
+ * intensive operations are performed just once at the beginning of a group
+ * of passes and then used by all the passes in that group. This is done
+ * so as to increase both the average and peak rate of graphic operations,
+ * by moving computationally intensive operations to the beginning of a group.
+ * In particular, at the start of each group of passes a set of
+ * graphic buffers are created, then used by the first and remaining
+ * passes of that group of passes.
+ *
+ * The per-group initialization of the graphic buffers is performed
+ * by a function called initFrames. This function creates an array
+ * of smart pointers to the graphic buffers, in the form of a vector
+ * of vectors. The array is accessed in row major order, so each
+ * row is a vector of smart pointers. All the pointers of a single
+ * row point to graphic buffers which use the same pixel format and
+ * have the same dimension, although it is likely that each one is
+ * filled with a different color. This is done so that after doing
+ * the first HWC prepare then set call, subsequent set calls can
+ * be made with each of the layer handles changed to a different
+ * graphic buffer within the same row. Since the graphic buffers
+ * in a particular row have the same pixel format and dimension,
+ * additional HWC set calls can be made, without having to perform
+ * an HWC prepare call.
+ *
+ * This test supports the following command-line options:
+ *
+ * -v Verbose
+ * -s num Starting pass
+ * -e num Ending pass
+ * -p num Execute the single pass specified by num
+ * -n num Number of set operations to perform after each prepare operation
+ * -t float Maximum time in seconds to execute the test
+ * -d float Delay in seconds performed after each set operation
+ * -D float Delay in seconds performed after the last pass is executed
+ *
+ * Typically the test is executed for a large range of passes. By default
+ * passes 0 through 99999 (100,000 passes) are executed. Although this test
+ * does not validate the generated image, at times it is useful to reexecute
+ * a particular pass and leave the displayed image on the screen for an
+ * extended period of time. This can be done either by setting the -s
+ * and -e options to the desired pass, along with a large value for -D.
+ * This can also be done via the -p option, again with a large value for
+ * the -D options.
+ *
+ * So far this test only contains code to create graphic buffers with
+ * a continuous solid color. Although this test is unable to validate the
+ * image produced, any image that contains other than rectangles of a solid
+ * color are incorrect. Note that the rectangles may use a transparent
+ * color and have a blending operation that causes the color in overlapping
+ * rectangles to be mixed. In such cases the overlapping portions may have
+ * a different color from the rest of the rectangle.
+ */
+
+#include <algorithm>
+#include <assert.h>
+#include <cerrno>
+#include <cmath>
+#include <cstdlib>
+#include <ctime>
+#include <libgen.h>
+#include <sched.h>
+#include <sstream>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <vector>
+
+#include <arpa/inet.h> // For ntohl() and htonl()
+
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <ui/FramebufferNativeWindow.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/EGLUtils.h>
+
+#define LOG_TAG "hwcStressTest"
+#include <utils/Log.h>
+#include <testUtil.h>
+
+#include <hardware/hwcomposer.h>
+
+using namespace std;
+using namespace android;
+
+const float maxSizeRatio = 1.3; // Graphic buffers can be upto this munch
+ // larger than the default screen size
+const unsigned int passesPerGroup = 10; // A group of passes all use the same
+ // graphic buffers
+const float rareRatio = 0.1; // Ratio at which rare conditions are produced.
+
+// Defaults for command-line options
+const bool defaultVerbose = false;
+const unsigned int defaultStartPass = 0;
+const unsigned int defaultEndPass = 99999;
+const unsigned int defaultPerPassNumSet = 10;
+const float defaultPerPassDelay = 0.1;
+const float defaultEndDelay = 2.0; // Default delay between completion of
+ // final pass and restart of framework
+const float defaultDuration = FLT_MAX; // A fairly long time, so that
+ // range of passes will have
+ // precedence
+
+// Command-line option settings
+static bool verbose = defaultVerbose;
+static unsigned int startPass = defaultStartPass;
+static unsigned int endPass = defaultEndPass;
+static unsigned int numSet = defaultPerPassNumSet;
+static float perSetDelay = defaultPerPassDelay;
+static float endDelay = defaultEndDelay;
+static float duration = defaultDuration;
+
+// Command-line mutual exclusion detection flags.
+// Corresponding flag set true once an option is used.
+bool eFlag, sFlag, pFlag;
+
+#define MAXSTR 100
+#define MAXCMD 200
+#define BITSPERBYTE 8 // TODO: Obtain from <values.h>, once
+ // it has been added
+
+#define CMD_STOP_FRAMEWORK "stop 2>&1"
+#define CMD_START_FRAMEWORK "start 2>&1"
+
+#define NUMA(a) (sizeof(a) / sizeof(a [0]))
+#define MEMCLR(addr, size) do { \
+ memset((addr), 0, (size)); \
+ } while (0)
+
+// Represent RGB color as fraction of color components.
+// Each of the color components are expected in the range [0.0, 1.0]
+class RGBColor {
+ public:
+ RGBColor(): _r(0.0), _g(0.0), _b(0.0) {};
+ RGBColor(float f): _r(f), _g(f), _b(f) {}; // Gray
+ RGBColor(float r, float g, float b): _r(r), _g(g), _b(b) {};
+ float r(void) const { return _r; }
+ float g(void) const { return _g; }
+ float b(void) const { return _b; }
+
+ private:
+ float _r;
+ float _g;
+ float _b;
+};
+
+// Represent YUV color as fraction of color components.
+// Each of the color components are expected in the range [0.0, 1.0]
+class YUVColor {
+ public:
+ YUVColor(): _y(0.0), _u(0.0), _v(0.0) {};
+ YUVColor(float f): _y(f), _u(0.0), _v(0.0) {}; // Gray
+ YUVColor(float y, float u, float v): _y(y), _u(u), _v(v) {};
+ float y(void) const { return _y; }
+ float u(void) const { return _u; }
+ float v(void) const { return _v; }
+
+ private:
+ float _y;
+ float _u;
+ float _v;
+};
+
+// File scope constants
+static const struct {
+ unsigned int format;
+ const char *desc;
+} graphicFormat[] = {
+ {HAL_PIXEL_FORMAT_RGBA_8888, "RGBA8888"},
+ {HAL_PIXEL_FORMAT_RGBX_8888, "RGBX8888"},
+// {HAL_PIXEL_FORMAT_RGB_888, "RGB888"}, // Known issue: 3198458
+ {HAL_PIXEL_FORMAT_RGB_565, "RGB565"},
+ {HAL_PIXEL_FORMAT_BGRA_8888, "BGRA8888"},
+ {HAL_PIXEL_FORMAT_RGBA_5551, "RGBA5551"},
+ {HAL_PIXEL_FORMAT_RGBA_4444, "RGBA4444"},
+// {HAL_PIXEL_FORMAT_YV12, "YV12"}, // Currently not supported by HWC
+};
+const unsigned int blendingOps[] = {
+ HWC_BLENDING_NONE,
+ HWC_BLENDING_PREMULT,
+ HWC_BLENDING_COVERAGE,
+};
+const unsigned int layerFlags[] = {
+ HWC_SKIP_LAYER,
+};
+const vector<unsigned int> vecLayerFlags(layerFlags,
+ layerFlags + NUMA(layerFlags));
+
+const unsigned int transformFlags[] = {
+ HWC_TRANSFORM_FLIP_H,
+ HWC_TRANSFORM_FLIP_V,
+ HWC_TRANSFORM_ROT_90,
+ // ROT_180 & ROT_270 intentionally not listed, because they
+ // they are formed from combinations of the flags already listed.
+};
+const vector<unsigned int> vecTransformFlags(transformFlags,
+ transformFlags + NUMA(transformFlags));
+
+// File scope globals
+static const int texUsage = GraphicBuffer::USAGE_HW_TEXTURE |
+ GraphicBuffer::USAGE_SW_WRITE_RARELY;
+static hw_module_t const *hwcModule;
+static hwc_composer_device_t *hwcDevice;
+static vector <vector <sp<GraphicBuffer> > > frames;
+static EGLDisplay dpy;
+static EGLContext context;
+static EGLSurface surface;
+static EGLint width, height;
+
+// File scope prototypes
+static void execCmd(const char *cmd);
+static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE);
+static void checkGlError(const char* op);
+static void printEGLConfiguration(EGLDisplay dpy, EGLConfig config);
+static void printGLString(const char *name, GLenum s);
+static hwc_layer_list_t *createLayerList(size_t numLayers);
+static void freeLayerList(hwc_layer_list_t *list);
+static void fillColor(GraphicBuffer *gBuf, RGBColor color, float trans);
+static void fillColor(GraphicBuffer *gBuf, YUVColor color, float trans);
+void init(void);
+void initFrames(unsigned int seed);
+void displayList(hwc_layer_list_t *list);
+void displayListPrepareModifiable(hwc_layer_list_t *list);
+void displayListHandles(hwc_layer_list_t *list);
+const char *graphicFormat2str(unsigned int format);
+template <class T> vector<T> vectorRandSelect(const vector<T>& vec, size_t num);
+template <class T> T vectorOr(const vector<T>& vec);
+
+/*
+ * Main
+ *
+ * Performs the following high-level sequence of operations:
+ *
+ * 1. Command-line parsing
+ *
+ * 2. Initialization
+ *
+ * 3. For each pass:
+ *
+ * a. If pass is first pass or in a different group from the
+ * previous pass, initialize the array of graphic buffers.
+ *
+ * b. Create a HWC list with room to specify a prandomly
+ * selected number of layers.
+ *
+ * c. Select a subset of the rows from the graphic buffer array,
+ * such that there is a unique row to be used for each
+ * of the layers in the HWC list.
+ *
+ * d. Prandomly fill in the HWC list with handles
+ * selected from any of the columns of the selected row.
+ *
+ * e. Pass the populated list to the HWC prepare call.
+ *
+ * f. Pass the populated list to the HWC set call.
+ *
+ * g. If additional set calls are to be made, then for each
+ * additional set call, select a new set of handles and
+ * perform the set call.
+ */
+int
+main(int argc, char *argv[])
+{
+ int rv, opt;
+ char *chptr;
+ unsigned int pass;
+ char cmd[MAXCMD];
+ struct timeval startTime, currentTime, delta;
+
+ testSetLogCatTag(LOG_TAG);
+
+ // Parse command line arguments
+ while ((opt = getopt(argc, argv, "vp:d:D:n:s:e:t:?h")) != -1) {
+ switch (opt) {
+ case 'd': // Delay after each set operation
+ perSetDelay = strtod(optarg, &chptr);
+ if ((*chptr != '\0') || (perSetDelay < 0.0)) {
+ testPrintE("Invalid command-line specified per pass delay of: "
+ "%s", optarg);
+ exit(1);
+ }
+ break;
+
+ case 'D': // End of test delay
+ // Delay between completion of final pass and restart
+ // of framework
+ endDelay = strtod(optarg, &chptr);
+ if ((*chptr != '\0') || (endDelay < 0.0)) {
+ testPrintE("Invalid command-line specified end of test delay "
+ "of: %s", optarg);
+ exit(2);
+ }
+ break;
+
+ case 't': // Duration
+ duration = strtod(optarg, &chptr);
+ if ((*chptr != '\0') || (duration < 0.0)) {
+ testPrintE("Invalid command-line specified duration of: %s",
+ optarg);
+ exit(3);
+ }
+ break;
+
+ case 'n': // Num set operations per pass
+ numSet = strtoul(optarg, &chptr, 10);
+ if (*chptr != '\0') {
+ testPrintE("Invalid command-line specified num set per pass "
+ "of: %s", optarg);
+ exit(4);
+ }
+ break;
+
+ case 's': // Starting Pass
+ sFlag = true;
+ if (pFlag) {
+ testPrintE("Invalid combination of command-line options.");
+ testPrintE(" The -p option is mutually exclusive from the");
+ testPrintE(" -s and -e options.");
+ exit(5);
+ }
+ startPass = strtoul(optarg, &chptr, 10);
+ if (*chptr != '\0') {
+ testPrintE("Invalid command-line specified starting pass "
+ "of: %s", optarg);
+ exit(6);
+ }
+ break;
+
+ case 'e': // Ending Pass
+ eFlag = true;
+ if (pFlag) {
+ testPrintE("Invalid combination of command-line options.");
+ testPrintE(" The -p option is mutually exclusive from the");
+ testPrintE(" -s and -e options.");
+ exit(7);
+ }
+ endPass = strtoul(optarg, &chptr, 10);
+ if (*chptr != '\0') {
+ testPrintE("Invalid command-line specified ending pass "
+ "of: %s", optarg);
+ exit(8);
+ }
+ break;
+
+ case 'p': // Run a single specified pass
+ pFlag = true;
+ if (sFlag || eFlag) {
+ testPrintE("Invalid combination of command-line options.");
+ testPrintE(" The -p option is mutually exclusive from the");
+ testPrintE(" -s and -e options.");
+ exit(9);
+ }
+ startPass = endPass = strtoul(optarg, &chptr, 10);
+ if (*chptr != '\0') {
+ testPrintE("Invalid command-line specified pass of: %s",
+ optarg);
+ exit(10);
+ }
+ break;
+
+ case 'v': // Verbose
+ verbose = true;
+ break;
+
+ case 'h': // Help
+ case '?':
+ default:
+ testPrintE(" %s [options]", basename(argv[0]));
+ testPrintE(" options:");
+ testPrintE(" -p Execute specified pass");
+ testPrintE(" -s Starting pass");
+ testPrintE(" -e Ending pass");
+ testPrintE(" -t Duration");
+ testPrintE(" -d Delay after each set operation");
+ testPrintE(" -D End of test delay");
+ testPrintE(" -n Num set operations per pass");
+ testPrintE(" -v Verbose");
+ exit(((optopt == 0) || (optopt == '?')) ? 0 : 11);
+ }
+ }
+ if (endPass < startPass) {
+ testPrintE("Unexpected ending pass before starting pass");
+ testPrintE(" startPass: %u endPass: %u", startPass, endPass);
+ exit(12);
+ }
+ if (argc != optind) {
+ testPrintE("Unexpected command-line postional argument");
+ testPrintE(" %s [-s start_pass] [-e end_pass] [-t duration]",
+ basename(argv[0]));
+ exit(13);
+ }
+ testPrintI("duration: %g", duration);
+ testPrintI("startPass: %u", startPass);
+ testPrintI("endPass: %u", endPass);
+ testPrintI("numSet: %u", numSet);
+
+ // Stop framework
+ rv = snprintf(cmd, sizeof(cmd), "%s", CMD_STOP_FRAMEWORK);
+ if (rv >= (signed) sizeof(cmd) - 1) {
+ testPrintE("Command too long for: %s", CMD_STOP_FRAMEWORK);
+ exit(14);
+ }
+ execCmd(cmd);
+ testDelay(1.0); // TODO - needs means to query whether asyncronous stop
+ // framework operation has completed. For now, just wait
+ // a long time.
+
+ init();
+
+ // For each pass
+ gettimeofday(&startTime, NULL);
+ for (pass = startPass; pass <= endPass; pass++) {
+ // Stop if duration of work has already been performed
+ gettimeofday(&currentTime, NULL);
+ delta = tvDelta(&startTime, &currentTime);
+ if (tv2double(&delta) > duration) { break; }
+
+ // Regenerate a new set of test frames when this pass is
+ // either the first pass or is in a different group then
+ // the previous pass. A group of passes are passes that
+ // all have the same quotient when their pass number is
+ // divided by passesPerGroup.
+ if ((pass == startPass)
+ || ((pass / passesPerGroup) != ((pass - 1) / passesPerGroup))) {
+ initFrames(pass / passesPerGroup);
+ }
+
+ testPrintI("==== Starting pass: %u", pass);
+
+ // Cause deterministic sequence of prandom numbers to be
+ // generated for this pass.
+ srand48(pass);
+
+ hwc_layer_list_t *list;
+ list = createLayerList(testRandMod(frames.size()) + 1);
+ if (list == NULL) {
+ testPrintE("createLayerList failed");
+ exit(20);
+ }
+
+ // Prandomly select a subset of frames to be used by this pass.
+ vector <vector <sp<GraphicBuffer> > > selectedFrames;
+ selectedFrames = vectorRandSelect(frames, list->numHwLayers);
+
+ // Any transform tends to create a layer that the hardware
+ // composer is unable to support and thus has to leave for
+ // SurfaceFlinger. Place heavy bias on specifying no transforms.
+ bool noTransform = testRandFract() > rareRatio;
+
+ for (unsigned int n1 = 0; n1 < list->numHwLayers; n1++) {
+ unsigned int idx = testRandMod(selectedFrames[n1].size());
+ sp<GraphicBuffer> gBuf = selectedFrames[n1][idx];
+ hwc_layer_t *layer = &list->hwLayers[n1];
+ layer->handle = gBuf->handle;
+
+ layer->blending = blendingOps[testRandMod(NUMA(blendingOps))];
+ layer->flags = (testRandFract() > rareRatio) ? 0
+ : vectorOr(vectorRandSelect(vecLayerFlags,
+ testRandMod(vecLayerFlags.size() + 1)));
+ layer->transform = (noTransform || testRandFract() > rareRatio) ? 0
+ : vectorOr(vectorRandSelect(vecTransformFlags,
+ testRandMod(vecTransformFlags.size() + 1)));
+ layer->sourceCrop.left = testRandMod(gBuf->getWidth());
+ layer->sourceCrop.top = testRandMod(gBuf->getHeight());
+ layer->sourceCrop.right = layer->sourceCrop.left
+ + testRandMod(gBuf->getWidth() - layer->sourceCrop.left) + 1;
+ layer->sourceCrop.bottom = layer->sourceCrop.top
+ + testRandMod(gBuf->getHeight() - layer->sourceCrop.top) + 1;
+ layer->displayFrame.left = testRandMod(width);
+ layer->displayFrame.top = testRandMod(height);
+ layer->displayFrame.right = layer->displayFrame.left
+ + testRandMod(width - layer->displayFrame.left) + 1;
+ layer->displayFrame.bottom = layer->displayFrame.top
+ + testRandMod(height - layer->displayFrame.top) + 1;
+ layer->visibleRegionScreen.numRects = 1;
+ layer->visibleRegionScreen.rects = &layer->displayFrame;
+ }
+
+ // Perform prepare operation
+ if (verbose) { testPrintI("Prepare:"); displayList(list); }
+ hwcDevice->prepare(hwcDevice, list);
+ if (verbose) {
+ testPrintI("Post Prepare:");
+ displayListPrepareModifiable(list);
+ }
+
+ // Turn off the geometry changed flag
+ list->flags &= ~HWC_GEOMETRY_CHANGED;
+
+ // Perform the set operation(s)
+ if (verbose) {testPrintI("Set:"); }
+ for (unsigned int n1 = 0; n1 < numSet; n1++) {
+ if (verbose) {displayListHandles(list); }
+ hwcDevice->set(hwcDevice, dpy, surface, list);
+
+ // Prandomly select a new set of handles
+ for (unsigned int n1 = 0; n1 < list->numHwLayers; n1++) {
+ unsigned int idx = testRandMod(selectedFrames[n1].size());
+ sp<GraphicBuffer> gBuf = selectedFrames[n1][idx];
+ hwc_layer_t *layer = &list->hwLayers[n1];
+ layer->handle = (native_handle_t *) gBuf->handle;
+ }
+
+ testDelay(perSetDelay);
+ }
+
+
+ freeLayerList(list);
+ testPrintI("==== Completed pass: %u", pass);
+ }
+
+ testDelay(endDelay);
+
+ // Start framework
+ rv = snprintf(cmd, sizeof(cmd), "%s", CMD_START_FRAMEWORK);
+ if (rv >= (signed) sizeof(cmd) - 1) {
+ testPrintE("Command too long for: %s", CMD_START_FRAMEWORK);
+ exit(21);
+ }
+ execCmd(cmd);
+
+ testPrintI("Successfully completed %u passes", pass - startPass);
+
+ return 0;
+}
+
+/*
+ * Execute Command
+ *
+ * Executes the command pointed to by cmd. Output from the
+ * executed command is captured and sent to LogCat Info. Once
+ * the command has finished execution, it's exit status is captured
+ * and checked for an exit status of zero. Any other exit status
+ * causes diagnostic information to be printed and an immediate
+ * testcase failure.
+ */
+static void execCmd(const char *cmd)
+{
+ FILE *fp;
+ int rv;
+ int status;
+ char str[MAXSTR];
+
+ // Display command to be executed
+ testPrintI("cmd: %s", cmd);
+
+ // Execute the command
+ fflush(stdout);
+ if ((fp = popen(cmd, "r")) == NULL) {
+ testPrintE("execCmd popen failed, errno: %i", errno);
+ exit(30);
+ }
+
+ // Obtain and display each line of output from the executed command
+ while (fgets(str, sizeof(str), fp) != NULL) {
+ if ((strlen(str) > 1) && (str[strlen(str) - 1] == '\n')) {
+ str[strlen(str) - 1] = '\0';
+ }
+ testPrintI(" out: %s", str);
+ }
+
+ // Obtain and check return status of executed command.
+ // Fail on non-zero exit status
+ status = pclose(fp);
+ if (!(WIFEXITED(status) && (WEXITSTATUS(status) == 0))) {
+ testPrintE("Unexpected command failure");
+ testPrintE(" status: %#x", status);
+ if (WIFEXITED(status)) {
+ testPrintE("WEXITSTATUS: %i", WEXITSTATUS(status));
+ }
+ if (WIFSIGNALED(status)) {
+ testPrintE("WTERMSIG: %i", WTERMSIG(status));
+ }
+ exit(31);
+ }
+}
+
+static void checkEglError(const char* op, EGLBoolean returnVal) {
+ if (returnVal != EGL_TRUE) {
+ testPrintE("%s() returned %d", op, returnVal);
+ }
+
+ for (EGLint error = eglGetError(); error != EGL_SUCCESS; error
+ = eglGetError()) {
+ testPrintE("after %s() eglError %s (0x%x)",
+ op, EGLUtils::strerror(error), error);
+ }
+}
+
+static void checkGlError(const char* op) {
+ for (GLint error = glGetError(); error; error
+ = glGetError()) {
+ testPrintE("after %s() glError (0x%x)", op, error);
+ }
+}
+
+static void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) {
+
+#define X(VAL) {VAL, #VAL}
+ struct {EGLint attribute; const char* name;} names[] = {
+ X(EGL_BUFFER_SIZE),
+ X(EGL_ALPHA_SIZE),
+ X(EGL_BLUE_SIZE),
+ X(EGL_GREEN_SIZE),
+ X(EGL_RED_SIZE),
+ X(EGL_DEPTH_SIZE),
+ X(EGL_STENCIL_SIZE),
+ X(EGL_CONFIG_CAVEAT),
+ X(EGL_CONFIG_ID),
+ X(EGL_LEVEL),
+ X(EGL_MAX_PBUFFER_HEIGHT),
+ X(EGL_MAX_PBUFFER_PIXELS),
+ X(EGL_MAX_PBUFFER_WIDTH),
+ X(EGL_NATIVE_RENDERABLE),
+ X(EGL_NATIVE_VISUAL_ID),
+ X(EGL_NATIVE_VISUAL_TYPE),
+ X(EGL_SAMPLES),
+ X(EGL_SAMPLE_BUFFERS),
+ X(EGL_SURFACE_TYPE),
+ X(EGL_TRANSPARENT_TYPE),
+ X(EGL_TRANSPARENT_RED_VALUE),
+ X(EGL_TRANSPARENT_GREEN_VALUE),
+ X(EGL_TRANSPARENT_BLUE_VALUE),
+ X(EGL_BIND_TO_TEXTURE_RGB),
+ X(EGL_BIND_TO_TEXTURE_RGBA),
+ X(EGL_MIN_SWAP_INTERVAL),
+ X(EGL_MAX_SWAP_INTERVAL),
+ X(EGL_LUMINANCE_SIZE),
+ X(EGL_ALPHA_MASK_SIZE),
+ X(EGL_COLOR_BUFFER_TYPE),
+ X(EGL_RENDERABLE_TYPE),
+ X(EGL_CONFORMANT),
+ };
+#undef X
+
+ for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) {
+ EGLint value = -1;
+ EGLint returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value);
+ EGLint error = eglGetError();
+ if (returnVal && error == EGL_SUCCESS) {
+ testPrintI(" %s: %d (%#x)", names[j].name, value, value);
+ }
+ }
+ testPrintI("");
+}
+
+static void printGLString(const char *name, GLenum s)
+{
+ const char *v = (const char *) glGetString(s);
+
+ if (v == NULL) {
+ testPrintI("GL %s unknown", name);
+ } else {
+ testPrintI("GL %s = %s", name, v);
+ }
+}
+
+/*
+ * createLayerList
+ * dynamically creates layer list with numLayers worth
+ * of hwLayers entries.
+ */
+static hwc_layer_list_t *createLayerList(size_t numLayers)
+{
+ hwc_layer_list_t *list;
+
+ size_t size = sizeof(hwc_layer_list) + numLayers * sizeof(hwc_layer_t);
+ if ((list = (hwc_layer_list_t *) calloc(1, size)) == NULL) {
+ return NULL;
+ }
+ list->flags = HWC_GEOMETRY_CHANGED;
+ list->numHwLayers = numLayers;
+
+ return list;
+}
+
+/*
+ * freeLayerList
+ * Frees memory previous allocated via createLayerList().
+ */
+static void freeLayerList(hwc_layer_list_t *list)
+{
+ free(list);
+}
+
+static void fillColor(GraphicBuffer *gBuf, RGBColor color, float trans)
+{
+ unsigned char* buf = NULL;
+ status_t err;
+ unsigned int numPixels = gBuf->getWidth() * gBuf->getHeight();
+ uint32_t pixel;
+
+ // RGB 2 YUV conversion ratios
+ const struct rgb2yuvRatios {
+ int format;
+ float weightRed;
+ float weightBlu;
+ float weightGrn;
+ } rgb2yuvRatios[] = {
+ { HAL_PIXEL_FORMAT_YV12, 0.299, 0.114, 0.587 },
+ };
+
+ const struct rgbAttrib {
+ int format;
+ bool hostByteOrder;
+ size_t bytes;
+ size_t rOffset;
+ size_t rSize;
+ size_t gOffset;
+ size_t gSize;
+ size_t bOffset;
+ size_t bSize;
+ size_t aOffset;
+ size_t aSize;
+ } rgbAttributes[] = {
+ {HAL_PIXEL_FORMAT_RGBA_8888, false, 4, 0, 8, 8, 8, 16, 8, 24, 8},
+ {HAL_PIXEL_FORMAT_RGBX_8888, false, 4, 0, 8, 8, 8, 16, 8, 0, 0},
+ {HAL_PIXEL_FORMAT_RGB_888, false, 3, 0, 8, 8, 8, 16, 8, 0, 0},
+ {HAL_PIXEL_FORMAT_RGB_565, true, 2, 0, 5, 5, 6, 11, 5, 0, 0},
+ {HAL_PIXEL_FORMAT_BGRA_8888, false, 4, 16, 8, 8, 8, 0, 8, 24, 8},
+ {HAL_PIXEL_FORMAT_RGBA_5551, true , 2, 0, 5, 5, 5, 10, 5, 15, 1},
+ {HAL_PIXEL_FORMAT_RGBA_4444, false, 2, 12, 4, 0, 4, 4, 4, 8, 4},
+ };
+
+ // If YUV format, convert color and pass work to YUV color fill
+ for (unsigned int n1 = 0; n1 < NUMA(rgb2yuvRatios); n1++) {
+ if (gBuf->getPixelFormat() == rgb2yuvRatios[n1].format) {
+ float wr = rgb2yuvRatios[n1].weightRed;
+ float wb = rgb2yuvRatios[n1].weightBlu;
+ float wg = rgb2yuvRatios[n1].weightGrn;
+ float y = wr * color.r() + wb * color.b() + wg * color.g();
+ float u = 0.5 * ((color.b() - y) / (1 - wb)) + 0.5;
+ float v = 0.5 * ((color.r() - y) / (1 - wr)) + 0.5;
+ YUVColor yuvColor(y, u, v);
+ fillColor(gBuf, yuvColor, trans);
+ return;
+ }
+ }
+
+ const struct rgbAttrib *attrib;
+ for (attrib = rgbAttributes; attrib < rgbAttributes + NUMA(rgbAttributes);
+ attrib++) {
+ if (attrib->format == gBuf->getPixelFormat()) { break; }
+ }
+ if (attrib >= rgbAttributes + NUMA(rgbAttributes)) {
+ testPrintE("fillColor rgb unsupported format of: %u",
+ gBuf->getPixelFormat());
+ exit(50);
+ }
+
+ pixel = htonl((uint32_t) (((1 << attrib->rSize) - 1) * color.r())
+ << ((sizeof(pixel) * BITSPERBYTE)
+ - (attrib->rOffset + attrib->rSize)));
+ pixel |= htonl((uint32_t) (((1 << attrib->gSize) - 1) * color.g())
+ << ((sizeof(pixel) * BITSPERBYTE)
+ - (attrib->gOffset + attrib->gSize)));
+ pixel |= htonl((uint32_t) (((1 << attrib->bSize) - 1) * color.b())
+ << ((sizeof(pixel) * BITSPERBYTE)
+ - (attrib->bOffset + attrib->bSize)));
+ if (attrib->aSize) {
+ pixel |= htonl((uint32_t) (((1 << attrib->aSize) - 1) * trans)
+ << ((sizeof(pixel) * BITSPERBYTE)
+ - (attrib->aOffset + attrib->aSize)));
+ }
+ if (attrib->hostByteOrder) {
+ pixel = ntohl(pixel);
+ pixel >>= sizeof(pixel) * BITSPERBYTE - attrib->bytes * BITSPERBYTE;
+ }
+
+ err = gBuf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&buf));
+ if (err != 0) {
+ testPrintE("fillColor rgb lock failed: %d", err);
+ exit(51);
+ }
+
+ for (unsigned int n1 = 0; n1 < numPixels; n1++) {
+ memmove(buf, &pixel, attrib->bytes);
+ buf += attrib->bytes;
+ }
+
+ err = gBuf->unlock();
+ if (err != 0) {
+ testPrintE("fillColor rgb unlock failed: %d", err);
+ exit(52);
+ }
+}
+
+static void fillColor(GraphicBuffer *gBuf, YUVColor color, float trans)
+{
+ unsigned char* buf = NULL;
+ status_t err;
+ unsigned int width = gBuf->getWidth();
+ unsigned int height = gBuf->getHeight();
+
+ const struct yuvAttrib {
+ int format;
+ size_t padWidth;
+ bool planar;
+ unsigned int uSubSampX;
+ unsigned int uSubSampY;
+ unsigned int vSubSampX;
+ unsigned int vSubSampY;
+ } yuvAttributes[] = {
+ { HAL_PIXEL_FORMAT_YV12, 16, true, 2, 2, 2, 2},
+ };
+
+ const struct yuvAttrib *attrib;
+ for (attrib = yuvAttributes; attrib < yuvAttributes + NUMA(yuvAttributes);
+ attrib++) {
+ if (attrib->format == gBuf->getPixelFormat()) { break; }
+ }
+ if (attrib >= yuvAttributes + NUMA(yuvAttributes)) {
+ testPrintE("fillColor yuv unsupported format of: %u",
+ gBuf->getPixelFormat());
+ exit(60);
+ }
+
+ assert(attrib->planar == true); // So far, only know how to handle planar
+
+ // If needed round width up to pad size
+ if (width % attrib->padWidth) {
+ width += attrib->padWidth - (width % attrib->padWidth);
+ }
+ assert((width % attrib->padWidth) == 0);
+
+ err = gBuf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&buf));
+ if (err != 0) {
+ testPrintE("fillColor lock failed: %d", err);
+ exit(61);
+ }
+
+ // Fill in Y component
+ for (unsigned int x = 0; x < width; x++) {
+ for (unsigned int y = 0; y < height; y++) {
+ *buf++ = (x < gBuf->getWidth()) ? (255 * color.y()) : 0;
+ }
+ }
+
+ // Fill in U component
+ for (unsigned int x = 0; x < width; x += attrib->uSubSampX) {
+ for (unsigned int y = 0; y < height; y += attrib->uSubSampY) {
+ *buf++ = (x < gBuf->getWidth()) ? (255 * color.u()) : 0;
+ }
+ }
+
+ // Fill in V component
+ for (unsigned int x = 0; x < width; x += attrib->vSubSampX) {
+ for (unsigned int y = 0; y < height; y += attrib->vSubSampY) {
+ *buf++ = (x < gBuf->getWidth()) ? (255 * color.v()) : 0;
+ }
+ }
+
+ err = gBuf->unlock();
+ if (err != 0) {
+ testPrintE("fillColor unlock failed: %d", err);
+ exit(62);
+ }
+}
+
+void init(void)
+{
+ int rv;
+
+ EGLBoolean returnValue;
+ EGLConfig myConfig = {0};
+ EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
+ EGLint sConfigAttribs[] = {
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_NONE };
+ EGLint majorVersion, minorVersion;
+
+ checkEglError("<init>");
+ dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ checkEglError("eglGetDisplay");
+ if (dpy == EGL_NO_DISPLAY) {
+ testPrintE("eglGetDisplay returned EGL_NO_DISPLAY");
+ exit(70);
+ }
+
+ returnValue = eglInitialize(dpy, &majorVersion, &minorVersion);
+ checkEglError("eglInitialize", returnValue);
+ testPrintI("EGL version %d.%d", majorVersion, minorVersion);
+ if (returnValue != EGL_TRUE) {
+ testPrintE("eglInitialize failed");
+ exit(71);
+ }
+
+ EGLNativeWindowType window = android_createDisplaySurface();
+ if (window == NULL) {
+ testPrintE("android_createDisplaySurface failed");
+ exit(72);
+ }
+ returnValue = EGLUtils::selectConfigForNativeWindow(dpy,
+ sConfigAttribs, window, &myConfig);
+ if (returnValue) {
+ testPrintE("EGLUtils::selectConfigForNativeWindow() returned %d",
+ returnValue);
+ exit(73);
+ }
+ checkEglError("EGLUtils::selectConfigForNativeWindow");
+
+ testPrintI("Chose this configuration:");
+ printEGLConfiguration(dpy, myConfig);
+
+ surface = eglCreateWindowSurface(dpy, myConfig, window, NULL);
+ checkEglError("eglCreateWindowSurface");
+ if (surface == EGL_NO_SURFACE) {
+ testPrintE("gelCreateWindowSurface failed.");
+ exit(74);
+ }
+
+ context = eglCreateContext(dpy, myConfig, EGL_NO_CONTEXT, contextAttribs);
+ checkEglError("eglCreateContext");
+ if (context == EGL_NO_CONTEXT) {
+ testPrintE("eglCreateContext failed");
+ exit(75);
+ }
+ returnValue = eglMakeCurrent(dpy, surface, surface, context);
+ checkEglError("eglMakeCurrent", returnValue);
+ if (returnValue != EGL_TRUE) {
+ testPrintE("eglMakeCurrent failed");
+ exit(76);
+ }
+ eglQuerySurface(dpy, surface, EGL_WIDTH, &width);
+ checkEglError("eglQuerySurface");
+ eglQuerySurface(dpy, surface, EGL_HEIGHT, &height);
+ checkEglError("eglQuerySurface");
+
+ fprintf(stderr, "Window dimensions: %d x %d", width, height);
+
+ printGLString("Version", GL_VERSION);
+ printGLString("Vendor", GL_VENDOR);
+ printGLString("Renderer", GL_RENDERER);
+ printGLString("Extensions", GL_EXTENSIONS);
+
+ if ((rv = hw_get_module(HWC_HARDWARE_MODULE_ID, &hwcModule)) != 0) {
+ testPrintE("hw_get_module failed, rv: %i", rv);
+ errno = -rv;
+ perror(NULL);
+ exit(77);
+ }
+ if ((rv = hwc_open(hwcModule, &hwcDevice)) != 0) {
+ testPrintE("hwc_open failed, rv: %i", rv);
+ errno = -rv;
+ perror(NULL);
+ exit(78);
+ }
+
+ testPrintI("");
+}
+
+/*
+ * Initialize Frames
+ *
+ * Creates an array of graphic buffers, within the global variable
+ * named frames. The graphic buffers are contained within a vector of
+ * verctors. All the graphic buffers in a particular row are of the same
+ * format and dimension. Each graphic buffer is uniformly filled with a
+ * prandomly selected color. It is likely that each buffer, even
+ * in the same row, will be filled with a unique color.
+ */
+void initFrames(unsigned int seed)
+{
+ const size_t maxRows = 5;
+ const size_t minCols = 2; // Need at least double buffering
+ const size_t maxCols = 4; // One more than triple buffering
+
+ if (verbose) { testPrintI("initFrames seed: %u", seed); }
+ srand48(seed);
+ size_t rows = testRandMod(maxRows) + 1;
+
+ frames.clear();
+ frames.resize(rows);
+
+ for (unsigned int row = 0; row < rows; row++) {
+ // All frames within a row have to have the same format and
+ // dimensions. Width and height need to be >= 1.
+ int format = graphicFormat[testRandMod(NUMA(graphicFormat))].format;
+ size_t w = (width * maxSizeRatio) * testRandFract();
+ size_t h = (height * maxSizeRatio) * testRandFract();
+ w = max(1u, w);
+ h = max(1u, h);
+ if (verbose) {
+ testPrintI(" frame %u width: %u height: %u format: %u %s",
+ row, w, h, format, graphicFormat2str(format));
+ }
+
+ size_t cols = testRandMod((maxCols + 1) - minCols) + minCols;
+ frames[row].resize(cols);
+ for (unsigned int col = 0; col < cols; col++) {
+ RGBColor color(testRandFract(), testRandFract(), testRandFract());
+ float transp = testRandFract();
+
+ frames[row][col] = new GraphicBuffer(w, h, format, texUsage);
+ fillColor(frames[row][col].get(), color, transp);
+ if (verbose) {
+ testPrintI(" buf: %p handle: %p color: <%f, %f, %f> "
+ "transp: %f",
+ frames[row][col].get(), frames[row][col]->handle,
+ color.r(), color.g(), color.b(), transp);
+ }
+ }
+ }
+}
+
+void displayList(hwc_layer_list_t *list)
+{
+ testPrintI(" flags: %#x%s", list->flags,
+ (list->flags & HWC_GEOMETRY_CHANGED) ? " GEOMETRY_CHANGED" : "");
+ testPrintI(" numHwLayers: %u", list->numHwLayers);
+
+ for (unsigned int layer = 0; layer < list->numHwLayers; layer++) {
+ testPrintI(" layer %u compositionType: %#x%s%s", layer,
+ list->hwLayers[layer].compositionType,
+ (list->hwLayers[layer].compositionType == HWC_FRAMEBUFFER)
+ ? " FRAMEBUFFER" : "",
+ (list->hwLayers[layer].compositionType == HWC_OVERLAY)
+ ? " OVERLAY" : "");
+
+ testPrintI(" hints: %#x",
+ list->hwLayers[layer].hints,
+ (list->hwLayers[layer].hints & HWC_HINT_TRIPLE_BUFFER)
+ ? " TRIPLE_BUFFER" : "",
+ (list->hwLayers[layer].hints & HWC_HINT_CLEAR_FB)
+ ? " CLEAR_FB" : "");
+
+ testPrintI(" flags: %#x%s",
+ list->hwLayers[layer].flags,
+ (list->hwLayers[layer].flags & HWC_SKIP_LAYER)
+ ? " SKIP_LAYER" : "");
+
+ testPrintI(" handle: %p",
+ list->hwLayers[layer].handle);
+
+ // Intentionally skipped display of ROT_180 & ROT_270,
+ // which are formed from combinations of the other flags.
+ testPrintI(" transform: %#x%s%s%s",
+ list->hwLayers[layer].transform,
+ (list->hwLayers[layer].transform & HWC_TRANSFORM_FLIP_H)
+ ? " FLIP_H" : "",
+ (list->hwLayers[layer].transform & HWC_TRANSFORM_FLIP_V)
+ ? " FLIP_V" : "",
+ (list->hwLayers[layer].transform & HWC_TRANSFORM_ROT_90)
+ ? " ROT_90" : "");
+
+ testPrintI(" blending: %#x",
+ list->hwLayers[layer].blending,
+ (list->hwLayers[layer].blending == HWC_BLENDING_NONE)
+ ? " NONE" : "",
+ (list->hwLayers[layer].blending == HWC_BLENDING_PREMULT)
+ ? " PREMULT" : "",
+ (list->hwLayers[layer].blending == HWC_BLENDING_COVERAGE)
+ ? " COVERAGE" : "");
+
+ testPrintI(" sourceCrop: [%i, %i, %i, %i]",
+ list->hwLayers[layer].sourceCrop.left,
+ list->hwLayers[layer].sourceCrop.top,
+ list->hwLayers[layer].sourceCrop.right,
+ list->hwLayers[layer].sourceCrop.bottom);
+
+ testPrintI(" displayFrame: [%i, %i, %i, %i]",
+ list->hwLayers[layer].displayFrame.left,
+ list->hwLayers[layer].displayFrame.top,
+ list->hwLayers[layer].displayFrame.right,
+ list->hwLayers[layer].displayFrame.bottom);
+ }
+}
+
+/*
+ * Display List Prepare Modifiable
+ *
+ * Displays the portions of a list that are meant to be modified by
+ * a prepare call.
+ */
+void displayListPrepareModifiable(hwc_layer_list_t *list)
+{
+ for (unsigned int layer = 0; layer < list->numHwLayers; layer++) {
+ testPrintI(" layer %u compositionType: %#x%s%s", layer,
+ list->hwLayers[layer].compositionType,
+ (list->hwLayers[layer].compositionType == HWC_FRAMEBUFFER)
+ ? " FRAMEBUFFER" : "",
+ (list->hwLayers[layer].compositionType == HWC_OVERLAY)
+ ? " OVERLAY" : "");
+ testPrintI(" hints: %#x%s%s",
+ list->hwLayers[layer].hints,
+ (list->hwLayers[layer].hints & HWC_HINT_TRIPLE_BUFFER)
+ ? " TRIPLE_BUFFER" : "",
+ (list->hwLayers[layer].hints & HWC_HINT_CLEAR_FB)
+ ? " CLEAR_FB" : "");
+ }
+}
+
+/*
+ * Display List Handles
+ *
+ * Displays the handles of all the graphic buffers in the list.
+ */
+void displayListHandles(hwc_layer_list_t *list)
+{
+ const unsigned int maxLayersPerLine = 6;
+
+ ostringstream str(" layers:");
+ for (unsigned int layer = 0; layer < list->numHwLayers; layer++) {
+ str << ' ' << list->hwLayers[layer].handle;
+ if (((layer % maxLayersPerLine) == (maxLayersPerLine - 1))
+ && (layer != list->numHwLayers - 1)) {
+ testPrintI("%s", str.str().c_str());
+ str.str(" ");
+ }
+ }
+ testPrintI("%s", str.str().c_str());
+}
+
+const char *graphicFormat2str(unsigned int format)
+{
+ const static char *unknown = "unknown";
+
+ for (unsigned int n1 = 0; n1 < NUMA(graphicFormat); n1++) {
+ if (format == graphicFormat[n1].format) {
+ return graphicFormat[n1].desc;
+ }
+ }
+
+ return unknown;
+}
+
+/*
+ * Vector Random Select
+ *
+ * Prandomly selects and returns num elements from vec.
+ */
+template <class T>
+vector<T> vectorRandSelect(const vector<T>& vec, size_t num)
+{
+ vector<T> rv = vec;
+
+ while (rv.size() > num) {
+ rv.erase(rv.begin() + testRandMod(rv.size()));
+ }
+
+ return rv;
+}
+
+/*
+ * Vector Or
+ *
+ * Or's togethen the values of each element of vec and returns the result.
+ */
+template <class T>
+T vectorOr(const vector<T>& vec)
+{
+ T rv = 0;
+
+ for (size_t n1 = 0; n1 < vec.size(); n1++) {
+ rv |= vec[n1];
+ }
+
+ return rv;
+}
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar.xml b/packages/SystemUI/res/layout-xlarge/status_bar.xml
index d4e9c53..758377b 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar.xml
@@ -82,14 +82,24 @@
android:orientation="horizontal"
android:gravity="center"
>
- <ImageView
- android:id="@+id/network"
+ <FrameLayout
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_gravity="top"
android:layout_marginTop="19dp"
android:layout_marginRight="4dp"
- />
+ >
+ <ImageView
+ android:id="@+id/network_signal"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ />
+ <ImageView
+ android:id="@+id/network_type"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ />
+ </FrameLayout>
<ImageView
android:id="@+id/battery"
android:layout_height="wrap_content"
diff --git a/packages/SystemUI/res/layout-xlarge/status_bar_notification_panel.xml b/packages/SystemUI/res/layout-xlarge/status_bar_notification_panel.xml
index c0612c8..1d98458 100644
--- a/packages/SystemUI/res/layout-xlarge/status_bar_notification_panel.xml
+++ b/packages/SystemUI/res/layout-xlarge/status_bar_notification_panel.xml
@@ -95,7 +95,17 @@
/>
<ImageView
- android:id="@+id/network"
+ android:id="@+id/network_signal"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_toRightOf="@id/battery_text"
+ android:layout_alignBaseline="@id/battery"
+ android:layout_marginRight="8dp"
+ android:baseline="15dp"
+ />
+
+ <ImageView
+ android:id="@+id/network_type"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_toRightOf="@id/battery_text"
@@ -109,7 +119,7 @@
style="@style/StatusBarNotificationText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_toRightOf="@id/network"
+ android:layout_toRightOf="@id/network_signal"
android:layout_alignBaseline="@id/battery"
android:singleLine="true"
android:text="@string/status_bar_settings_settings_button"
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 1a32aa7..8a18d55 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"التنبيهات"</string>
<string name="battery_low_title" msgid="7923774589611311406">"الرجاء توصيل الشاحن"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"البطارية منخفضة:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"يتبقى <xliff:g id="NUMBER">%d%%</xliff:g> أو أقل."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"استخدام البطارية"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"حديثة"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index a9c8ba0..9270997 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Известия"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Моля, включете зарядно устройство"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Батерията се изтощава:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"Остава <xliff:g id="NUMBER">%d%%</xliff:g> или по-малко."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Използване на батерията"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Скорошни"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index eea01e1..70f3ee1 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificacions"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Connecteu el carregador"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Comença a quedar poca bateria:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"En queda un <xliff:g id="NUMBER">%d%%</xliff:g> o menys."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Ús de la bateria"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Recents"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-cs-xlarge/strings.xml b/packages/SystemUI/res/values-cs-xlarge/strings.xml
deleted file mode 100644
index d432a8b..0000000
--- a/packages/SystemUI/res/values-cs-xlarge/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for status_bar_clear_all_button (4722520806446512408) -->
- <skip />
- <string name="status_bar_settings_signal_meter_disconnected" msgid="2123001074951934237">"žádné připojení k internetu"</string>
- <!-- no translation found for status_bar_settings_signal_meter_wifi_ssid_format (6261810256542749384) -->
- <skip />
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="160846667119240422">"Wi-Fi: připojeno"</string>
- <string name="status_bar_settings_signal_meter_wifi_connecting" msgid="4087640898624652649">"Wi-Fi: připojování"</string>
- <string name="status_bar_settings_signal_meter_data_connected" msgid="2171100321540926054">"Mob. data: připojeno"</string>
- <string name="status_bar_settings_signal_meter_data_connecting" msgid="7183001278053801143">"Mob. data: připojování"</string>
-</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 5eac747..cfdf0dd 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Oznámení"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Prosím připojte dobíjecí zařízení"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Baterie je vybitá:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"Zbývá <xliff:g id="NUMBER">%d%%</xliff:g> nebo méně."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Využití baterie"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Nejnovější"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-da-xlarge/strings.xml b/packages/SystemUI/res/values-da-xlarge/strings.xml
deleted file mode 100644
index 9d587a8..0000000
--- a/packages/SystemUI/res/values-da-xlarge/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for status_bar_clear_all_button (4722520806446512408) -->
- <skip />
- <string name="status_bar_settings_signal_meter_disconnected" msgid="2123001074951934237">"ingen forbindelse"</string>
- <!-- no translation found for status_bar_settings_signal_meter_wifi_ssid_format (6261810256542749384) -->
- <skip />
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="160846667119240422">"Wi-Fi forbundet"</string>
- <string name="status_bar_settings_signal_meter_wifi_connecting" msgid="4087640898624652649">"Wi-Fi: forbinder..."</string>
- <string name="status_bar_settings_signal_meter_data_connected" msgid="2171100321540926054">"Mobildata tilsluttet"</string>
- <string name="status_bar_settings_signal_meter_data_connecting" msgid="7183001278053801143">"Mobildata tilsluttes"</string>
-</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 7b49070..e4fc728 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Meddelelser"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Forbind oplader"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Batteriet er ved at være fladt:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> eller mindre tilbage."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Batteriforbrug"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Seneste"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-de-xlarge/strings.xml b/packages/SystemUI/res/values-de-xlarge/strings.xml
deleted file mode 100644
index fd1a976..0000000
--- a/packages/SystemUI/res/values-de-xlarge/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for status_bar_clear_all_button (4722520806446512408) -->
- <skip />
- <string name="status_bar_settings_signal_meter_disconnected" msgid="2123001074951934237">"Keine Verbindung"</string>
- <!-- no translation found for status_bar_settings_signal_meter_wifi_ssid_format (6261810256542749384) -->
- <skip />
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="160846667119240422">"WLAN: verbunden"</string>
- <string name="status_bar_settings_signal_meter_wifi_connecting" msgid="4087640898624652649">"WLAN: verbindet..."</string>
- <string name="status_bar_settings_signal_meter_data_connected" msgid="2171100321540926054">"Mobile Daten: aktiv"</string>
- <string name="status_bar_settings_signal_meter_data_connecting" msgid="7183001278053801143">"Mobile Daten: verbindet"</string>
-</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 1535e78..edb1bef 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Benachrichtigungen"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Ladegerät anschließen"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Akku ist fast leer."</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> oder weniger verbleiben."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Akkuverbrauch"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Zuletzt verwendet"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-el-xlarge/strings.xml b/packages/SystemUI/res/values-el-xlarge/strings.xml
deleted file mode 100644
index c52d6daf..0000000
--- a/packages/SystemUI/res/values-el-xlarge/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for status_bar_clear_all_button (4722520806446512408) -->
- <skip />
- <string name="status_bar_settings_signal_meter_disconnected" msgid="2123001074951934237">"χωρίς σύνδ. σε Διαδ."</string>
- <!-- no translation found for status_bar_settings_signal_meter_wifi_ssid_format (6261810256542749384) -->
- <skip />
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="160846667119240422">"Wi-Fi: συνδέθηκε"</string>
- <string name="status_bar_settings_signal_meter_wifi_connecting" msgid="4087640898624652649">"Wi-Fi: σύνδεση..."</string>
- <string name="status_bar_settings_signal_meter_data_connected" msgid="2171100321540926054">"Δεδ. κιν.: συνδέθηκε"</string>
- <string name="status_bar_settings_signal_meter_data_connecting" msgid="7183001278053801143">"Δεδ.κιν.: σύνδεση..."</string>
-</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 369b16f..21ea803 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Ειδοποιήσεις"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Συνδέστε τον φορτιστή"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Η στάθμη της μπαταρίας είναι χαμηλή:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"Απομένει <xliff:g id="NUMBER">%d%%</xliff:g> ή λιγότερο."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Χρήση μπαταρίας"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Πρόσφατα"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index db4f9ba..c9d4b76 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifications"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Please connect charger"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"The battery is getting low:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> or less remaining."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Battery use"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Recent"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-es-rUS-xlarge/strings.xml b/packages/SystemUI/res/values-es-rUS-xlarge/strings.xml
deleted file mode 100644
index 6530edf..0000000
--- a/packages/SystemUI/res/values-es-rUS-xlarge/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for status_bar_clear_all_button (4722520806446512408) -->
- <skip />
- <string name="status_bar_settings_signal_meter_disconnected" msgid="2123001074951934237">"no hay conexión a Internet"</string>
- <!-- no translation found for status_bar_settings_signal_meter_wifi_ssid_format (6261810256542749384) -->
- <skip />
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="160846667119240422">"Wi-Fi: conectado"</string>
- <string name="status_bar_settings_signal_meter_wifi_connecting" msgid="4087640898624652649">"Wi-Fi: conectando…"</string>
- <string name="status_bar_settings_signal_meter_data_connected" msgid="2171100321540926054">"Datos para cel: conectado"</string>
- <string name="status_bar_settings_signal_meter_data_connecting" msgid="7183001278053801143">"Datos para cel: conectando"</string>
-</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 2312be7..b6d3618 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -31,11 +31,19 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificaciones"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Conecta el cargador"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Hay poca batería:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"Restan <xliff:g id="NUMBER">%d%%</xliff:g> o menos."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Uso de la batería"</string>
- <string name="status_bar_settings_settings_button" msgid="7832600575390861653">"Configuración"</string>
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
+ <skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Reciente"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
<skip />
diff --git a/packages/SystemUI/res/values-es-xlarge/strings.xml b/packages/SystemUI/res/values-es-xlarge/strings.xml
deleted file mode 100644
index adcda91..0000000
--- a/packages/SystemUI/res/values-es-xlarge/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for status_bar_clear_all_button (4722520806446512408) -->
- <skip />
- <string name="status_bar_settings_signal_meter_disconnected" msgid="2123001074951934237">"sin conexión"</string>
- <!-- no translation found for status_bar_settings_signal_meter_wifi_ssid_format (6261810256542749384) -->
- <skip />
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="160846667119240422">"WiFi: conectado"</string>
- <string name="status_bar_settings_signal_meter_wifi_connecting" msgid="4087640898624652649">"WiFi: conectando..."</string>
- <string name="status_bar_settings_signal_meter_data_connected" msgid="2171100321540926054">"Datos móviles: conectados"</string>
- <string name="status_bar_settings_signal_meter_data_connecting" msgid="7183001278053801143">"Datos móviles: conectando..."</string>
-</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 64b60b4..77773af 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificaciones"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Conecta el cargador"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Se está agotando la batería:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> o menos disponible"</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Uso de la batería"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Reciente"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 8e2b348..015b87c 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"اعلان ها"</string>
<string name="battery_low_title" msgid="7923774589611311406">"لطفاً شارژر را وصل کنید"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"باتری در حال کم شدن است:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> یا کمتر باقیمانده است."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"استفاده از باتری"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"اخیر"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 8fcc7d6..d677afc 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Ilmoitukset"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Kytke laturi"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Akun virta on vähissä:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"jäljellä <xliff:g id="NUMBER">%d%%</xliff:g> tai vähemmän."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Akun käyttö"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Viimeisimmät"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-fr-xlarge/strings.xml b/packages/SystemUI/res/values-fr-xlarge/strings.xml
deleted file mode 100644
index f8036ad..0000000
--- a/packages/SystemUI/res/values-fr-xlarge/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for status_bar_clear_all_button (4722520806446512408) -->
- <skip />
- <string name="status_bar_settings_signal_meter_disconnected" msgid="2123001074951934237">"Internet indisponible"</string>
- <!-- no translation found for status_bar_settings_signal_meter_wifi_ssid_format (6261810256542749384) -->
- <skip />
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="160846667119240422">"Wi-Fi : connecté"</string>
- <string name="status_bar_settings_signal_meter_wifi_connecting" msgid="4087640898624652649">"Wi-Fi : connexion..."</string>
- <string name="status_bar_settings_signal_meter_data_connected" msgid="2171100321540926054">"Données mobiles connectées"</string>
- <string name="status_bar_settings_signal_meter_data_connecting" msgid="7183001278053801143">"Connexion données mobiles..."</string>
-</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 7df4d74..8877329 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifications"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Branchez le chargeur"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Le niveau de la batterie est bas :"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"Maximum <xliff:g id="NUMBER">%d%%</xliff:g> restants."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Utilisation de la batterie"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Récentes"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-he/strings.xml b/packages/SystemUI/res/values-he/strings.xml
index 0e3479b..ad1f755 100644
--- a/packages/SystemUI/res/values-he/strings.xml
+++ b/packages/SystemUI/res/values-he/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"התראות"</string>
<string name="battery_low_title" msgid="7923774589611311406">"חבר מטען"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"הסוללה נחלשת:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"נותרו עוד <xliff:g id="NUMBER">%d%%</xliff:g> או פחות."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"צריכת סוללה"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"אחרונות"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 0fea021..d601eb0 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Obavijesti"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Priključite punjač"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Baterija će uskoro biti potrošena:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"Preostaje <xliff:g id="NUMBER">%d%%</xliff:g> ili manje."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Iskorištenost baterije"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Nedavni"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 788e96f..4188b6f 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Értesítések"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Kérjük, csatlakoztassa a töltőt"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Akkufeszültség alacsony:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> vagy kevesebb maradt."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Akkumulátorhasználat"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Legutóbbiak"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-id/strings.xml b/packages/SystemUI/res/values-id/strings.xml
index cde575f..974498a 100644
--- a/packages/SystemUI/res/values-id/strings.xml
+++ b/packages/SystemUI/res/values-id/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Pemberitahuan"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Harap hubungkan ke pengisi daya"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Baterai kekurangan daya:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> atau kurang yang tersisa."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Penggunaan baterai"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Terbaru"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-it-xlarge/strings.xml b/packages/SystemUI/res/values-it-xlarge/strings.xml
deleted file mode 100644
index 3909bd5..0000000
--- a/packages/SystemUI/res/values-it-xlarge/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for status_bar_clear_all_button (4722520806446512408) -->
- <skip />
- <string name="status_bar_settings_signal_meter_disconnected" msgid="2123001074951934237">"no conness. Internet"</string>
- <!-- no translation found for status_bar_settings_signal_meter_wifi_ssid_format (6261810256542749384) -->
- <skip />
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="160846667119240422">"Wi-Fi: connesso"</string>
- <string name="status_bar_settings_signal_meter_wifi_connecting" msgid="4087640898624652649">"Wi-Fi: connessione…"</string>
- <string name="status_bar_settings_signal_meter_data_connected" msgid="2171100321540926054">"Dati cell.: connesso"</string>
- <string name="status_bar_settings_signal_meter_data_connecting" msgid="7183001278053801143">"Dati cell.: connessione…"</string>
-</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index ee91a16..0507cf9 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifiche"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Collegare il caricabatterie"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Batteria quasi scarica:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> rimanente o meno."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Utilizzo batteria"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Recenti"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-ja-xlarge/strings.xml b/packages/SystemUI/res/values-ja-xlarge/strings.xml
deleted file mode 100644
index df512b7..0000000
--- a/packages/SystemUI/res/values-ja-xlarge/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for status_bar_clear_all_button (4722520806446512408) -->
- <skip />
- <string name="status_bar_settings_signal_meter_disconnected" msgid="2123001074951934237">"インターネット接続なし"</string>
- <!-- no translation found for status_bar_settings_signal_meter_wifi_ssid_format (6261810256542749384) -->
- <skip />
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="160846667119240422">"Wi-Fi: 接続されました"</string>
- <string name="status_bar_settings_signal_meter_wifi_connecting" msgid="4087640898624652649">"Wi-Fi: 接続中..."</string>
- <string name="status_bar_settings_signal_meter_data_connected" msgid="2171100321540926054">"データ通信: 接続されました"</string>
- <string name="status_bar_settings_signal_meter_data_connecting" msgid="7183001278053801143">"データ通信: 接続中..."</string>
-</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 817f656..782d03b 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
<string name="battery_low_title" msgid="7923774589611311406">"充電してください"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"電池が残り少なくなっています:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"残り<xliff:g id="NUMBER">%d%%</xliff:g>未満です。"</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"電池使用量"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"新着"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-ko-xlarge/strings.xml b/packages/SystemUI/res/values-ko-xlarge/strings.xml
deleted file mode 100644
index 42f798c..0000000
--- a/packages/SystemUI/res/values-ko-xlarge/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for status_bar_clear_all_button (4722520806446512408) -->
- <skip />
- <string name="status_bar_settings_signal_meter_disconnected" msgid="2123001074951934237">"인터넷에 연결되지 않음"</string>
- <!-- no translation found for status_bar_settings_signal_meter_wifi_ssid_format (6261810256542749384) -->
- <skip />
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="160846667119240422">"Wi-Fi: 연결됨"</string>
- <string name="status_bar_settings_signal_meter_wifi_connecting" msgid="4087640898624652649">"Wi-Fi: 연결 중…"</string>
- <string name="status_bar_settings_signal_meter_data_connected" msgid="2171100321540926054">"모바일 데이터: 연결됨"</string>
- <string name="status_bar_settings_signal_meter_data_connecting" msgid="7183001278053801143">"모바일 데이터: 연결 중…"</string>
-</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index be94258..5e9b9d5 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"알림"</string>
<string name="battery_low_title" msgid="7923774589611311406">"충전기를 연결하세요."</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"배터리 전원이 부족합니다."</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"잔여 배터리가 <xliff:g id="NUMBER">%d%%</xliff:g> 이하입니다."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"배터리 사용량"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"최근 사용한 앱"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index ccfc800..3d6d099 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Įspėjimai"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Prijunkite kroviklį"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Akumuliatorius senka:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"Liko <xliff:g id="NUMBER">%d%%</xliff:g> ar mažiau."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Akumuliatoriaus naudojimas"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Naujos"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index dd6cdcf..74a7890 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Paziņojumi"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Lūdzu, pievienojiet uzlādes ierīci."</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Akumulatora uzlādes līmenis kļūst zems:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"Atlicis <xliff:g id="NUMBER">%d%%</xliff:g> vai mazāk."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Akumulatora lietojums"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Nesens"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-nb-xlarge/strings.xml b/packages/SystemUI/res/values-nb-xlarge/strings.xml
deleted file mode 100644
index b07d70c..0000000
--- a/packages/SystemUI/res/values-nb-xlarge/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for status_bar_clear_all_button (4722520806446512408) -->
- <skip />
- <string name="status_bar_settings_signal_meter_disconnected" msgid="2123001074951934237">"ingen Int.-tilkobl."</string>
- <!-- no translation found for status_bar_settings_signal_meter_wifi_ssid_format (6261810256542749384) -->
- <skip />
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="160846667119240422">"Wi-Fi: tilkoblet"</string>
- <string name="status_bar_settings_signal_meter_wifi_connecting" msgid="4087640898624652649">"Wi-Fi: kobler til"</string>
- <string name="status_bar_settings_signal_meter_data_connected" msgid="2171100321540926054">"Mob.data: tilkoblet"</string>
- <string name="status_bar_settings_signal_meter_data_connecting" msgid="7183001278053801143">"Mob.data: kobler til"</string>
-</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 5da4f01..147242f 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Varslinger"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Koble til en lader"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Batteriet er nesten tomt:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"mindre enn <xliff:g id="NUMBER">%d%%</xliff:g> igjen."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Batteribruk"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Nylig"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-nl-xlarge/strings.xml b/packages/SystemUI/res/values-nl-xlarge/strings.xml
deleted file mode 100644
index 6298908..0000000
--- a/packages/SystemUI/res/values-nl-xlarge/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for status_bar_clear_all_button (4722520806446512408) -->
- <skip />
- <string name="status_bar_settings_signal_meter_disconnected" msgid="2123001074951934237">"geen internet"</string>
- <!-- no translation found for status_bar_settings_signal_meter_wifi_ssid_format (6261810256542749384) -->
- <skip />
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="160846667119240422">"Wi-Fi: verbonden"</string>
- <string name="status_bar_settings_signal_meter_wifi_connecting" msgid="4087640898624652649">"Wi-Fi: verbinden…"</string>
- <string name="status_bar_settings_signal_meter_data_connected" msgid="2171100321540926054">"Mobiel: verbonden"</string>
- <string name="status_bar_settings_signal_meter_data_connecting" msgid="7183001278053801143">"Mobiel: verbinden..."</string>
-</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 3492652..6067cca 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Meldingen"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Sluit de oplader aan"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"De accu raakt op:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> of minder resterend."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Accugebruik"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Recent"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-pl-xlarge/strings.xml b/packages/SystemUI/res/values-pl-xlarge/strings.xml
deleted file mode 100644
index e2cefc6..0000000
--- a/packages/SystemUI/res/values-pl-xlarge/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for status_bar_clear_all_button (4722520806446512408) -->
- <skip />
- <string name="status_bar_settings_signal_meter_disconnected" msgid="2123001074951934237">"brak połączenia internetowego"</string>
- <!-- no translation found for status_bar_settings_signal_meter_wifi_ssid_format (6261810256542749384) -->
- <skip />
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="160846667119240422">"Wi-Fi: połączono"</string>
- <string name="status_bar_settings_signal_meter_wifi_connecting" msgid="4087640898624652649">"Wi-Fi: łączenie…"</string>
- <string name="status_bar_settings_signal_meter_data_connected" msgid="2171100321540926054">"Sieć komórkowa: połączono"</string>
- <string name="status_bar_settings_signal_meter_data_connecting" msgid="7183001278053801143">"Sieć komórkowa: łączenie…"</string>
-</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index f6a6d79..6b19a34 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Powiadomienia"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Podłącz ładowarkę"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Bateria się rozładowuje:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"Pozostało: <xliff:g id="NUMBER">%d%%</xliff:g> lub mniej."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Użycie baterii"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Najnowsze"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-pt-rPT-xlarge/strings.xml b/packages/SystemUI/res/values-pt-rPT-xlarge/strings.xml
deleted file mode 100644
index 550c11c..0000000
--- a/packages/SystemUI/res/values-pt-rPT-xlarge/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for status_bar_clear_all_button (4722520806446512408) -->
- <skip />
- <string name="status_bar_settings_signal_meter_disconnected" msgid="2123001074951934237">"Sem ligação à internet"</string>
- <!-- no translation found for status_bar_settings_signal_meter_wifi_ssid_format (6261810256542749384) -->
- <skip />
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="160846667119240422">"Wi-Fi: ligado"</string>
- <string name="status_bar_settings_signal_meter_wifi_connecting" msgid="4087640898624652649">"Wi-Fi: a ligar…"</string>
- <string name="status_bar_settings_signal_meter_data_connected" msgid="2171100321540926054">"Dados móveis: ligado"</string>
- <string name="status_bar_settings_signal_meter_data_connecting" msgid="7183001278053801143">"Dados móveis: a ligar..."</string>
-</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 2c03a18..7bf6eb4 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificações"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Ligue o carregador"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"A bateria está a ficar fraca:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"Restam <xliff:g id="NUMBER">%d%%</xliff:g> ou menos."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Utilização da bateria"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Recente"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-pt-xlarge/strings.xml b/packages/SystemUI/res/values-pt-xlarge/strings.xml
deleted file mode 100644
index 9f2d033..0000000
--- a/packages/SystemUI/res/values-pt-xlarge/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for status_bar_clear_all_button (4722520806446512408) -->
- <skip />
- <string name="status_bar_settings_signal_meter_disconnected" msgid="2123001074951934237">"Sem conex. à intern."</string>
- <!-- no translation found for status_bar_settings_signal_meter_wifi_ssid_format (6261810256542749384) -->
- <skip />
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="160846667119240422">"Wi-Fi: conectado"</string>
- <string name="status_bar_settings_signal_meter_wifi_connecting" msgid="4087640898624652649">"Wi-Fi: conectando…"</string>
- <string name="status_bar_settings_signal_meter_data_connected" msgid="2171100321540926054">"Dados móv: conectado"</string>
- <string name="status_bar_settings_signal_meter_data_connecting" msgid="7183001278053801143">"Dados: conectando..."</string>
-</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index a7a43a8..14b4b1f 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificações"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Conecte o carregador"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"A bateria está ficando baixa:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> ou menos restante(s)."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Uso da bateria"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Recente"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml
index a8625a9..95520db 100644
--- a/packages/SystemUI/res/values-rm/strings.xml
+++ b/packages/SystemUI/res/values-rm/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Avis"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Connectar il chargiabattarias"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"L\'accu è prest vid."</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> u pli pauc restant."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Consum dad accu"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Utilisà sco ultim"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 7b4ad47..b6cfe73 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificări"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Conectaţi încărcătorul"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Bateria se termină:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"A rămas <xliff:g id="NUMBER">%d%%</xliff:g> sau mai puţin."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Utilizarea bateriei"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Recente"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-ru-xlarge/strings.xml b/packages/SystemUI/res/values-ru-xlarge/strings.xml
deleted file mode 100644
index 68b2b9a..0000000
--- a/packages/SystemUI/res/values-ru-xlarge/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for status_bar_clear_all_button (4722520806446512408) -->
- <skip />
- <string name="status_bar_settings_signal_meter_disconnected" msgid="2123001074951934237">"связь отсутствует"</string>
- <!-- no translation found for status_bar_settings_signal_meter_wifi_ssid_format (6261810256542749384) -->
- <skip />
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="160846667119240422">"Wi-Fi: подключено"</string>
- <string name="status_bar_settings_signal_meter_wifi_connecting" msgid="4087640898624652649">"Wi-Fi: подключение..."</string>
- <string name="status_bar_settings_signal_meter_data_connected" msgid="2171100321540926054">"Моб. данные: подключено"</string>
- <string name="status_bar_settings_signal_meter_data_connecting" msgid="7183001278053801143">"Моб. данные: подключение..."</string>
-</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index d597315..0a15bcd 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Уведомления"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Подключите зарядное устройство"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Батарея разряжена:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"Осталось <xliff:g id="NUMBER">%d%%</xliff:g> или меньше."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Расход заряда батареи"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Недавние"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index b4a3221..a55d3b7 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Upozornenia"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Pripojte nabíjačku"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Batéria je skoro vybitá:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"Zostáva <xliff:g id="NUMBER">%d%%</xliff:g> alebo menej."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Využitie batérie"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Najnovšie"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 8783529..a9e5c30 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Obvestila"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Priključite napajalnik"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Baterija je skoraj prazna:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"Preostalo <xliff:g id="NUMBER">%d%%</xliff:g> ali manj."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Uporaba baterije"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Nedavno"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index a4d2bf0..f7dca2a 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Обавештења"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Прикључите пуњач"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Ниво напуњености батерије је низак:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"Преостало је <xliff:g id="NUMBER">%d%%</xliff:g> или мање."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Коришћење батерије"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Недавно"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-sv-xlarge/strings.xml b/packages/SystemUI/res/values-sv-xlarge/strings.xml
deleted file mode 100644
index c1147c7..0000000
--- a/packages/SystemUI/res/values-sv-xlarge/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for status_bar_clear_all_button (4722520806446512408) -->
- <skip />
- <string name="status_bar_settings_signal_meter_disconnected" msgid="2123001074951934237">"ingen Internetanslutn."</string>
- <!-- no translation found for status_bar_settings_signal_meter_wifi_ssid_format (6261810256542749384) -->
- <skip />
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="160846667119240422">"Wi-Fi: ansluten"</string>
- <string name="status_bar_settings_signal_meter_wifi_connecting" msgid="4087640898624652649">"Wi-Fi: ansluter..."</string>
- <string name="status_bar_settings_signal_meter_data_connected" msgid="2171100321540926054">"Mobildata: ansluten"</string>
- <string name="status_bar_settings_signal_meter_data_connecting" msgid="7183001278053801143">"Mobildata: ansluter…"</string>
-</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index f2dc7f1..06188ab 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Meddelanden"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Anslut laddaren"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Batteriet håller på att ta slut:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> eller mindre kvar."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Batteriförbrukning"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Senaste"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index fb25fdf..59b869d 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"การแจ้งเตือน"</string>
<string name="battery_low_title" msgid="7923774589611311406">"โปรดเสียบอุปกรณ์ชาร์จ"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"แบตเตอรี่เหลือน้อย"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"เหลือ <xliff:g id="NUMBER">%d%%</xliff:g> หรือน้อยกว่า"</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"การใช้แบตเตอรี่"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"เมื่อเร็วๆ นี้"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 900de9f..2a075a7 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Mga Notification"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Pakikonekta ang charger"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Humihina ang baterya:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> o mas kaunti ang natitira."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Paggamit ng baterya"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Kamakailan"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-tr-xlarge/strings.xml b/packages/SystemUI/res/values-tr-xlarge/strings.xml
deleted file mode 100644
index cc36b93..0000000
--- a/packages/SystemUI/res/values-tr-xlarge/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for status_bar_clear_all_button (4722520806446512408) -->
- <skip />
- <string name="status_bar_settings_signal_meter_disconnected" msgid="2123001074951934237">"internet bağlantısı yok"</string>
- <!-- no translation found for status_bar_settings_signal_meter_wifi_ssid_format (6261810256542749384) -->
- <skip />
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="160846667119240422">"Kablosuz: bağlı"</string>
- <string name="status_bar_settings_signal_meter_wifi_connecting" msgid="4087640898624652649">"Kablosuz: bağlanıyor..."</string>
- <string name="status_bar_settings_signal_meter_data_connected" msgid="2171100321540926054">"Mobil veri: bağlı"</string>
- <string name="status_bar_settings_signal_meter_data_connecting" msgid="7183001278053801143">"Mob veri: bağlnyr..."</string>
-</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 31451e1..253fbe0 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Bildirimler"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Lütfen şarj cihazını takın"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Pil tükeniyor:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> veya daha az kaldı."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Pil kullanımı"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"En Son Görevler"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index e7b9f19..63088d9 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Сповіщення"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Підключ. заряд. пристрій"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Батарея виснажується:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"Залиш-ся <xliff:g id="NUMBER">%d%%</xliff:g> або менше."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Викор. батареї"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Останні"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index fe11324..8f4927f 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Thông báo"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Vui lòng kết nối bộ sạc"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Pin đang yếu:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"còn <xliff:g id="NUMBER">%d%%</xliff:g> hoặc ít hơn."</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"Sử dụng pin"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"Gần đây"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-zh-rCN-xlarge/strings.xml b/packages/SystemUI/res/values-zh-rCN-xlarge/strings.xml
deleted file mode 100644
index 072bcb0..0000000
--- a/packages/SystemUI/res/values-zh-rCN-xlarge/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for status_bar_clear_all_button (4722520806446512408) -->
- <skip />
- <string name="status_bar_settings_signal_meter_disconnected" msgid="2123001074951934237">"无互联网连接"</string>
- <!-- no translation found for status_bar_settings_signal_meter_wifi_ssid_format (6261810256542749384) -->
- <skip />
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="160846667119240422">"Wi-Fi:已连接"</string>
- <string name="status_bar_settings_signal_meter_wifi_connecting" msgid="4087640898624652649">"Wi-Fi:正在连接..."</string>
- <string name="status_bar_settings_signal_meter_data_connected" msgid="2171100321540926054">"移动数据:已连接"</string>
- <string name="status_bar_settings_signal_meter_data_connecting" msgid="7183001278053801143">"移动数据:正在连接..."</string>
-</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 48218c0..161a085 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
<string name="battery_low_title" msgid="7923774589611311406">"请连接充电器"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"电量所剩不多:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"电量剩余 <xliff:g id="NUMBER">%d%%</xliff:g> 或更少。"</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"电量使用情况"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"近期任务"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/res/values-zh-rTW-xlarge/strings.xml b/packages/SystemUI/res/values-zh-rTW-xlarge/strings.xml
deleted file mode 100644
index 0d06aad..0000000
--- a/packages/SystemUI/res/values-zh-rTW-xlarge/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-/**
- * Copyright (c) 2010, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- -->
-
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for status_bar_clear_all_button (4722520806446512408) -->
- <skip />
- <string name="status_bar_settings_signal_meter_disconnected" msgid="2123001074951934237">"沒有網際網路連線"</string>
- <!-- no translation found for status_bar_settings_signal_meter_wifi_ssid_format (6261810256542749384) -->
- <skip />
- <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="160846667119240422">"Wi-F:已連線"</string>
- <string name="status_bar_settings_signal_meter_wifi_connecting" msgid="4087640898624652649">"Wi-Fi:連線中..."</string>
- <string name="status_bar_settings_signal_meter_data_connected" msgid="2171100321540926054">"行動數據:已連線"</string>
- <string name="status_bar_settings_signal_meter_data_connecting" msgid="7183001278053801143">"行動數據:連線中..."</string>
-</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 10c08d0..eb9108d 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -31,11 +31,18 @@
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
<string name="battery_low_title" msgid="7923774589611311406">"請連接充電器"</string>
<!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"電池電量即將不足:"</string>
- <!-- outdated translation 696154104579022959 --> <string name="battery_low_percent_format" msgid="1077244949318261761">"還剩 <xliff:g id="NUMBER">%d%%</xliff:g> 以下。"</string>
+ <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
+ <skip />
<!-- no translation found for invalid_charger (4549105996740522523) -->
<skip />
<string name="battery_low_why" msgid="7279169609518386372">"電池使用狀況"</string>
- <!-- no translation found for status_bar_settings_settings_button (7832600575390861653) -->
+ <!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_airplane (4879879698500955300) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_rotation_lock (8361452930058000609) -->
+ <skip />
+ <!-- no translation found for status_bar_settings_notifications (397146176280905137) -->
<skip />
<string name="recent_tasks_title" msgid="3691764623638127888">"最新的"</string>
<!-- no translation found for recent_tasks_empty (1905484479067697884) -->
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DoNotDisturb.java b/packages/SystemUI/src/com/android/systemui/statusbar/DoNotDisturb.java
new file mode 100644
index 0000000..9e44e71
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DoNotDisturb.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.systemui.statusbar;
+
+import android.app.StatusBarManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Slog;
+
+import com.android.systemui.statusbar.policy.Prefs;
+
+public class DoNotDisturb implements SharedPreferences.OnSharedPreferenceChangeListener {
+ private Context mContext;
+ private StatusBarManager mStatusBar;
+ SharedPreferences mPrefs;
+ private boolean mDoNotDisturb;
+
+ public DoNotDisturb(Context context) {
+ mContext = context;
+ mStatusBar = (StatusBarManager)context.getSystemService(Context.STATUS_BAR_SERVICE);
+ mPrefs = Prefs.read(context);
+ mPrefs.registerOnSharedPreferenceChangeListener(this);
+ mDoNotDisturb = mPrefs.getBoolean(Prefs.DO_NOT_DISTURB_PREF, Prefs.DO_NOT_DISTURB_DEFAULT);
+ updateDisableRecord();
+ }
+
+ public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
+ final boolean val = prefs.getBoolean(Prefs.DO_NOT_DISTURB_PREF,
+ Prefs.DO_NOT_DISTURB_DEFAULT);
+ if (val != mDoNotDisturb) {
+ mDoNotDisturb = val;
+ updateDisableRecord();
+ }
+ }
+
+ private void updateDisableRecord() {
+ final int disabled = StatusBarManager.DISABLE_NOTIFICATION_ICONS
+ | StatusBarManager.DISABLE_NOTIFICATION_ALERTS
+ | StatusBarManager.DISABLE_NOTIFICATION_TICKER;
+ mStatusBar.disable(mDoNotDisturb ? disabled : 0);
+ }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
index d7f3730..472a225 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBar.java
@@ -53,6 +53,8 @@ public abstract class StatusBar extends SystemUI implements CommandQueue.Callbac
protected abstract View makeStatusBarView();
protected abstract int getStatusBarGravity();
+ private DoNotDisturb mDoNotDisturb;
+
public void start() {
// First set up our views and stuff.
View sb = makeStatusBarView();
@@ -127,5 +129,7 @@ public abstract class StatusBar extends SystemUI implements CommandQueue.Callbac
+ " imeButton=" + switches[3]
);
}
+
+ mDoNotDisturb = new DoNotDisturb(mContext);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DoNotDisturbController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DoNotDisturbController.java
new file mode 100644
index 0000000..94c8aa5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DoNotDisturbController.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.systemui.statusbar.policy;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.Settings;
+import android.util.Slog;
+import android.view.IWindowManager;
+import android.widget.CompoundButton;
+
+public class DoNotDisturbController implements CompoundButton.OnCheckedChangeListener,
+ SharedPreferences.OnSharedPreferenceChangeListener {
+ private static final String TAG = "StatusBar.DoNotDisturbController";
+
+ SharedPreferences mPrefs;
+ private Context mContext;
+ private CompoundButton mCheckBox;
+
+ private boolean mDoNotDisturb;
+
+ public DoNotDisturbController(Context context, CompoundButton checkbox) {
+ mContext = context;
+
+ mPrefs = Prefs.read(context);
+ mPrefs.registerOnSharedPreferenceChangeListener(this);
+ mDoNotDisturb = mPrefs.getBoolean(Prefs.DO_NOT_DISTURB_PREF, Prefs.DO_NOT_DISTURB_DEFAULT);
+
+ mCheckBox = checkbox;
+ checkbox.setOnCheckedChangeListener(this);
+
+ checkbox.setChecked(!mDoNotDisturb);
+ }
+
+ // The checkbox is ON for notifications coming in and OFF for Do not disturb, so we
+ // don't have a double negative.
+ public void onCheckedChanged(CompoundButton view, boolean checked) {
+ //Slog.d(TAG, "onCheckedChanged checked=" + checked + " mDoNotDisturb=" + mDoNotDisturb);
+ final boolean value = !checked;
+ if (value != mDoNotDisturb) {
+ SharedPreferences.Editor editor = Prefs.edit(mContext);
+ editor.putBoolean(Prefs.DO_NOT_DISTURB_PREF, value);
+ editor.apply();
+ }
+ }
+
+ public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
+ final boolean val = prefs.getBoolean(Prefs.DO_NOT_DISTURB_PREF,
+ Prefs.DO_NOT_DISTURB_DEFAULT);
+ if (val != mDoNotDisturb) {
+ mDoNotDisturb = val;
+ mCheckBox.setChecked(!val);
+ }
+ }
+
+ public void release() {
+ mPrefs.unregisterOnSharedPreferenceChangeListener(this);
+ }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java
new file mode 100644
index 0000000..05eafe8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.systemui.statusbar.policy;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+public class Prefs {
+ private static final String SHARED_PREFS_NAME = "status_bar";
+
+ // a boolean
+ public static final String DO_NOT_DISTURB_PREF = "do_not_disturb";
+ public static final boolean DO_NOT_DISTURB_DEFAULT = false;
+
+ public static SharedPreferences read(Context context) {
+ return context.getSharedPreferences(Prefs.SHARED_PREFS_NAME, Context.MODE_PRIVATE);
+ }
+
+ public static SharedPreferences.Editor edit(Context context) {
+ return context.getSharedPreferences(Prefs.SHARED_PREFS_NAME, Context.MODE_PRIVATE).edit();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java
index f9ba908..d1f8dd0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/SettingsView.java
@@ -31,12 +31,14 @@ import android.widget.TextView;
import com.android.systemui.R;
import com.android.systemui.statusbar.policy.AirplaneModeController;
import com.android.systemui.statusbar.policy.AutoRotateController;
+import com.android.systemui.statusbar.policy.DoNotDisturbController;
public class SettingsView extends LinearLayout implements View.OnClickListener {
static final String TAG = "SettingsView";
AirplaneModeController mAirplane;
AutoRotateController mRotate;
+ DoNotDisturbController mDoNotDisturb;
public SettingsView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
@@ -57,6 +59,8 @@ public class SettingsView extends LinearLayout implements View.OnClickListener {
findViewById(R.id.network).setOnClickListener(this);
mRotate = new AutoRotateController(context,
(CompoundButton)findViewById(R.id.rotate_checkbox));
+ mDoNotDisturb = new DoNotDisturbController(context,
+ (CompoundButton)findViewById(R.id.do_not_disturb_checkbox));
findViewById(R.id.settings).setOnClickListener(this);
}
@@ -64,6 +68,7 @@ public class SettingsView extends LinearLayout implements View.OnClickListener {
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mAirplane.release();
+ mDoNotDisturb.release();
}
public void onClick(View v) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index 3cae088..31311a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -159,7 +159,9 @@ public class TabletStatusBar extends StatusBar {
mBatteryController.addLabelView(
(TextView)mNotificationPanel.findViewById(R.id.battery_text));
mNetworkController.addCombinedSignalIconView(
- (ImageView)mNotificationPanel.findViewById(R.id.network));
+ (ImageView)mNotificationPanel.findViewById(R.id.network_signal));
+ mNetworkController.addDataTypeIconView(
+ (ImageView)mNotificationPanel.findViewById(R.id.network_type));
mNetworkController.addLabelView(
(TextView)mNotificationPanel.findViewById(R.id.network_text));
@@ -283,7 +285,10 @@ public class TabletStatusBar extends StatusBar {
mBatteryController = new BatteryController(mContext);
mBatteryController.addIconView((ImageView)sb.findViewById(R.id.battery));
mNetworkController = new NetworkController(mContext);
- mNetworkController.addCombinedSignalIconView((ImageView)sb.findViewById(R.id.network));
+ mNetworkController.addCombinedSignalIconView(
+ (ImageView)sb.findViewById(R.id.network_signal));
+ mNetworkController.addDataTypeIconView(
+ (ImageView)sb.findViewById(R.id.network_type));
// The navigation buttons
mNavigationArea = sb.findViewById(R.id.navigationArea);
@@ -491,7 +496,7 @@ public class TabletStatusBar extends StatusBar {
final RemoteViews contentView = notification.notification.contentView;
- if (false) {
+ if (DEBUG) {
Slog.d(TAG, "old notification: when=" + oldNotification.notification.when
+ " ongoing=" + oldNotification.isOngoing()
+ " expanded=" + oldEntry.expanded
@@ -503,7 +508,7 @@ public class TabletStatusBar extends StatusBar {
// Can we just reapply the RemoteViews in place? If when didn't change, the order
// didn't change.
- if (notification.notification.when == oldNotification.notification.when
+ boolean orderUnchanged = (notification.notification.when == oldNotification.notification.when
&& notification.isOngoing() == oldNotification.isOngoing()
&& oldEntry.expanded != null
&& contentView != null
@@ -511,7 +516,10 @@ public class TabletStatusBar extends StatusBar {
&& contentView.getPackage() != null
&& oldContentView.getPackage() != null
&& oldContentView.getPackage().equals(contentView.getPackage())
- && oldContentView.getLayoutId() == contentView.getLayoutId()) {
+ && oldContentView.getLayoutId() == contentView.getLayoutId());
+ ViewGroup rowParent = (ViewGroup) oldEntry.row.getParent();
+ boolean isLastAnyway = rowParent.indexOfChild(oldEntry.row) == rowParent.getChildCount() - 1;
+ if (orderUnchanged || isLastAnyway) {
if (DEBUG) Slog.d(TAG, "reusing notification for key: " + key);
oldEntry.notification = notification;
try {
@@ -580,12 +588,12 @@ public class TabletStatusBar extends StatusBar {
if ((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) {
Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: yes");
// synchronize with current shadow state
- mShadowController.hideElement(mNotificationArea);
+ mShadowController.hideElement(mNotificationIconArea);
mTicker.halt();
} else {
Slog.d(TAG, "DISABLE_NOTIFICATION_ICONS: no");
// synchronize with current shadow state
- mShadowController.showElement(mNotificationArea);
+ mShadowController.showElement(mNotificationIconArea);
}
} else if ((diff & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
if ((state & StatusBarManager.DISABLE_NOTIFICATION_TICKER) != 0) {
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
index 42b73b9..72af34d 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
@@ -281,7 +281,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
mUpdateMonitor.registerSimStateCallback(this);
mLockPatternUtils = new LockPatternUtils(mContext);
- mKeyguardViewProperties
+ mKeyguardViewProperties
= new LockPatternKeyguardViewProperties(mLockPatternUtils, mUpdateMonitor);
mKeyguardViewManager = new KeyguardViewManager(
@@ -589,6 +589,11 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
return;
}
+ if (mLockPatternUtils.isLockScreenDisabled()) {
+ if (DEBUG) Log.d(TAG, "doKeyguard: not showing because lockscreen is off");
+ return;
+ }
+
if (DEBUG) Log.d(TAG, "doKeyguard: showing the lock screen");
showLocked();
}
@@ -1005,7 +1010,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
Log.d(TAG, "playSounds: whichSound = " + whichSound + "; soundPath was null");
}
}
- }
+ }
/**
* Handle message sent by {@link #showLocked}.
diff --git a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java b/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
index a8dd76c..abed18f 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
@@ -32,7 +32,8 @@ import android.view.FallbackEventHandler;
import android.view.KeyEvent;
public class PhoneFallbackEventHandler implements FallbackEventHandler {
- static String TAG = "PhoneFallbackEventHandler";
+ private static String TAG = "PhoneFallbackEventHandler";
+ private static final boolean DEBUG = false;
Context mContext;
View mView;
@@ -180,7 +181,9 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler {
}
boolean onKeyUp(int keyCode, KeyEvent event) {
- Slog.d(TAG, "up " + keyCode);
+ if (DEBUG) {
+ Slog.d(TAG, "up " + keyCode);
+ }
final KeyEvent.DispatcherState dispatcher = mView.getKeyDispatcherState();
if (dispatcher != null) {
dispatcher.handleUpEvent(event);
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 1373627..c528745 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -1215,11 +1215,13 @@ public class PhoneWindowManager implements WindowManagerPolicy {
/** {@inheritDoc} */
@Override
- public boolean interceptKeyBeforeDispatching(WindowState win, int action, int flags,
- int keyCode, int scanCode, int metaState, int repeatCount, int policyFlags) {
+ public boolean interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) {
final boolean keyguardOn = keyguardOn();
- final boolean down = (action == KeyEvent.ACTION_DOWN);
- final boolean canceled = ((flags & KeyEvent.FLAG_CANCELED) != 0);
+ final int keyCode = event.getKeyCode();
+ final int repeatCount = event.getRepeatCount();
+ final int metaState = event.getMetaState();
+ final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
+ final boolean canceled = event.isCanceled();
if (false) {
Log.d(TAG, "interceptKeyTi keyCode=" + keyCode + " down=" + down + " repeatCount="
@@ -1348,7 +1350,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// Shortcuts are invoked through Search+key, so intercept those here
if (mSearchKeyPressed) {
if (down && repeatCount == 0 && !keyguardOn) {
- Intent shortcutIntent = mShortcutManager.getIntent(keyCode, metaState);
+ Intent shortcutIntent = mShortcutManager.getIntent(event);
if (shortcutIntent != null) {
shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(shortcutIntent);
@@ -1368,13 +1370,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
/** {@inheritDoc} */
@Override
- public boolean dispatchUnhandledKey(WindowState win, int action, int flags,
- int keyCode, int scanCode, int metaState, int repeatCount, int policyFlags) {
+ public boolean dispatchUnhandledKey(WindowState win, KeyEvent event, int policyFlags) {
if (false) {
- Slog.d(TAG, "Unhandled key: win=" + win + ", action=" + action
- + ", flags=" + flags + ", keyCode=" + keyCode
- + ", scanCode=" + scanCode + ", metaState=" + metaState
- + ", repeatCount=" + repeatCount + ", policyFlags=" + policyFlags);
+ Slog.d(TAG, "Unhandled key: win=" + win + ", action=" + event.getAction()
+ + ", flags=" + event.getFlags()
+ + ", keyCode=" + event.getKeyCode()
+ + ", scanCode=" + event.getScanCode()
+ + ", metaState=" + event.getMetaState()
+ + ", repeatCount=" + event.getRepeatCount()
+ + ", policyFlags=" + policyFlags);
}
return false;
}
@@ -1970,10 +1974,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
/** {@inheritDoc} */
@Override
- public int interceptKeyBeforeQueueing(long whenNanos, int action, int flags,
- int keyCode, int scanCode, int policyFlags, boolean isScreenOn) {
- final boolean down = action == KeyEvent.ACTION_DOWN;
- final boolean canceled = (flags & KeyEvent.FLAG_CANCELED) != 0;
+ public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
+ final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
+ final boolean canceled = event.isCanceled();
+ final int keyCode = event.getKeyCode();
final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;
@@ -2164,12 +2168,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// Only do this if we would otherwise not pass it to the user. In that
// case, the PhoneWindow class will do the same thing, except it will
// only do it if the showing app doesn't process the key on its own.
- long when = whenNanos / 1000000;
- KeyEvent keyEvent = new KeyEvent(when, when, action, keyCode, 0, 0,
- KeyCharacterMap.VIRTUAL_KEYBOARD, scanCode, flags,
- InputDevice.SOURCE_KEYBOARD);
mBroadcastWakeLock.acquire();
- mHandler.post(new PassHeadsetKey(keyEvent));
+ mHandler.post(new PassHeadsetKey(new KeyEvent(event)));
}
break;
}
diff --git a/policy/src/com/android/internal/policy/impl/ShortcutManager.java b/policy/src/com/android/internal/policy/impl/ShortcutManager.java
index 51377d8..fc66a20 100644
--- a/policy/src/com/android/internal/policy/impl/ShortcutManager.java
+++ b/policy/src/com/android/internal/policy/impl/ShortcutManager.java
@@ -25,6 +25,7 @@ import android.provider.Settings;
import android.util.Log;
import android.util.SparseArray;
import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
import java.net.URISyntaxException;
@@ -100,20 +101,17 @@ class ShortcutManager extends ContentObserver {
* This will first try an exact match (with modifiers), and then try a
* match without modifiers (primary character on a key).
*
- * @param keyCode The keycode of the key pushed.
- * @param modifiers The modifiers without any that are used for chording
- * to invoke a shortcut.
+ * @param event The key event of the key that was pressed.
* @return The intent that matches the shortcut, or null if not found.
*/
- public Intent getIntent(int keyCode, int modifiers) {
- KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
+ public Intent getIntent(KeyEvent event) {
// First try the exact keycode (with modifiers)
- int shortcut = kcm.get(keyCode, modifiers);
+ int shortcut = event.getUnicodeChar();
Intent intent = shortcut != 0 ? mShortcutIntents.get(shortcut) : null;
if (intent != null) return intent;
-
+
// Next try the keycode without modifiers (the primary character on that key)
- shortcut = Character.toLowerCase(kcm.get(keyCode, 0));
+ shortcut = Character.toLowerCase(event.getUnicodeChar(0));
return shortcut != 0 ? mShortcutIntents.get(shortcut) : null;
}
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index a0013d0..535f07f 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -277,10 +277,6 @@ void CameraService::releaseSound() {
void CameraService::playSound(sound_kind kind) {
LOG1("playSound(%d)", kind);
- // FIXME: temporarily disable sound while working on audio HAL issues preventing simultaneous
- // playback and record
- if (kind == SOUND_RECORDING) return;
-
Mutex::Autolock lock(mSoundLock);
sp<MediaPlayer> player = mSoundPlayer[kind];
if (player != 0) {
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index bebd013..2651fd3 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -198,22 +198,26 @@ class BackupManagerService extends IBackupManager.Stub {
public long token;
public PackageInfo pkgInfo;
public int pmToken; // in post-install restore, the PM's token for this transaction
+ public boolean needFullBackup;
RestoreParams(IBackupTransport _transport, IRestoreObserver _obs,
- long _token, PackageInfo _pkg, int _pmToken) {
+ long _token, PackageInfo _pkg, int _pmToken, boolean _needFullBackup) {
transport = _transport;
observer = _obs;
token = _token;
pkgInfo = _pkg;
pmToken = _pmToken;
+ needFullBackup = _needFullBackup;
}
- RestoreParams(IBackupTransport _transport, IRestoreObserver _obs, long _token) {
+ RestoreParams(IBackupTransport _transport, IRestoreObserver _obs, long _token,
+ boolean _needFullBackup) {
transport = _transport;
observer = _obs;
token = _token;
pkgInfo = null;
pmToken = 0;
+ needFullBackup = _needFullBackup;
}
}
@@ -323,7 +327,8 @@ class BackupManagerService extends IBackupManager.Stub {
RestoreParams params = (RestoreParams)msg.obj;
Slog.d(TAG, "MSG_RUN_RESTORE observer=" + params.observer);
(new PerformRestoreTask(params.transport, params.observer,
- params.token, params.pkgInfo, params.pmToken)).run();
+ params.token, params.pkgInfo, params.pmToken,
+ params.needFullBackup)).run();
break;
}
@@ -1560,6 +1565,7 @@ class BackupManagerService extends IBackupManager.Stub {
private PackageInfo mTargetPackage;
private File mStateDir;
private int mPmToken;
+ private boolean mNeedFullBackup;
class RestoreRequest {
public PackageInfo app;
@@ -1572,12 +1578,14 @@ class BackupManagerService extends IBackupManager.Stub {
}
PerformRestoreTask(IBackupTransport transport, IRestoreObserver observer,
- long restoreSetToken, PackageInfo targetPackage, int pmToken) {
+ long restoreSetToken, PackageInfo targetPackage, int pmToken,
+ boolean needFullBackup) {
mTransport = transport;
mObserver = observer;
mToken = restoreSetToken;
mTargetPackage = targetPackage;
mPmToken = pmToken;
+ mNeedFullBackup = needFullBackup;
try {
mStateDir = new File(mBaseStateDir, transport.transportDirName());
@@ -1655,7 +1663,8 @@ class BackupManagerService extends IBackupManager.Stub {
// Pull the Package Manager metadata from the restore set first
pmAgent = new PackageManagerBackupAgent(
mPackageManager, agentPackages);
- processOneRestore(omPackage, 0, IBackupAgent.Stub.asInterface(pmAgent.onBind()));
+ processOneRestore(omPackage, 0, IBackupAgent.Stub.asInterface(pmAgent.onBind()),
+ mNeedFullBackup);
// Verify that the backup set includes metadata. If not, we can't do
// signature/version verification etc, so we simply do not proceed with
@@ -1752,7 +1761,8 @@ class BackupManagerService extends IBackupManager.Stub {
// And then finally run the restore on this agent
try {
- processOneRestore(packageInfo, metaInfo.versionCode, agent);
+ processOneRestore(packageInfo, metaInfo.versionCode, agent,
+ mNeedFullBackup);
++count;
} finally {
// unbind and tidy up even on timeout or failure, just in case
@@ -1822,7 +1832,8 @@ class BackupManagerService extends IBackupManager.Stub {
}
// Do the guts of a restore of one application, using mTransport.getRestoreData().
- void processOneRestore(PackageInfo app, int appVersionCode, IBackupAgent agent) {
+ void processOneRestore(PackageInfo app, int appVersionCode, IBackupAgent agent,
+ boolean needFullBackup) {
// !!! TODO: actually run the restore through mTransport
final String packageName = app.packageName;
@@ -1901,6 +1912,14 @@ class BackupManagerService extends IBackupManager.Stub {
try { if (newState != null) newState.close(); } catch (IOException e) {}
backupData = newState = null;
mCurrentOperations.delete(token);
+
+ // If we know a priori that we'll need to perform a full post-restore backup
+ // pass, clear the new state file data. This means we're discarding work that
+ // was just done by the app's agent, but this way the agent doesn't need to
+ // take any special action based on global device state.
+ if (needFullBackup) {
+ newStateName.delete();
+ }
}
}
}
@@ -2386,7 +2405,7 @@ class BackupManagerService extends IBackupManager.Stub {
mWakelock.acquire();
Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
msg.obj = new RestoreParams(getTransport(mCurrentTransport), null,
- restoreSet, pkg, token);
+ restoreSet, pkg, token, true);
mBackupHandler.sendMessage(msg);
} else {
// Auto-restore disabled or no way to attempt a restore; just tell the Package
@@ -2517,7 +2536,7 @@ class BackupManagerService extends IBackupManager.Stub {
long oldId = Binder.clearCallingIdentity();
mWakelock.acquire();
Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
- msg.obj = new RestoreParams(mRestoreTransport, observer, token);
+ msg.obj = new RestoreParams(mRestoreTransport, observer, token, true);
mBackupHandler.sendMessage(msg);
Binder.restoreCallingIdentity(oldId);
return 0;
@@ -2582,7 +2601,7 @@ class BackupManagerService extends IBackupManager.Stub {
long oldId = Binder.clearCallingIdentity();
mWakelock.acquire();
Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
- msg.obj = new RestoreParams(mRestoreTransport, observer, token, app, 0);
+ msg.obj = new RestoreParams(mRestoreTransport, observer, token, app, 0, false);
mBackupHandler.sendMessage(msg);
Binder.restoreCallingIdentity(oldId);
return 0;
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index 53a19f5..0dead1c 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -407,17 +407,29 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
context.registerReceiver(mReceiver, filter);
}
+ /**
+ * Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration
+ * reminders. Clears alarm if no expirations are configured.
+ */
protected void setExpirationAlarmCheckLocked(Context context) {
final long expiration = getPasswordExpirationLocked(null);
final long now = System.currentTimeMillis();
final long timeToExpire = expiration - now;
final long alarmTime;
- if (timeToExpire > 0L && timeToExpire < MS_PER_DAY) {
- // Next expiration is less than a day, set alarm for exact expiration time
- alarmTime = now + timeToExpire;
- } else {
- // Check again in 24 hours...
+ if (expiration == 0) {
+ // No expirations are currently configured: Cancel alarm.
+ alarmTime = 0;
+ } else if (timeToExpire <= 0) {
+ // The password has already expired: Repeat every 24 hours.
alarmTime = now + MS_PER_DAY;
+ } else {
+ // Selecting the next alarm time: Roll forward to the next 24 hour multiple before
+ // the expiration time.
+ long alarmInterval = timeToExpire % MS_PER_DAY;
+ if (alarmInterval == 0) {
+ alarmInterval = MS_PER_DAY;
+ }
+ alarmTime = now + alarmInterval;
}
long token = Binder.clearCallingIdentity();
@@ -427,7 +439,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION),
PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT);
am.cancel(pi);
- am.set(AlarmManager.RTC, alarmTime, pi);
+ if (alarmTime != 0) {
+ am.set(AlarmManager.RTC, alarmTime, pi);
+ }
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -794,7 +808,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)
&& admin.passwordExpirationTimeout > 0L
&& admin.passwordExpirationDate > 0L
- && now > admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS) {
+ && now >= admin.passwordExpirationDate - EXPIRATION_GRACE_PERIOD_MS) {
sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING);
}
}
@@ -1007,14 +1021,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
+ /**
+ * Return a single admin's expiration cycle time, or the min of all cycle times.
+ * Returns 0 if not configured.
+ */
public long getPasswordExpirationTimeout(ComponentName who) {
synchronized (this) {
- long timeout = 0L;
if (who != null) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
- return admin != null ? admin.passwordExpirationTimeout : timeout;
+ return admin != null ? admin.passwordExpirationTimeout : 0L;
}
+ long timeout = 0L;
final int N = mAdminList.size();
for (int i = 0; i < N; i++) {
ActiveAdmin admin = mAdminList.get(i);
@@ -1027,13 +1045,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
+ /**
+ * Return a single admin's expiration date/time, or the min (soonest) for all admins.
+ * Returns 0 if not configured.
+ */
private long getPasswordExpirationLocked(ComponentName who) {
- long timeout = 0L;
if (who != null) {
ActiveAdmin admin = getActiveAdminUncheckedLocked(who);
- return admin != null ? admin.passwordExpirationDate : timeout;
+ return admin != null ? admin.passwordExpirationDate : 0L;
}
+ long timeout = 0L;
final int N = mAdminList.size();
for (int i = 0; i < N; i++) {
ActiveAdmin admin = mAdminList.get(i);
@@ -1606,6 +1628,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mFailedPasswordAttempts = 0;
saveSettingsLocked();
updatePasswordExpirationsLocked();
+ setExpirationAlarmCheckLocked(mContext);
sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
} finally {
@@ -1615,14 +1638,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
+ /**
+ * Called any time the device password is updated. Resets all password expiration clocks.
+ */
private void updatePasswordExpirationsLocked() {
final int N = mAdminList.size();
if (N > 0) {
for (int i=0; i<N; i++) {
ActiveAdmin admin = mAdminList.get(i);
if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) {
- admin.passwordExpirationDate = System.currentTimeMillis()
- + admin.passwordExpirationTimeout;
+ long timeout = admin.passwordExpirationTimeout;
+ long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L;
+ admin.passwordExpirationDate = expiration;
}
}
saveSettingsLocked();
diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java
index 4364c04..9078811 100644
--- a/services/java/com/android/server/InputManager.java
+++ b/services/java/com/android/server/InputManager.java
@@ -30,6 +30,7 @@ import android.util.Xml;
import android.view.InputChannel;
import android.view.InputDevice;
import android.view.InputEvent;
+import android.view.KeyEvent;
import android.view.Surface;
import java.io.BufferedReader;
@@ -41,7 +42,6 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
-import java.util.Properties;
/*
* Wraps the C++ InputManager and provides its callbacks.
@@ -368,11 +368,6 @@ public class InputManager {
public int height;
}
- private static final class InputDeviceCalibration {
- public String[] keys;
- public String[] values;
- }
-
/*
* Callbacks from native.
*/
@@ -404,26 +399,23 @@ public class InputManager {
}
@SuppressWarnings("unused")
- public int interceptKeyBeforeQueueing(long whenNanos, int action, int flags,
- int keyCode, int scanCode, int policyFlags, boolean isScreenOn) {
+ public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
return mWindowManagerService.mInputMonitor.interceptKeyBeforeQueueing(
- whenNanos, action, flags, keyCode, scanCode, policyFlags, isScreenOn);
+ event, policyFlags, isScreenOn);
}
@SuppressWarnings("unused")
- public boolean interceptKeyBeforeDispatching(InputChannel focus, int action,
- int flags, int keyCode, int scanCode, int metaState, int repeatCount,
- int policyFlags) {
- return mWindowManagerService.mInputMonitor.interceptKeyBeforeDispatching(focus,
- action, flags, keyCode, scanCode, metaState, repeatCount, policyFlags);
+ public boolean interceptKeyBeforeDispatching(InputChannel focus,
+ KeyEvent event, int policyFlags) {
+ return mWindowManagerService.mInputMonitor.interceptKeyBeforeDispatching(
+ focus, event, policyFlags);
}
@SuppressWarnings("unused")
- public boolean dispatchUnhandledKey(InputChannel focus, int action,
- int flags, int keyCode, int scanCode, int metaState, int repeatCount,
- int policyFlags) {
- return mWindowManagerService.mInputMonitor.dispatchUnhandledKey(focus,
- action, flags, keyCode, scanCode, metaState, repeatCount, policyFlags);
+ public boolean dispatchUnhandledKey(InputChannel focus,
+ KeyEvent event, int policyFlags) {
+ return mWindowManagerService.mInputMonitor.dispatchUnhandledKey(
+ focus, event, policyFlags);
}
@SuppressWarnings("unused")
@@ -494,33 +486,6 @@ public class InputManager {
}
@SuppressWarnings("unused")
- public InputDeviceCalibration getInputDeviceCalibration(String deviceName) {
- // Calibration is specified as a sequence of colon-delimited key value pairs.
- Properties properties = new Properties();
- File calibrationFile = new File(Environment.getRootDirectory(),
- CALIBRATION_DIR_PATH + deviceName + ".idc");
- if (calibrationFile.exists()) {
- try {
- FileInputStream fis = new FileInputStream(calibrationFile);
- properties.load(fis);
- fis.close();
- } catch (IOException ex) {
- Slog.w(TAG, "Error reading input device calibration properties for device "
- + deviceName + " from " + calibrationFile + ".", ex);
- }
- } else {
- Slog.i(TAG, "No input device calibration properties found for device "
- + deviceName + ".");
- return null;
- }
-
- InputDeviceCalibration calibration = new InputDeviceCalibration();
- calibration.keys = properties.keySet().toArray(new String[properties.size()]);
- calibration.values = properties.values().toArray(new String[properties.size()]);
- return calibration;
- }
-
- @SuppressWarnings("unused")
public String[] getExcludedDeviceNames() {
ArrayList<String> names = new ArrayList<String>();
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index c7bfdc8..95200fa 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -55,7 +55,6 @@ import android.os.IBinder;
import android.os.IInterface;
import android.os.Message;
import android.os.Parcel;
-import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
@@ -125,6 +124,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
private static final String SUBTYPE_MODE_VOICE = "voice";
final Context mContext;
+ final Resources mRes;
final Handler mHandler;
final InputMethodSettings mSettings;
final SettingsObserver mSettingsObserver;
@@ -468,6 +468,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
public InputMethodManagerService(Context context, StatusBarManagerService statusBar) {
mContext = context;
+ mRes = context.getResources();
mHandler = new Handler(this);
mIWindowManager = IWindowManager.Stub.asInterface(
ServiceManager.getService(Context.WINDOW_SERVICE));
@@ -1214,11 +1215,22 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
mCurFocusedWindow = windowToken;
+ // Should we auto-show the IME even if the caller has not
+ // specified what should be done with it?
+ // We only do this automatically if the window can resize
+ // to accommodate the IME (so what the user sees will give
+ // them good context without input information being obscured
+ // by the IME) or if running on a large screen where there
+ // is more room for the target window + IME.
+ final boolean doAutoShow =
+ (softInputMode & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
+ == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
+ || mRes.getConfiguration().isLayoutSizeAtLeast(
+ Configuration.SCREENLAYOUT_SIZE_LARGE);
+
switch (softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE) {
case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
- if (!isTextEditor || (softInputMode &
- WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
- != WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) {
+ if (!isTextEditor || !doAutoShow) {
if (WindowManager.LayoutParams.mayUseInputMethod(windowFlags)) {
// There is no focus view, and this window will
// be behind any soft input window, so hide the
@@ -1226,13 +1238,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (DEBUG) Slog.v(TAG, "Unspecified window will hide input");
hideCurrentInputLocked(InputMethodManager.HIDE_NOT_ALWAYS, null);
}
- } else if (isTextEditor && (softInputMode &
- WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
- == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
- && (softInputMode &
- WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
+ } else if (isTextEditor && doAutoShow && (softInputMode &
+ WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
// There is a focus view, and we are navigating forward
// into the window, so show the input window for the user.
+ // We only do this automatically if the window an resize
+ // to accomodate the IME (so what the user sees will give
+ // them good context without input information being obscured
+ // by the IME) or if running on a large screen where there
+ // is more room for the target window + IME.
if (DEBUG) Slog.v(TAG, "Unspecified window will show input");
showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
}
@@ -1544,7 +1558,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
map.clear();
PackageManager pm = mContext.getPackageManager();
- final Configuration config = mContext.getResources().getConfiguration();
+ final Configuration config = mRes.getConfiguration();
final boolean haveHardKeyboard = config.keyboard == Configuration.KEYBOARD_QWERTY;
String disabledSysImes = Settings.Secure.getString(mContext.getContentResolver(),
Secure.DISABLED_SYSTEM_INPUT_METHODS);
@@ -1944,7 +1958,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return null;
}
if (TextUtils.isEmpty(locale)) {
- locale = mContext.getResources().getConfiguration().locale.toString();
+ locale = mRes.getConfiguration().locale.toString();
}
final String language = locale.substring(0, 2);
boolean partialMatchFound = false;
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 6de7e6a..7101bb0 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -41,7 +41,6 @@ import android.database.ContentObserver;
import android.hardware.Usb;
import android.media.AudioManager;
import android.net.Uri;
-import android.os.BatteryManager;
import android.os.Bundle;
import android.os.Binder;
import android.os.Handler;
@@ -61,7 +60,6 @@ import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.widget.Toast;
-import android.widget.Toast;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -92,7 +90,6 @@ public class NotificationManagerService extends INotificationManager.Stub
private WorkerHandler mHandler;
private StatusBarManagerService mStatusBar;
- private LightsService mLightsService;
private LightsService.Light mNotificationLight;
private LightsService.Light mAttentionLight;
@@ -440,7 +437,7 @@ public class NotificationManagerService extends INotificationManager.Stub
mDisabledNotifications = StatusBarManager.DISABLE_NOTIFICATION_ALERTS;
}
- // register for battery changed notifications
+ // register for various Intents
IntentFilter filter = new IntentFilter();
filter.addAction(Usb.ACTION_USB_STATE);
filter.addAction(Intent.ACTION_SCREEN_ON);
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index cbb35c6..5e49404 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -5829,30 +5829,25 @@ public class WindowManagerService extends IWindowManager.Stub
/* Provides an opportunity for the window manager policy to intercept early key
* processing as soon as the key has been read from the device. */
- public int interceptKeyBeforeQueueing(long whenNanos, int action, int flags,
- int keyCode, int scanCode, int policyFlags, boolean isScreenOn) {
- return mPolicy.interceptKeyBeforeQueueing(whenNanos, action, flags,
- keyCode, scanCode, policyFlags, isScreenOn);
+ public int interceptKeyBeforeQueueing(
+ KeyEvent event, int policyFlags, boolean isScreenOn) {
+ return mPolicy.interceptKeyBeforeQueueing(event, policyFlags, isScreenOn);
}
/* Provides an opportunity for the window manager policy to process a key before
* ordinary dispatch. */
- public boolean interceptKeyBeforeDispatching(InputChannel focus,
- int action, int flags, int keyCode, int scanCode, int metaState, int repeatCount,
- int policyFlags) {
+ public boolean interceptKeyBeforeDispatching(
+ InputChannel focus, KeyEvent event, int policyFlags) {
WindowState windowState = getWindowStateForInputChannel(focus);
- return mPolicy.interceptKeyBeforeDispatching(windowState, action, flags,
- keyCode, scanCode, metaState, repeatCount, policyFlags);
+ return mPolicy.interceptKeyBeforeDispatching(windowState, event, policyFlags);
}
/* Provides an opportunity for the window manager policy to process a key that
* the application did not handle. */
- public boolean dispatchUnhandledKey(InputChannel focus,
- int action, int flags, int keyCode, int scanCode, int metaState, int repeatCount,
- int policyFlags) {
+ public boolean dispatchUnhandledKey(
+ InputChannel focus, KeyEvent event, int policyFlags) {
WindowState windowState = getWindowStateForInputChannel(focus);
- return mPolicy.dispatchUnhandledKey(windowState, action, flags,
- keyCode, scanCode, metaState, repeatCount, policyFlags);
+ return mPolicy.dispatchUnhandledKey(windowState, event, policyFlags);
}
/* Called when the current input focus changes.
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index 3fd6965..aa84db5 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -57,7 +57,6 @@ static struct {
jmethodID filterTouchEvents;
jmethodID filterJumpyTouchEvents;
jmethodID getVirtualKeyDefinitions;
- jmethodID getInputDeviceCalibration;
jmethodID getExcludedDeviceNames;
jmethodID getMaxEventsPerSecond;
} gCallbacksClassInfo;
@@ -75,13 +74,6 @@ static struct {
static struct {
jclass clazz;
- jfieldID keys;
- jfieldID values;
-} gInputDeviceCalibrationClassInfo;
-
-static struct {
- jclass clazz;
-
jfieldID inputChannel;
jfieldID name;
jfieldID layoutParamsFlags;
@@ -186,8 +178,6 @@ public:
virtual bool filterJumpyTouchEvents();
virtual void getVirtualKeyDefinitions(const String8& deviceName,
Vector<VirtualKeyDefinition>& outVirtualKeyDefinitions);
- virtual void getInputDeviceCalibration(const String8& deviceName,
- InputDeviceCalibration& outCalibration);
virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames);
/* --- InputDispatcherPolicyInterface implementation --- */
@@ -201,9 +191,7 @@ public:
virtual nsecs_t getKeyRepeatTimeout();
virtual nsecs_t getKeyRepeatDelay();
virtual int32_t getMaxEventsPerSecond();
- virtual void interceptKeyBeforeQueueing(nsecs_t when, int32_t deviceId,
- int32_t action, int32_t& flags, int32_t keyCode, int32_t scanCode,
- uint32_t& policyFlags);
+ virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags);
virtual void interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags);
virtual bool interceptKeyBeforeDispatching(const sp<InputChannel>& inputChannel,
const KeyEvent* keyEvent, uint32_t policyFlags);
@@ -489,48 +477,6 @@ void NativeInputManager::getVirtualKeyDefinitions(const String8& deviceName,
}
}
-void NativeInputManager::getInputDeviceCalibration(const String8& deviceName,
- InputDeviceCalibration& outCalibration) {
- outCalibration.clear();
-
- JNIEnv* env = jniEnv();
-
- jstring deviceNameStr = env->NewStringUTF(deviceName.string());
- if (! checkAndClearExceptionFromCallback(env, "getInputDeviceCalibration")) {
- jobject result = env->CallObjectMethod(mCallbacksObj,
- gCallbacksClassInfo.getInputDeviceCalibration, deviceNameStr);
- if (! checkAndClearExceptionFromCallback(env, "getInputDeviceCalibration") && result) {
- jobjectArray keys = jobjectArray(env->GetObjectField(result,
- gInputDeviceCalibrationClassInfo.keys));
- jobjectArray values = jobjectArray(env->GetObjectField(result,
- gInputDeviceCalibrationClassInfo.values));
-
- jsize length = env->GetArrayLength(keys);
- for (jsize i = 0; i < length; i++) {
- jstring keyStr = jstring(env->GetObjectArrayElement(keys, i));
- jstring valueStr = jstring(env->GetObjectArrayElement(values, i));
-
- const char* keyChars = env->GetStringUTFChars(keyStr, NULL);
- String8 key(keyChars);
- env->ReleaseStringUTFChars(keyStr, keyChars);
-
- const char* valueChars = env->GetStringUTFChars(valueStr, NULL);
- String8 value(valueChars);
- env->ReleaseStringUTFChars(valueStr, valueChars);
-
- outCalibration.addProperty(key, value);
-
- env->DeleteLocalRef(keyStr);
- env->DeleteLocalRef(valueStr);
- }
- env->DeleteLocalRef(keys);
- env->DeleteLocalRef(values);
- env->DeleteLocalRef(result);
- }
- env->DeleteLocalRef(deviceNameStr);
- }
-}
-
void NativeInputManager::getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames) {
outExcludedDeviceNames.clear();
@@ -770,6 +716,7 @@ bool NativeInputManager::populateWindow(JNIEnv* env, jobject windowObj,
outWindow.ownerUid = ownerUid;
env->ReleaseStringUTFChars(name, nameStr);
+ env->DeleteLocalRef(name);
valid = true;
} else {
LOGW("Dropping input target because its input channel is not initialized.");
@@ -831,20 +778,8 @@ bool NativeInputManager::isScreenBright() {
return android_server_PowerManagerService_isScreenBright();
}
-void NativeInputManager::interceptKeyBeforeQueueing(nsecs_t when,
- int32_t deviceId, int32_t action, int32_t &flags,
- int32_t keyCode, int32_t scanCode, uint32_t& policyFlags) {
-#if DEBUG_INPUT_DISPATCHER_POLICY
- LOGD("interceptKeyBeforeQueueing - when=%lld, deviceId=%d, action=%d, flags=%d, "
- "keyCode=%d, scanCode=%d, policyFlags=0x%x",
- when, deviceId, action, flags, keyCode, scanCode, policyFlags);
-#endif
-
- if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) {
- policyFlags |= POLICY_FLAG_VIRTUAL;
- flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
- }
-
+void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent,
+ uint32_t& policyFlags) {
// Policy:
// - Ignore untrusted events and pass them along.
// - Ask the window manager what to do with normal events and trusted injected events.
@@ -854,21 +789,30 @@ void NativeInputManager::interceptKeyBeforeQueueing(nsecs_t when,
const int32_t WM_ACTION_POKE_USER_ACTIVITY = 2;
const int32_t WM_ACTION_GO_TO_SLEEP = 4;
+ nsecs_t when = keyEvent->getEventTime();
bool isScreenOn = this->isScreenOn();
bool isScreenBright = this->isScreenBright();
JNIEnv* env = jniEnv();
- jint wmActions = env->CallIntMethod(mCallbacksObj,
- gCallbacksClassInfo.interceptKeyBeforeQueueing,
- when, action, flags, keyCode, scanCode, policyFlags, isScreenOn);
- if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
+ jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
+ jint wmActions;
+ if (keyEventObj) {
+ wmActions = env->CallIntMethod(mCallbacksObj,
+ gCallbacksClassInfo.interceptKeyBeforeQueueing,
+ keyEventObj, policyFlags, isScreenOn);
+ if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
+ wmActions = 0;
+ }
+ android_view_KeyEvent_recycle(env, keyEventObj);
+ env->DeleteLocalRef(keyEventObj);
+ } else {
+ LOGE("Failed to obtain key event object for interceptKeyBeforeQueueing.");
wmActions = 0;
}
- if (!(flags & POLICY_FLAG_INJECTED)) {
+ if (!(policyFlags & POLICY_FLAG_INJECTED)) {
if (!isScreenOn) {
policyFlags |= POLICY_FLAG_WOKE_HERE;
- flags |= AKEY_EVENT_FLAG_WOKE_HERE;
}
if (!isScreenBright) {
@@ -893,10 +837,6 @@ void NativeInputManager::interceptKeyBeforeQueueing(nsecs_t when,
}
void NativeInputManager::interceptGenericBeforeQueueing(nsecs_t when, uint32_t& policyFlags) {
-#if DEBUG_INPUT_DISPATCHER_POLICY
- LOGD("interceptGenericBeforeQueueing - when=%lld, policyFlags=0x%x", when, policyFlags);
-#endif
-
// Policy:
// - Ignore untrusted events and pass them along.
// - No special filtering for injected events required at this time.
@@ -921,46 +861,62 @@ bool NativeInputManager::interceptKeyBeforeDispatching(const sp<InputChannel>& i
// - Ignore untrusted events and pass them along.
// - Filter normal events and trusted injected events through the window manager policy to
// handle the HOME key and the like.
+ bool result;
if (policyFlags & POLICY_FLAG_TRUSTED) {
JNIEnv* env = jniEnv();
// Note: inputChannel may be null.
jobject inputChannelObj = getInputChannelObjLocal(env, inputChannel);
- jboolean consumed = env->CallBooleanMethod(mCallbacksObj,
- gCallbacksClassInfo.interceptKeyBeforeDispatching,
- inputChannelObj, keyEvent->getAction(), keyEvent->getFlags(),
- keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(),
- keyEvent->getRepeatCount(), policyFlags);
- bool error = checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatching");
+ jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
+ if (keyEventObj) {
+ jboolean consumed = env->CallBooleanMethod(mCallbacksObj,
+ gCallbacksClassInfo.interceptKeyBeforeDispatching,
+ inputChannelObj, keyEventObj, policyFlags);
+ bool error = checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatching");
+ android_view_KeyEvent_recycle(env, keyEventObj);
+ env->DeleteLocalRef(keyEventObj);
+ result = consumed && !error;
+ } else {
+ LOGE("Failed to obtain key event object for interceptKeyBeforeDispatching.");
+ result = false;
+ }
env->DeleteLocalRef(inputChannelObj);
- return consumed && ! error;
} else {
- return false;
+ result = false;
}
+ return result;
}
bool NativeInputManager::dispatchUnhandledKey(const sp<InputChannel>& inputChannel,
const KeyEvent* keyEvent, uint32_t policyFlags) {
// Policy:
// - Ignore untrusted events and do not perform default handling.
+ bool result;
if (policyFlags & POLICY_FLAG_TRUSTED) {
JNIEnv* env = jniEnv();
// Note: inputChannel may be null.
jobject inputChannelObj = getInputChannelObjLocal(env, inputChannel);
- jboolean handled = env->CallBooleanMethod(mCallbacksObj,
- gCallbacksClassInfo.dispatchUnhandledKey,
- inputChannelObj, keyEvent->getAction(), keyEvent->getFlags(),
- keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(),
- keyEvent->getRepeatCount(), policyFlags);
- bool error = checkAndClearExceptionFromCallback(env, "dispatchUnhandledKey");
+ jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
+ if (keyEventObj) {
+ jboolean handled = env->CallBooleanMethod(mCallbacksObj,
+ gCallbacksClassInfo.dispatchUnhandledKey,
+ inputChannelObj, keyEventObj, policyFlags);
+ bool error = checkAndClearExceptionFromCallback(env, "dispatchUnhandledKey");
+ android_view_KeyEvent_recycle(env, keyEventObj);
+ env->DeleteLocalRef(keyEventObj);
+ result = handled && !error;
+ } else {
+ LOGE("Failed to obtain key event object for dispatchUnhandledKey.");
+ result = false;
+ }
env->DeleteLocalRef(inputChannelObj);
- return handled && ! error;
} else {
- return false;
+ result = false;
}
+ return result;
}
void NativeInputManager::pokeUserActivity(nsecs_t eventTime, int32_t eventType) {
@@ -1159,13 +1115,21 @@ static jint android_server_InputManager_nativeInjectInputEvent(JNIEnv* env, jcla
if (env->IsInstanceOf(inputEventObj, gKeyEventClassInfo.clazz)) {
KeyEvent keyEvent;
- android_view_KeyEvent_toNative(env, inputEventObj, & keyEvent);
+ status_t status = android_view_KeyEvent_toNative(env, inputEventObj, & keyEvent);
+ if (status) {
+ jniThrowRuntimeException(env, "Could not read contents of KeyEvent object.");
+ return INPUT_EVENT_INJECTION_FAILED;
+ }
return gNativeInputManager->getInputManager()->getDispatcher()->injectInputEvent(
& keyEvent, injectorPid, injectorUid, syncMode, timeoutMillis);
} else if (env->IsInstanceOf(inputEventObj, gMotionEventClassInfo.clazz)) {
MotionEvent motionEvent;
- android_view_MotionEvent_toNative(env, inputEventObj, & motionEvent);
+ status_t status = android_view_MotionEvent_toNative(env, inputEventObj, & motionEvent);
+ if (status) {
+ jniThrowRuntimeException(env, "Could not read contents of MotionEvent object.");
+ return INPUT_EVENT_INJECTION_FAILED;
+ }
return gNativeInputManager->getInputManager()->getDispatcher()->injectInputEvent(
& motionEvent, injectorPid, injectorUid, syncMode, timeoutMillis);
@@ -1384,13 +1348,14 @@ int register_android_server_InputManager(JNIEnv* env) {
"notifyANR", "(Ljava/lang/Object;Landroid/view/InputChannel;)J");
GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeQueueing, gCallbacksClassInfo.clazz,
- "interceptKeyBeforeQueueing", "(JIIIIIZ)I");
+ "interceptKeyBeforeQueueing", "(Landroid/view/KeyEvent;IZ)I");
GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeDispatching, gCallbacksClassInfo.clazz,
- "interceptKeyBeforeDispatching", "(Landroid/view/InputChannel;IIIIIII)Z");
+ "interceptKeyBeforeDispatching",
+ "(Landroid/view/InputChannel;Landroid/view/KeyEvent;I)Z");
GET_METHOD_ID(gCallbacksClassInfo.dispatchUnhandledKey, gCallbacksClassInfo.clazz,
- "dispatchUnhandledKey", "(Landroid/view/InputChannel;IIIIIII)Z");
+ "dispatchUnhandledKey", "(Landroid/view/InputChannel;Landroid/view/KeyEvent;I)Z");
GET_METHOD_ID(gCallbacksClassInfo.checkInjectEventsPermission, gCallbacksClassInfo.clazz,
"checkInjectEventsPermission", "(II)Z");
@@ -1405,10 +1370,6 @@ int register_android_server_InputManager(JNIEnv* env) {
"getVirtualKeyDefinitions",
"(Ljava/lang/String;)[Lcom/android/server/InputManager$VirtualKeyDefinition;");
- GET_METHOD_ID(gCallbacksClassInfo.getInputDeviceCalibration, gCallbacksClassInfo.clazz,
- "getInputDeviceCalibration",
- "(Ljava/lang/String;)Lcom/android/server/InputManager$InputDeviceCalibration;");
-
GET_METHOD_ID(gCallbacksClassInfo.getExcludedDeviceNames, gCallbacksClassInfo.clazz,
"getExcludedDeviceNames", "()[Ljava/lang/String;");
@@ -1435,17 +1396,6 @@ int register_android_server_InputManager(JNIEnv* env) {
GET_FIELD_ID(gVirtualKeyDefinitionClassInfo.height, gVirtualKeyDefinitionClassInfo.clazz,
"height", "I");
- // InputDeviceCalibration
-
- FIND_CLASS(gInputDeviceCalibrationClassInfo.clazz,
- "com/android/server/InputManager$InputDeviceCalibration");
-
- GET_FIELD_ID(gInputDeviceCalibrationClassInfo.keys, gInputDeviceCalibrationClassInfo.clazz,
- "keys", "[Ljava/lang/String;");
-
- GET_FIELD_ID(gInputDeviceCalibrationClassInfo.values, gInputDeviceCalibrationClassInfo.clazz,
- "values", "[Ljava/lang/String;");
-
// InputWindow
FIND_CLASS(gInputWindowClassInfo.clazz, "com/android/server/InputWindow");
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index cc01bc5..069e1b8 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -110,7 +110,7 @@ public abstract class DataConnectionTracker extends Handler {
public static final int EVENT_CLEAN_UP_CONNECTION = 34;
protected static final int EVENT_CDMA_OTA_PROVISION = 35;
protected static final int EVENT_RESTART_RADIO = 36;
- protected static final int EVENT_SET_MASTER_DATA_ENABLE = 37;
+ protected static final int EVENT_SET_INTERNAL_DATA_ENABLE = 37;
protected static final int EVENT_RESET_DONE = 38;
/***** Constants *****/
@@ -126,8 +126,9 @@ public abstract class DataConnectionTracker extends Handler {
protected static final int DISABLED = 0;
protected static final int ENABLED = 1;
- // responds to the setDataEnabled call - used independently from the APN requests
- protected boolean mMasterDataEnabled = true;
+ // responds to the setInternalDataEnabled call - used internally to turn off data
+ // for example during emergency calls
+ protected boolean mInternalDataEnabled = true;
protected boolean[] dataEnabled = new boolean[APN_NUM_TYPES];
@@ -489,9 +490,9 @@ public abstract class DataConnectionTracker extends Handler {
onCleanUpConnection(tearDown, (String) msg.obj);
break;
- case EVENT_SET_MASTER_DATA_ENABLE:
+ case EVENT_SET_INTERNAL_DATA_ENABLE:
boolean enabled = (msg.arg1 == ENABLED) ? true : false;
- onSetDataEnabled(enabled);
+ onSetInternalDataEnabled(enabled);
break;
case EVENT_RESET_DONE:
@@ -505,23 +506,13 @@ public abstract class DataConnectionTracker extends Handler {
}
/**
- * Report the current state of data connectivity (enabled or disabled)
- *
- * @return {@code false} if data connectivity has been explicitly disabled,
- * {@code true} otherwise.
- */
- public synchronized boolean getDataEnabled() {
- return (mMasterDataEnabled && dataEnabled[APN_DEFAULT_ID]);
- }
-
- /**
* Report on whether data connectivity is enabled
*
* @return {@code false} if data connectivity has been explicitly disabled,
* {@code true} otherwise.
*/
public synchronized boolean getAnyDataEnabled() {
- return (mMasterDataEnabled && (enabledCount != 0));
+ return (mInternalDataEnabled && (enabledCount != 0));
}
protected abstract void startNetStatPoll();
@@ -676,7 +667,7 @@ public abstract class DataConnectionTracker extends Handler {
*/
protected boolean isDataPossible() {
boolean possible = (isDataAllowed()
- && !(getDataEnabled() && (mState == State.FAILED || mState == State.IDLE)));
+ && !(getAnyDataEnabled() && (mState == State.FAILED || mState == State.IDLE)));
if (!possible && DBG && isDataAllowed()) {
log("Data not possible. No coverage: dataState = " + mState);
}
@@ -847,20 +838,20 @@ public abstract class DataConnectionTracker extends Handler {
* {@code false}) data
* @return {@code true} if the operation succeeded
*/
- public boolean setDataEnabled(boolean enable) {
+ public boolean setInternalDataEnabled(boolean enable) {
if (DBG)
- log("setDataEnabled(" + enable + ")");
+ log("setInternalDataEnabled(" + enable + ")");
- Message msg = obtainMessage(EVENT_SET_MASTER_DATA_ENABLE);
+ Message msg = obtainMessage(EVENT_SET_INTERNAL_DATA_ENABLE);
msg.arg1 = (enable ? ENABLED : DISABLED);
sendMessage(msg);
return true;
}
- protected void onSetDataEnabled(boolean enable) {
- if (mMasterDataEnabled != enable) {
+ protected void onSetInternalDataEnabled(boolean enable) {
+ if (mInternalDataEnabled != enable) {
synchronized (this) {
- mMasterDataEnabled = enable;
+ mInternalDataEnabled = enable;
}
if (enable) {
mRetryMgr.resetRetryCount();
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index 69b7de6..25ad48d 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -1325,36 +1325,6 @@ public interface Phone {
SimulatedRadioControl getSimulatedRadioControl();
/**
- * Allow mobile data connections.
- * @return {@code true} if the operation started successfully
- * <br/>{@code false} if it
- * failed immediately.<br/>
- * Even in the {@code true} case, it may still fail later
- * during setup, in which case an asynchronous indication will
- * be supplied.
- */
- boolean enableDataConnectivity();
-
- /**
- * Disallow mobile data connections, and terminate any that
- * are in progress.
- * @return {@code true} if the operation started successfully
- * <br/>{@code false} if it
- * failed immediately.<br/>
- * Even in the {@code true} case, it may still fail later
- * during setup, in which case an asynchronous indication will
- * be supplied.
- */
- boolean disableDataConnectivity();
-
- /**
- * Report the current state of data connectivity (enabled or disabled)
- * @return {@code false} if data connectivity has been explicitly disabled,
- * {@code true} otherwise.
- */
- boolean isDataConnectivityEnabled();
-
- /**
* Enables the specified APN type. Only works for "special" APN types,
* i.e., not the default APN.
* @param type The desired APN type. Cannot be {@link #APN_TYPE_DEFAULT}.
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index fe4fdb3..fce7b9b 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -941,10 +941,6 @@ public abstract class PhoneBase extends Handler implements Phone {
logUnexpectedCdmaMethodCall("unsetOnEcbModeExitResponse");
}
- public boolean isDataConnectivityEnabled() {
- return mDataConnection.getDataEnabled();
- }
-
public String[] getActiveApnTypes() {
return mDataConnection.getActiveApnTypes();
}
diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java
index 2e79762..219efbb 100644
--- a/telephony/java/com/android/internal/telephony/PhoneProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java
@@ -650,14 +650,6 @@ public class PhoneProxy extends Handler implements Phone {
return mActivePhone.getSimulatedRadioControl();
}
- public boolean enableDataConnectivity() {
- return mActivePhone.enableDataConnectivity();
- }
-
- public boolean disableDataConnectivity() {
- return mActivePhone.disableDataConnectivity();
- }
-
public int enableApnType(String type) {
return mActivePhone.enableApnType(type);
}
@@ -666,10 +658,6 @@ public class PhoneProxy extends Handler implements Phone {
return mActivePhone.disableApnType(type);
}
- public boolean isDataConnectivityEnabled() {
- return mActivePhone.isDataConnectivityEnabled();
- }
-
public boolean isDataConnectivityPossible() {
return mActivePhone.isDataConnectivityPossible();
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 099bc30..1e77589 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -478,10 +478,6 @@ public class CDMAPhone extends PhoneBase {
return mSST.cellLoc;
}
- public boolean disableDataConnectivity() {
- return mDataConnection.setDataEnabled(false);
- }
-
public CdmaCall getForegroundCall() {
return mCT.foregroundCall;
}
@@ -761,21 +757,6 @@ public class CDMAPhone extends PhoneBase {
return ret;
}
- public boolean enableDataConnectivity() {
-
- // block data activities when phone is in emergency callback mode
- if (mIsPhoneInEcmState) {
- Intent intent = new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS);
- ActivityManagerNative.broadcastStickyIntent(intent, null);
- return false;
- } else if ((mCT.state == Phone.State.OFFHOOK) && mCT.isInEmergencyCall()) {
- // Do not allow data call to be enabled when emergency call is going on
- return false;
- } else {
- return mDataConnection.setDataEnabled(true);
- }
- }
-
public boolean getIccRecordsLoaded() {
return mRuimRecords.getRecordsLoaded();
}
@@ -921,7 +902,7 @@ public class CDMAPhone extends PhoneBase {
// send an Intent
sendEmergencyCallbackModeChange();
// Re-initiate data connection
- mDataConnection.setDataEnabled(true);
+ mDataConnection.setInternalDataEnabled(true);
}
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
index 325c2e1..a89f783 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaCallTracker.java
@@ -1058,7 +1058,7 @@ public final class CdmaCallTracker extends CallTracker {
if (PhoneNumberUtils.isEmergencyNumber(dialString)) {
if (Phone.DEBUG_PHONE) log("disableDataCallInEmergencyCall");
mIsInEmergencyCall = true;
- phone.disableDataConnectivity();
+ phone.mDataConnection.setInternalDataEnabled(false);
}
}
@@ -1075,8 +1075,7 @@ public final class CdmaCallTracker extends CallTracker {
}
if (inEcm.compareTo("false") == 0) {
// Re-initiate data connection
- // TODO - can this be changed to phone.enableDataConnectivity();
- phone.mDataConnection.setDataEnabled(true);
+ phone.mDataConnection.setInternalDataEnabled(true);
}
}
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index f7664ca..b005cd3 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -204,7 +204,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
(mCdmaPhone.mSST.isConcurrentVoiceAndData() ||
mPhone.getState() == Phone.State.IDLE) &&
!roaming &&
- mMasterDataEnabled &&
+ mInternalDataEnabled &&
desiredPowerState &&
!mPendingRestartRadio &&
!mCdmaPhone.needsOtaServiceProvisioning();
@@ -222,7 +222,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
reason += " - concurrentVoiceAndData not allowed and state= " + mPhone.getState();
}
if (roaming) reason += " - Roaming";
- if (!mMasterDataEnabled) reason += " - mMasterDataEnabled= false";
+ if (!mInternalDataEnabled) reason += " - mInternalDataEnabled= false";
if (!desiredPowerState) reason += " - desiredPowerState= false";
if (mPendingRestartRadio) reason += " - mPendingRestartRadio= true";
if (mCdmaPhone.needsOtaServiceProvisioning()) reason += " - needs Provisioning";
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index fc03d1a..628f11a 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -1084,14 +1084,6 @@ public class GSMPhone extends PhoneBase {
mDataConnection.setDataOnRoamingEnabled(enable);
}
- public boolean enableDataConnectivity() {
- return mDataConnection.setDataEnabled(true);
- }
-
- public boolean disableDataConnectivity() {
- return mDataConnection.setDataEnabled(false);
- }
-
/**
* Removes the given MMI from the pending list and notifies
* registrants that it is complete.
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index b41402c..4713c24 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -284,7 +284,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
(gprsState == ServiceState.STATE_IN_SERVICE || mAutoAttachOnCreation) &&
mGsmPhone.mSIMRecords.getRecordsLoaded() &&
mPhone.getState() == Phone.State.IDLE &&
- mMasterDataEnabled &&
+ mInternalDataEnabled &&
(!mPhone.getServiceState().getRoaming() || getDataOnRoamingEnabled()) &&
!mIsPsRestricted &&
desiredPowerState;
@@ -297,7 +297,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
if (mPhone.getState() != Phone.State.IDLE) {
reason += " - PhoneState= " + mPhone.getState();
}
- if (!mMasterDataEnabled) reason += " - mMasterDataEnabled= false";
+ if (!mInternalDataEnabled) reason += " - mInternalDataEnabled= false";
if (mPhone.getServiceState().getRoaming() && !getDataOnRoamingEnabled()) {
reason += " - Roaming and data roaming not enabled";
}
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
index ef31ddd..1f1338c 100755
--- a/telephony/java/com/android/internal/telephony/sip/SipPhone.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
@@ -393,12 +393,11 @@ public class SipPhone extends SipPhoneBase {
new SipProfile.Builder(calleeSipUri).build();
SipConnection c = new SipConnection(this, callee,
originalNumber);
- connections.add(c);
c.dial();
+ connections.add(c);
setState(Call.State.DIALING);
return c;
} catch (ParseException e) {
- // TODO: notify someone
throw new SipException("dial", e);
}
}
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/FsUtils.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/FsUtils.java
index a79aead..d1aba43 100644
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/FsUtils.java
+++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/FsUtils.java
@@ -39,9 +39,12 @@ import org.apache.http.params.HttpParams;
import org.apache.http.util.EntityUtils;
import java.io.BufferedReader;
+import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -49,6 +52,7 @@ import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.SocketTimeoutException;
import java.net.URL;
+import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
@@ -274,4 +278,37 @@ public class FsUtils {
Log.e(LOG_TAG, "Couldn't close stream!", e);
}
}
+
+ public static List<String> loadTestListFromStorage(String path) {
+ List<String> list = new ArrayList<String>();
+ if (path != null && !path.isEmpty()) {
+ try {
+ File file = new File(path);
+ Log.d(LOG_TAG, "test list loaded from " + path);
+ BufferedReader reader = new BufferedReader(new FileReader(file));
+ String line = null;
+ while ((line = reader.readLine()) != null) {
+ list.add(line);
+ }
+ reader.close();
+ } catch (IOException ioe) {
+ Log.e(LOG_TAG, "failed to load test list", ioe);
+ }
+ }
+ return list;
+ }
+
+ public static void saveTestListToStorage(File file, int start, List<String> testList) {
+ try {
+ BufferedWriter writer = new BufferedWriter(
+ new FileWriter(file));
+ for (String line : testList.subList(start, testList.size())) {
+ writer.write(line + '\n');
+ }
+ writer.flush();
+ writer.close();
+ } catch (IOException e) {
+ Log.e(LOG_TAG, "failed to write test list", e);
+ }
+ }
}
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecutor.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecutor.java
index 7efb03f..ce546ec 100644
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecutor.java
+++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/LayoutTestsExecutor.java
@@ -21,17 +21,15 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
-import android.net.Uri;
import android.net.http.SslError;
import android.os.Bundle;
-import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.PowerManager;
-import android.os.Process;
import android.os.PowerManager.WakeLock;
+import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
import android.view.Window;
@@ -48,10 +46,7 @@ import android.webkit.WebStorage.QuotaUpdater;
import android.webkit.WebView;
import android.webkit.WebViewClient;
-import java.io.File;
import java.lang.Thread.UncaughtExceptionHandler;
-import java.net.MalformedURLException;
-import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -79,7 +74,7 @@ public class LayoutTestsExecutor extends Activity {
private static final String LOG_TAG = "LayoutTestsExecutor";
- public static final String EXTRA_TESTS_LIST = "TestsList";
+ public static final String EXTRA_TESTS_FILE = "TestsList";
public static final String EXTRA_TEST_INDEX = "TestIndex";
private static final int MSG_ACTUAL_RESULT_OBTAINED = 0;
@@ -305,7 +300,7 @@ public class LayoutTestsExecutor extends Activity {
requestWindowFeature(Window.FEATURE_PROGRESS);
Intent intent = getIntent();
- mTestsList = intent.getStringArrayListExtra(EXTRA_TESTS_LIST);
+ mTestsList = FsUtils.loadTestListFromStorage(intent.getStringExtra(EXTRA_TESTS_FILE));
mCurrentTestIndex = intent.getIntExtra(EXTRA_TEST_INDEX, -1);
mTotalTestCount = mCurrentTestIndex + mTestsList.size();
@@ -735,4 +730,5 @@ public class LayoutTestsExecutor extends Activity {
Log.i(LOG_TAG, mCurrentTestRelativePath + ": waitUntilDone() called");
mLayoutTestControllerHandler.sendEmptyMessage(MSG_WAIT_UNTIL_DONE);
}
+
}
diff --git a/tests/DumpRenderTree2/src/com/android/dumprendertree2/TestsListActivity.java b/tests/DumpRenderTree2/src/com/android/dumprendertree2/TestsListActivity.java
index 9db4d2b..e374c1b 100644
--- a/tests/DumpRenderTree2/src/com/android/dumprendertree2/TestsListActivity.java
+++ b/tests/DumpRenderTree2/src/com/android/dumprendertree2/TestsListActivity.java
@@ -16,6 +16,8 @@
package com.android.dumprendertree2;
+import com.android.dumprendertree2.scriptsupport.OnEverythingFinishedCallback;
+
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
@@ -28,8 +30,7 @@ import android.view.Window;
import android.webkit.WebView;
import android.widget.Toast;
-import com.android.dumprendertree2.scriptsupport.OnEverythingFinishedCallback;
-
+import java.io.File;
import java.util.ArrayList;
/**
@@ -189,12 +190,12 @@ public class TestsListActivity extends Activity {
intent.setAction(Intent.ACTION_RUN);
if (startFrom < mTotalTestCount) {
- intent.putStringArrayListExtra(LayoutTestsExecutor.EXTRA_TESTS_LIST,
- new ArrayList<String>(mTestsList.subList(startFrom, mTotalTestCount)));
+ File testListFile = new File(getExternalFilesDir(null), "test_list.txt");
+ FsUtils.saveTestListToStorage(testListFile, startFrom, mTestsList);
+ intent.putExtra(LayoutTestsExecutor.EXTRA_TESTS_FILE, testListFile.getAbsolutePath());
intent.putExtra(LayoutTestsExecutor.EXTRA_TEST_INDEX, startFrom);
} else {
- intent.putStringArrayListExtra(LayoutTestsExecutor.EXTRA_TESTS_LIST,
- new ArrayList<String>());
+ intent.putExtra(LayoutTestsExecutor.EXTRA_TESTS_FILE, "");
}
startActivity(intent);
diff --git a/tests/StatusBar/res/layout/progress_notification.xml b/tests/StatusBar/res/layout/progress_notification.xml
new file mode 100644
index 0000000..5ab5d1e
--- /dev/null
+++ b/tests/StatusBar/res/layout/progress_notification.xml
@@ -0,0 +1,22 @@
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+
+ <ProgressBar
+ android:id="@+id/progress_bar"
+ style="?android:attr/progressBarStyleHorizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:max="100" />
+
+ <TextView
+ android:id="@+id/status_text"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:maxLines="1"
+ android:paddingTop="1dip"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+
+</LinearLayout>
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index 0f0637f..90c2a1a 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -31,6 +31,8 @@ import android.util.Log;
import android.net.Uri;
import android.os.SystemClock;
import android.widget.RemoteViews;
+import android.widget.TextView;
+import android.widget.ProgressBar;
import android.os.PowerManager;
public class NotificationTestList extends TestActivity
@@ -44,6 +46,8 @@ public class NotificationTestList extends TestActivity
long mActivityCreateTime = System.currentTimeMillis();
long mChronometerBase = 0;
+ boolean mProgressDone = true;
+
final int[] kNumberedIconResIDs = {
R.drawable.notification0,
R.drawable.notification1,
@@ -289,6 +293,50 @@ public class NotificationTestList extends TestActivity
}
},
+ new Test("Progress #1") {
+ public void run() {
+ final boolean PROGRESS_UPDATES_WHEN = true;
+ if (!mProgressDone) return;
+ mProgressDone = false;
+ Thread t = new Thread() {
+ public void run() {
+ int x = 0;
+ while (!mProgressDone) {
+ Notification n = new Notification(R.drawable.icon1, null,
+ PROGRESS_UPDATES_WHEN
+ ? System.currentTimeMillis()
+ : mActivityCreateTime);
+ RemoteViews v = new RemoteViews(getPackageName(),
+ R.layout.progress_notification);
+
+ v.setProgressBar(R.id.progress_bar, 100, x, false);
+ v.setTextViewText(R.id.status_text, "Progress: " + x + "%");
+
+ n.contentView = v;
+ n.flags |= Notification.FLAG_ONGOING_EVENT;
+
+ mNM.notify(500, n);
+ x = (x + 7) % 100;
+
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ break;
+ }
+ }
+ }
+ };
+ t.start();
+ }
+ },
+
+ new Test("Stop Progress") {
+ public void run() {
+ mProgressDone = true;
+ mNM.cancel(500);
+ }
+ },
+
new Test("Blue Lights") {
public void run()
{
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index 08f3c7a..b901e0d 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -366,13 +366,59 @@ public class Canvas_Delegate {
/*package*/ static void native_concat(int nCanvas, int nMatrix) {
- // FIXME
- throw new UnsupportedOperationException();
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
+ if (canvasDelegate == null) {
+ assert false;
+ return;
+ }
+
+ Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix);
+ if (matrixDelegate == null) {
+ assert false;
+ return;
+ }
+
+ // get the current top graphics2D object.
+ Graphics2D g = canvasDelegate.getGraphics2d();
+
+ // get its current matrix
+ AffineTransform currentTx = g.getTransform();
+ // get the AffineTransform of the given matrix
+ AffineTransform matrixTx = matrixDelegate.getAffineTransform();
+
+ // combine them so that the given matrix is applied after.
+ currentTx.preConcatenate(matrixTx);
+
+ // give it to the graphics2D as a new matrix replacing all previous transform
+ g.setTransform(currentTx);
}
/*package*/ static void native_setMatrix(int nCanvas, int nMatrix) {
- // FIXME
- throw new UnsupportedOperationException();
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
+ if (canvasDelegate == null) {
+ assert false;
+ }
+
+ Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix);
+ if (matrixDelegate == null) {
+ assert false;
+ }
+
+ // get the current top graphics2D object.
+ Graphics2D g = canvasDelegate.getGraphics2d();
+
+ // get the AffineTransform of the given matrix
+ AffineTransform matrixTx = matrixDelegate.getAffineTransform();
+
+ // give it to the graphics2D as a new matrix replacing all previous transform
+ g.setTransform(matrixTx);
+
+ // FIXME: log
+// if (mLogger != null && matrixDelegate.hasPerspective()) {
+// mLogger.warning("android.graphics.Canvas#setMatrix(android.graphics.Matrix) only supports affine transformations in the Layout Editor.");
+// }
}
/*package*/ static boolean native_clipRect(int nCanvas,
diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
index 6e80268..b2333f6 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
@@ -64,7 +64,7 @@ public final class Matrix_Delegate {
return null;
}
- return getAffineTransform(delegate);
+ return delegate.getAffineTransform();
}
public static boolean hasPerspective(Matrix m) {
@@ -74,7 +74,7 @@ public final class Matrix_Delegate {
return false;
}
- return (delegate.mValues[6] != 0 || delegate.mValues[7] != 0 || delegate.mValues[8] != 1);
+ return delegate.hasPerspective();
}
/**
@@ -106,6 +106,18 @@ public final class Matrix_Delegate {
return true;
}
+ /**
+ * Returns an {@link AffineTransform} matching the matrix.
+ */
+ public AffineTransform getAffineTransform() {
+ return getAffineTransform(mValues);
+ }
+
+ public boolean hasPerspective() {
+ return (mValues[6] != 0 || mValues[7] != 0 || mValues[8] != 1);
+ }
+
+
// ---- native methods ----
@@ -599,7 +611,7 @@ public final class Matrix_Delegate {
try {
- AffineTransform affineTransform = getAffineTransform(d);
+ AffineTransform affineTransform = d.getAffineTransform();
AffineTransform inverseTransform = affineTransform.createInverse();
inv_mtx.mValues[0] = (float)inverseTransform.getScaleX();
inv_mtx.mValues[1] = (float)inverseTransform.getShearX();
@@ -713,10 +725,6 @@ public final class Matrix_Delegate {
// ---- Private helper methods ----
- private static AffineTransform getAffineTransform(Matrix_Delegate d) {
- return getAffineTransform(d.mValues);
- }
-
/*package*/ static AffineTransform getAffineTransform(float[] matrix) {
// the AffineTransform constructor takes the value in a different order
// for a matrix [ 0 1 2 ]
diff --git a/tools/layoutlib/bridge/src/android/os/Handler_Delegate.java b/tools/layoutlib/bridge/src/android/os/Handler_Delegate.java
new file mode 100644
index 0000000..4d4ec7f
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/os/Handler_Delegate.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+
+/**
+ * Delegate overriding selected methods of android.os.Handler
+ *
+ * Through the layoutlib_create tool, selected methods of Handler have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ *
+ */
+public class Handler_Delegate {
+
+ // -------- Delegate methods
+
+ /*package*/ static boolean sendMessageAtTime(Handler handler, Message msg, long uptimeMillis) {
+ // get the callback
+ IHandlerCallback callback = sCallbacks.get();
+ if (callback != null) {
+ callback.sendMessageAtTime(handler, msg, uptimeMillis);
+ }
+ return true;
+ }
+
+ // -------- Delegate implementation
+
+ public interface IHandlerCallback {
+ void sendMessageAtTime(Handler handler, Message msg, long uptimeMillis);
+ }
+
+ private final static ThreadLocal<IHandlerCallback> sCallbacks =
+ new ThreadLocal<IHandlerCallback>();
+
+ public static void setCallback(IHandlerCallback callback) {
+ sCallbacks.set(callback);
+ }
+
+}
diff --git a/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java b/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java
new file mode 100644
index 0000000..be222fc
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+
+/**
+ * Delegate implementing the native methods of android.os.SystemClock
+ *
+ * Through the layoutlib_create tool, the original native methods of SystemClock have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
+ * around to map int to instance of the delegate.
+ *
+ */
+public class SystemClock_Delegate {
+ private static long sBootTime = System.currentTimeMillis();
+
+ /*package*/ static boolean setCurrentTimeMillis(long millis) {
+ return true;
+ }
+
+ /**
+ * Returns milliseconds since boot, not counting time spent in deep sleep.
+ * <b>Note:</b> This value may get reset occasionally (before it would
+ * otherwise wrap around).
+ *
+ * @return milliseconds of non-sleep uptime since boot.
+ */
+ /*package*/ static long uptimeMillis() {
+ return System.currentTimeMillis() - sBootTime;
+ }
+
+ /**
+ * Returns milliseconds since boot, including time spent in sleep.
+ *
+ * @return elapsed milliseconds since boot.
+ */
+ /*package*/ static long elapsedRealtime() {
+ return System.currentTimeMillis() - sBootTime;
+ }
+
+ /**
+ * Returns milliseconds running in the current thread.
+ *
+ * @return elapsed milliseconds in the thread
+ */
+ /*package*/ static long currentThreadTimeMillis() {
+ return System.currentTimeMillis();
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 35ba73d..2de1cbb 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -40,6 +40,7 @@ import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.locks.ReentrantLock;
/**
* Main entry point of the LayoutLib Bridge.
@@ -57,6 +58,12 @@ public final class Bridge extends LayoutBridge {
}
/**
+ * Lock to ensure only one rendering/inflating happens at a time.
+ * This is due to some singleton in the Android framework.
+ */
+ private final static ReentrantLock sLock = new ReentrantLock();
+
+ /**
* Maps from id to resource name/type. This is for android.R only.
*/
private final static Map<Integer, String[]> sRMap = new HashMap<Integer, String[]>();
@@ -160,7 +167,6 @@ public final class Bridge extends LayoutBridge {
BridgeAssetManager.initSystem();
-
// When DEBUG_LAYOUT is set and is not 0 or false, setup a default listener
// on static (native) methods which prints the signature on the console and
// throws an exception.
@@ -252,27 +258,6 @@ public final class Bridge extends LayoutBridge {
}
/**
- * Sets a 9 patch chunk in a project cache or in the framework cache.
- * @param value the path of the 9 patch
- * @param ninePatch the 9 patch object
- * @param projectKey the key of the project, or null to put the bitmap in the framework cache.
- */
- public static void setCached9Patch(String value, NinePatchChunk ninePatch, Object projectKey) {
- if (projectKey != null) {
- Map<String, SoftReference<NinePatchChunk>> map = sProject9PatchCache.get(projectKey);
-
- if (map == null) {
- map = new HashMap<String, SoftReference<NinePatchChunk>>();
- sProject9PatchCache.put(projectKey, map);
- }
-
- map.put(value, new SoftReference<NinePatchChunk>(ninePatch));
- } else {
- sFramework9PatchCache.put(value, new SoftReference<NinePatchChunk>(ninePatch));
- }
- }
-
- /**
* Starts a layout session by inflating and rendering it. The method returns a
* {@link ILayoutScene} on which further actions can be taken.
*
@@ -306,27 +291,25 @@ public final class Bridge extends LayoutBridge {
public BridgeLayoutScene createScene(SceneParams params) {
try {
SceneResult lastResult = SceneResult.SUCCESS;
- LayoutSceneImpl scene = null;
- synchronized (this) {
- try {
- scene = new LayoutSceneImpl(params);
-
- scene.prepare();
+ LayoutSceneImpl scene = new LayoutSceneImpl(params);
+ try {
+ scene.prepareThread();
+ lastResult = scene.init(params.getTimeout());
+ if (lastResult == SceneResult.SUCCESS) {
lastResult = scene.inflate();
if (lastResult == SceneResult.SUCCESS) {
lastResult = scene.render();
}
- } finally {
- if (scene != null) {
- scene.cleanup();
- }
}
+ } finally {
+ scene.release();
+ scene.cleanupThread();
}
- return new BridgeLayoutScene(this, scene, lastResult);
+ return new BridgeLayoutScene(scene, lastResult);
} catch (Throwable t) {
t.printStackTrace();
- return new BridgeLayoutScene(this, null, new SceneResult("error!", t));
+ return new BridgeLayoutScene(null, new SceneResult("error!", t));
}
}
@@ -343,6 +326,13 @@ public final class Bridge extends LayoutBridge {
}
/**
+ * Returns the lock for the bridge
+ */
+ public static ReentrantLock getLock() {
+ return sLock;
+ }
+
+ /**
* Returns details of a framework resource from its integer value.
* @param value the integer value
* @return an array of 2 strings containing the resource name and type, or null if the id
@@ -461,4 +451,27 @@ public final class Bridge extends LayoutBridge {
return null;
}
+
+ /**
+ * Sets a 9 patch chunk in a project cache or in the framework cache.
+ * @param value the path of the 9 patch
+ * @param ninePatch the 9 patch object
+ * @param projectKey the key of the project, or null to put the bitmap in the framework cache.
+ */
+ public static void setCached9Patch(String value, NinePatchChunk ninePatch, Object projectKey) {
+ if (projectKey != null) {
+ Map<String, SoftReference<NinePatchChunk>> map = sProject9PatchCache.get(projectKey);
+
+ if (map == null) {
+ map = new HashMap<String, SoftReference<NinePatchChunk>>();
+ sProject9PatchCache.put(projectKey, map);
+ }
+
+ map.put(value, new SoftReference<NinePatchChunk>(ninePatch));
+ } else {
+ sFramework9PatchCache.put(value, new SoftReference<NinePatchChunk>(ninePatch));
+ }
+ }
+
+
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeLayoutScene.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeLayoutScene.java
index 8b67166..97bf857 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeLayoutScene.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeLayoutScene.java
@@ -17,6 +17,7 @@
package com.android.layoutlib.bridge;
import com.android.layoutlib.api.LayoutScene;
+import com.android.layoutlib.api.SceneParams;
import com.android.layoutlib.api.SceneResult;
import com.android.layoutlib.api.ViewInfo;
import com.android.layoutlib.bridge.impl.LayoutSceneImpl;
@@ -33,7 +34,6 @@ import java.util.Map;
*/
public class BridgeLayoutScene extends LayoutScene {
- private final Bridge mBridge;
private final LayoutSceneImpl mScene;
private SceneResult mLastResult;
@@ -58,15 +58,34 @@ public class BridgeLayoutScene extends LayoutScene {
}
@Override
- public SceneResult render() {
-
- synchronized (mBridge) {
- try {
- mScene.prepare();
+ public SceneResult render(long timeout) {
+ try {
+ mScene.prepareThread();
+ mLastResult = mScene.acquire(timeout);
+ if (mLastResult == SceneResult.SUCCESS) {
mLastResult = mScene.render();
- } finally {
- mScene.cleanup();
}
+ } finally {
+ mScene.release();
+ mScene.cleanupThread();
+ }
+
+ return mLastResult;
+ }
+
+ @Override
+ public SceneResult animate(Object targetObject, String animationName,
+ boolean isFrameworkAnimation, IAnimationListener listener) {
+ try {
+ mScene.prepareThread();
+ mLastResult = mScene.acquire(SceneParams.DEFAULT_TIMEOUT);
+ if (mLastResult == SceneResult.SUCCESS) {
+ mLastResult = mScene.animate(targetObject, animationName, isFrameworkAnimation,
+ listener);
+ }
+ } finally {
+ mScene.release();
+ mScene.cleanupThread();
}
return mLastResult;
@@ -78,8 +97,7 @@ public class BridgeLayoutScene extends LayoutScene {
}
- /*package*/ BridgeLayoutScene(Bridge bridge, LayoutSceneImpl scene, SceneResult lastResult) {
- mBridge = bridge;
+ /*package*/ BridgeLayoutScene(LayoutSceneImpl scene, SceneResult lastResult) {
mScene = scene;
mLastResult = lastResult;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
index 1011173..affd1c6 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
@@ -261,6 +261,41 @@ public final class BridgeResources extends Resources {
}
@Override
+ public XmlResourceParser getAnimation(int id) throws NotFoundException {
+ IResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+
+ if (value != null) {
+ XmlPullParser parser = null;
+
+ try {
+ File xml = new File(value.getValue());
+ if (xml.isFile()) {
+ // we need to create a pull parser around the layout XML file, and then
+ // give that to our XmlBlockParser
+ parser = new KXmlParser();
+ parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
+ parser.setInput(new FileReader(xml));
+
+ return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]);
+ }
+ } catch (XmlPullParserException e) {
+ mContext.getLogger().error(e);
+ // we'll return null below.
+ } catch (FileNotFoundException e) {
+ // this shouldn't happen since we check above.
+ }
+
+ }
+
+ // id was not found or not resolved. Throw a NotFoundException.
+ throwException(id);
+
+ // this is not used since the method above always throws
+ return null;
+ }
+
+
+ @Override
public TypedArray obtainAttributes(AttributeSet set, int[] attrs) {
return mContext.obtainStyledAttributes(set, attrs);
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/AnimationThread.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/AnimationThread.java
new file mode 100644
index 0000000..c20bdfd
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/AnimationThread.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.layoutlib.bridge.impl;
+
+import com.android.layoutlib.api.SceneResult;
+import com.android.layoutlib.api.LayoutScene.IAnimationListener;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.os.Handler;
+import android.os.Handler_Delegate;
+import android.os.Message;
+import android.os.Handler_Delegate.IHandlerCallback;
+
+import java.util.LinkedList;
+import java.util.Queue;
+
+public class AnimationThread extends Thread {
+
+ private static class MessageBundle {
+ final Handler mTarget;
+ final Message mMessage;
+ final long mUptimeMillis;
+
+ MessageBundle(Handler target, Message message, long uptimeMillis) {
+ mTarget = target;
+ mMessage = message;
+ mUptimeMillis = uptimeMillis;
+ }
+ }
+
+ private final LayoutSceneImpl mScene;
+ private final Animator mAnimator;
+
+ Queue<MessageBundle> mQueue = new LinkedList<MessageBundle>();
+ private final IAnimationListener mListener;
+
+ public AnimationThread(LayoutSceneImpl scene, Animator animator, IAnimationListener listener) {
+ mScene = scene;
+ mAnimator = animator;
+ mListener = listener;
+ }
+
+ @Override
+ public void run() {
+ mScene.prepareThread();
+ try {
+ Handler_Delegate.setCallback(new IHandlerCallback() {
+ public void sendMessageAtTime(Handler handler, Message msg, long uptimeMillis) {
+ if (msg.what == ValueAnimator.ANIMATION_START ||
+ msg.what == ValueAnimator.ANIMATION_FRAME) {
+ mQueue.add(new MessageBundle(handler, msg, uptimeMillis));
+ } else {
+ // just ignore.
+ }
+ }
+ });
+
+ // start the animation. This will send a message to the handler right away, so
+ // mQueue is filled when this method returns.
+ mAnimator.start();
+
+ // loop the animation
+ do {
+ // get the next message.
+ MessageBundle bundle = mQueue.poll();
+ if (bundle == null) {
+ break;
+ }
+
+ // sleep enough for this bundle to be on time
+ long currentTime = System.currentTimeMillis();
+ if (currentTime < bundle.mUptimeMillis) {
+ try {
+ sleep(bundle.mUptimeMillis - currentTime);
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+ // ready to do the work, acquire the scene.
+ SceneResult result = mScene.acquire(250);
+ if (result != SceneResult.SUCCESS) {
+ mListener.done(result);
+ return;
+ }
+
+ // process the bundle. If the animation is not finished, this will enqueue
+ // the next message, so mQueue will have another one.
+ try {
+ bundle.mTarget.handleMessage(bundle.mMessage);
+ if (mScene.render() == SceneResult.SUCCESS) {
+ mListener.onNewFrame(mScene.getImage());
+ }
+ } finally {
+ mScene.release();
+ }
+ } while (mQueue.size() > 0);
+
+ mListener.done(SceneResult.SUCCESS);
+ } finally {
+ Handler_Delegate.setCallback(null);
+ mScene.cleanupThread();
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java
index f7d249e..0859976 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java
@@ -16,6 +16,10 @@
package com.android.layoutlib.bridge.impl;
+import static com.android.layoutlib.api.SceneResult.SceneStatus.ERROR_LOCK_INTERRUPTED;
+import static com.android.layoutlib.api.SceneResult.SceneStatus.ERROR_TIMEOUT;
+import static com.android.layoutlib.api.SceneResult.SceneStatus.SUCCESS;
+
import com.android.internal.util.XmlUtils;
import com.android.layoutlib.api.IProjectCallback;
import com.android.layoutlib.api.IResourceValue;
@@ -25,7 +29,9 @@ import com.android.layoutlib.api.SceneParams;
import com.android.layoutlib.api.SceneResult;
import com.android.layoutlib.api.ViewInfo;
import com.android.layoutlib.api.IDensityBasedResourceValue.Density;
+import com.android.layoutlib.api.LayoutScene.IAnimationListener;
import com.android.layoutlib.api.SceneParams.RenderingMode;
+import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.BridgeConstants;
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.android.BridgeInflater;
@@ -33,6 +39,8 @@ import com.android.layoutlib.bridge.android.BridgeWindow;
import com.android.layoutlib.bridge.android.BridgeWindowSession;
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
+import android.animation.AnimatorInflater;
+import android.animation.ObjectAnimator;
import android.app.Fragment_Delegate;
import android.graphics.Bitmap;
import android.graphics.Bitmap_Delegate;
@@ -59,6 +67,8 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantLock;
/**
* Class managing a layout "scene".
@@ -73,6 +83,12 @@ public class LayoutSceneImpl {
private static final int DEFAULT_TITLE_BAR_HEIGHT = 25;
private static final int DEFAULT_STATUS_BAR_HEIGHT = 25;
+ /**
+ * The current context being rendered. This is set through {@link #acquire(long)} and
+ * {@link #init(long)}, and unset in {@link #release()}.
+ */
+ private static BridgeContext sCurrentContext = null;
+
private final SceneParams mParams;
// scene state
@@ -98,22 +114,35 @@ public class LayoutSceneImpl {
/**
* Creates a layout scene with all the information coming from the layout bridge API.
- *
- * This also calls {@link LayoutSceneImpl#prepare()}.
* <p>
- * <b>THIS MUST BE INSIDE A SYNCHRONIZED BLOCK on the BRIDGE OBJECT.<b>
+ * This <b>must</b> be followed by a call to {@link LayoutSceneImpl#init()}, which act as a
+ * call to {@link LayoutSceneImpl#acquire(long)}
*
* @see LayoutBridge#createScene(com.android.layoutlib.api.SceneParams)
*/
public LayoutSceneImpl(SceneParams params) {
- // we need to make sure the Looper has been initialized for this thread.
- // this is required for View that creates Handler objects.
- if (Looper.myLooper() == null) {
- Looper.prepare();
- }
-
// copy the params.
mParams = new SceneParams(params);
+ }
+
+ /**
+ * Initializes and acquires the scene, creating various Android objects such as context,
+ * inflater, and parser.
+ *
+ * @param timeout the time to wait if another rendering is happening.
+ *
+ * @return whether the scene was prepared
+ *
+ * @see #acquire(long)
+ * @see #release()
+ */
+ public SceneResult init(long timeout) {
+ // acquire the lock. if the result is null, lock was just acquired, otherwise, return
+ // the result.
+ SceneResult result = acquireLock(timeout);
+ if (result != null) {
+ return result;
+ }
// setup the display Metrics.
DisplayMetrics metrics = new DisplayMetrics();
@@ -138,6 +167,9 @@ public class LayoutSceneImpl {
mParams.getProjectResources(), mParams.getFrameworkResources(),
styleParentMap, mParams.getProjectCallback(), mParams.getLogger());
+ // set the current rendering context
+ sCurrentContext = mContext;
+
// make sure the Resources object references the context (and other objects) for this
// scene
mContext.initResources();
@@ -149,7 +181,8 @@ public class LayoutSceneImpl {
mWindowBackground = mContext.findItemInStyle(mCurrentTheme, "windowBackground");
mWindowBackground = mContext.resolveResValue(mWindowBackground);
- mScreenOffset = getScreenOffset(mParams.getFrameworkResources(), mCurrentTheme, mContext);
+ mScreenOffset = getScreenOffset(mParams.getFrameworkResources(), mCurrentTheme,
+ mContext);
}
// build the inflater and parser.
@@ -159,44 +192,144 @@ public class LayoutSceneImpl {
mBlockParser = new BridgeXmlBlockParser(mParams.getLayoutDescription(),
mContext, false /* platformResourceFlag */);
+
+ return SceneResult.SUCCESS;
}
/**
- * Prepares the scene for action.
- * <p>
- * <b>THIS MUST BE INSIDE A SYNCHRONIZED BLOCK on the BRIDGE OBJECT.<b>
+ * Prepares the current thread for rendering.
+ *
+ * Note that while this can be called several time, the first call to {@link #cleanupThread()}
+ * will do the clean-up, and make the thread unable to do further scene actions.
*/
- public void prepare() {
+ public void prepareThread() {
// we need to make sure the Looper has been initialized for this thread.
// this is required for View that creates Handler objects.
if (Looper.myLooper() == null) {
Looper.prepare();
}
+ }
+
+ /**
+ * Cleans up thread-specific data. After this, the thread cannot be used for scene actions.
+ * <p>
+ * Note that it doesn't matter how many times {@link #prepareThread()} was called, a single
+ * call to this will prevent the thread from doing further scene actions
+ */
+ public void cleanupThread() {
+ // clean up the looper
+ Looper.sThreadLocal.remove();
+ }
+
+ /**
+ * Prepares the scene for action.
+ * <p>
+ * This call is blocking if another rendering/inflating is currently happening, and will return
+ * whether the preparation worked.
+ *
+ * The preparation can fail if another rendering took too long and the timeout was elapsed.
+ *
+ * More than one call to this from the same thread will have no effect and will return
+ * {@link SceneResult#SUCCESS}.
+ *
+ * After scene actions have taken place, only one call to {@link #release()} must be
+ * done.
+ *
+ * @param timeout the time to wait if another rendering is happening.
+ *
+ * @return whether the scene was prepared
+ *
+ * @see #release()
+ *
+ * @throws IllegalStateException if {@link #init(long)} was never called.
+ */
+ public SceneResult acquire(long timeout) {
+ if (mContext == null) {
+ throw new IllegalStateException("After scene creation, #init() must be called");
+ }
+
+ // acquire the lock. if the result is null, lock was just acquired, otherwise, return
+ // the result.
+ SceneResult result = acquireLock(timeout);
+ if (result != null) {
+ return result;
+ }
// make sure the Resources object references the context (and other objects) for this
// scene
mContext.initResources();
+ sCurrentContext = mContext;
+
+ return SUCCESS.getResult();
}
/**
- * Cleans up the scene after an action.
+ * Acquire the lock so that the scene can be acted upon.
* <p>
- * <b>THIS MUST BE INSIDE A SYNCHRONIZED BLOCK on the BRIDGE OBJECT.<b>
+ * This returns null if the lock was just acquired, otherwise it returns
+ * {@link SceneResult#SUCCESS} if the lock already belonged to that thread, or another
+ * instance (see {@link SceneResult#getStatus()}) if an error occurred.
+ *
+ * @param timeout the time to wait if another rendering is happening.
+ * @return null if the lock was just acquire or another result depending on the state.
+ *
+ * @throws IllegalStateException if the current context is different than the one owned by
+ * the scene.
*/
- public void cleanup() {
- // clean up the looper
- Looper.sThreadLocal.remove();
+ private SceneResult acquireLock(long timeout) {
+ ReentrantLock lock = Bridge.getLock();
+ if (lock.isHeldByCurrentThread() == false) {
+ try {
+ boolean acquired = lock.tryLock(timeout, TimeUnit.MILLISECONDS);
+
+ if (acquired == false) {
+ return ERROR_TIMEOUT.getResult();
+ }
+ } catch (InterruptedException e) {
+ return ERROR_LOCK_INTERRUPTED.getResult();
+ }
+ } else {
+ // This thread holds the lock already. Checks that this wasn't for a different context.
+ // If this is called by init, mContext will be null and so should sCurrentContext
+ // anyway
+ if (mContext != sCurrentContext) {
+ throw new IllegalStateException("Acquiring different scenes from same thread without releases");
+ }
+ return SUCCESS.getResult();
+ }
- // Make sure to remove static references, otherwise we could not unload the lib
- mContext.disposeResources();
+ return null;
+ }
+
+ /**
+ * Cleans up the scene after an action.
+ */
+ public void release() {
+ ReentrantLock lock = Bridge.getLock();
+
+ // with the use of finally blocks, it is possible to find ourself calling this
+ // without a successful call to prepareScene. This test makes sure that unlock() will
+ // not throw IllegalMonitorStateException.
+ if (lock.isHeldByCurrentThread()) {
+ // Make sure to remove static references, otherwise we could not unload the lib
+ mContext.disposeResources();
+ sCurrentContext = null;
+
+ lock.unlock();
+ }
}
/**
* Inflates the layout.
* <p>
- * <b>THIS MUST BE INSIDE A SYNCHRONIZED BLOCK on the BRIDGE OBJECT.<b>
+ * {@link #acquire(long)} must have been called before this.
+ *
+ * @throws IllegalStateException if the current context is different than the one owned by
+ * the scene, or if {@link #init(long)} was not called.
*/
public SceneResult inflate() {
+ checkLock();
+
try {
mViewRoot = new FrameLayout(mContext);
@@ -247,10 +380,16 @@ public class LayoutSceneImpl {
/**
* Renders the scene.
* <p>
- * <b>THIS MUST BE INSIDE A SYNCHRONIZED BLOCK on the BRIDGE OBJECT.<b>
+ * {@link #acquire(long)} must have been called before this.
+ *
+ * @throws IllegalStateException if the current context is different than the one owned by
+ * the scene, or if {@link #acquire(long)} was not called.
*/
public SceneResult render() {
+ checkLock();
+
try {
+ long current = System.currentTimeMillis();
if (mViewRoot == null) {
return new SceneResult("Layout has not been inflated!");
}
@@ -329,6 +468,8 @@ public class LayoutSceneImpl {
mViewInfo = visit(((ViewGroup)mViewRoot).getChildAt(0), mContext);
+ System.out.println("rendering (ms): " + (System.currentTimeMillis() - current));
+
// success!
return SceneResult.SUCCESS;
} catch (Throwable e) {
@@ -346,6 +487,71 @@ public class LayoutSceneImpl {
}
/**
+ * Animate an object
+ * <p>
+ * {@link #acquire(long)} must have been called before this.
+ *
+ * @throws IllegalStateException if the current context is different than the one owned by
+ * the scene, or if {@link #acquire(long)} was not called.
+ */
+ public SceneResult animate(Object targetObject, String animationName,
+ boolean isFrameworkAnimation, IAnimationListener listener) {
+ checkLock();
+
+ // find the animation file.
+ IResourceValue animationResource = null;
+ int animationId = 0;
+ if (isFrameworkAnimation) {
+ animationResource = mContext.getFrameworkResource("anim", animationName);
+ if (animationResource != null) {
+ animationId = Bridge.getResourceValue("anim", animationName);
+ }
+ } else {
+ animationResource = mContext.getProjectResource("anim", animationName);
+ if (animationResource != null) {
+ animationId = mContext.getProjectCallback().getResourceValue("anim", animationName);
+ }
+ }
+
+ if (animationResource != null) {
+ try {
+ ObjectAnimator anim = (ObjectAnimator) AnimatorInflater.loadAnimator(
+ mContext, animationId);
+ if (anim != null) {
+ anim.setTarget(targetObject);
+
+ new AnimationThread(this, anim, listener).start();
+
+ return SceneResult.SUCCESS;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ return new SceneResult("", e);
+ }
+ }
+
+ return new SceneResult("Failed to find animation");
+ }
+
+ /**
+ * Checks that the lock is owned by the current thread and that the current context is the one
+ * from this scene.
+ *
+ * @throws IllegalStateException if the current context is different than the one owned by
+ * the scene, or if {@link #acquire(long)} was not called.
+ */
+ private void checkLock() {
+ ReentrantLock lock = Bridge.getLock();
+ if (lock.isHeldByCurrentThread() == false) {
+ throw new IllegalStateException("scene must be acquired first. see #acquire(long)");
+ }
+ if (sCurrentContext != mContext) {
+ throw new IllegalStateException("Thread acquired a scene but is rendering a different one");
+ }
+ }
+
+
+ /**
* Compute style information from the given list of style for the project and framework.
* @param themeName the name of the current theme. In order to differentiate project and
* platform themes sharing the same name, all project themes must be prepended with
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index bb2e6b3..4440685 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -95,6 +95,7 @@ public final class CreateInfo implements ICreateInfo {
*/
private final static String[] DELEGATE_METHODS = new String[] {
"android.app.Fragment#instantiate", //(Landroid/content/Context;Ljava/lang/String;Landroid/os/Bundle;)Landroid/app/Fragment;",
+ "android.os.Handler#sendMessageAtTime",
"android.view.View#isInEditMode",
// TODO: comment out once DelegateClass is working
// "android.content.res.Resources$Theme#obtainStyledAttributes",
@@ -118,6 +119,7 @@ public final class CreateInfo implements ICreateInfo {
"android.graphics.SweepGradient",
"android.graphics.Typeface",
"android.graphics.Xfermode",
+ "android.os.SystemClock",
"android.util.FloatMath",
};
diff --git a/voip/java/android/net/sip/SipManager.java b/voip/java/android/net/sip/SipManager.java
index 8aaa805..2e38662 100644
--- a/voip/java/android/net/sip/SipManager.java
+++ b/voip/java/android/net/sip/SipManager.java
@@ -314,10 +314,6 @@ public class SipManager {
SipAudioCall call = new SipAudioCall(mContext, localProfile);
call.setListener(listener);
SipSession s = createSipSession(localProfile, null);
- if (s == null) {
- throw new SipException(
- "Failed to create SipSession; network available?");
- }
call.makeCall(peerProfile, s, timeout);
return call;
}
@@ -366,7 +362,9 @@ public class SipManager {
*/
public SipAudioCall takeAudioCall(Intent incomingCallIntent,
SipAudioCall.Listener listener) throws SipException {
- if (incomingCallIntent == null) return null;
+ if (incomingCallIntent == null) {
+ throw new SipException("Cannot retrieve session with null intent");
+ }
String callId = getCallId(incomingCallIntent);
if (callId == null) {
@@ -381,7 +379,9 @@ public class SipManager {
try {
ISipSession session = mSipService.getPendingSession(callId);
- if (session == null) return null;
+ if (session == null) {
+ throw new SipException("No pending session for the call");
+ }
SipAudioCall call = new SipAudioCall(
mContext, session.getLocalProfile());
call.attachCall(new SipSession(session), offerSd);
@@ -526,6 +526,10 @@ public class SipManager {
SipSession.Listener listener) throws SipException {
try {
ISipSession s = mSipService.createSession(localProfile, null);
+ if (s == null) {
+ throw new SipException(
+ "Failed to create SipSession; network unavailable?");
+ }
return new SipSession(s, listener);
} catch (RemoteException e) {
throw new SipException("createSipSession()", e);
@@ -541,7 +545,7 @@ public class SipManager {
try {
return mSipService.getListOfProfiles();
} catch (RemoteException e) {
- return null;
+ return new SipProfile[0];
}
}
diff --git a/voip/java/com/android/server/sip/SipService.java b/voip/java/com/android/server/sip/SipService.java
index f480fec..3af6e78 100644
--- a/voip/java/com/android/server/sip/SipService.java
+++ b/voip/java/com/android/server/sip/SipService.java
@@ -135,7 +135,7 @@ public final class SipService extends ISipService.Stub {
switch (state) {
case WifiManager.WIFI_STATE_ENABLED:
mWifiEnabled = true;
- if (anyOpened()) grabWifiLock();
+ if (anyOpenedToReceiveCalls()) grabWifiLock();
break;
case WifiManager.WIFI_STATE_DISABLED:
mWifiEnabled = false;
@@ -231,7 +231,7 @@ public final class SipService extends ISipService.Stub {
notifyProfileRemoved(group.getLocalProfile());
group.close();
- if (!anyOpened()) {
+ if (!anyOpenedToReceiveCalls()) {
releaseWifiLock();
mMyWakeLock.reset(); // in case there's leak
}
@@ -243,7 +243,7 @@ public final class SipService extends ISipService.Stub {
SipSessionGroupExt group = mSipGroups.get(localProfileUri);
if (group == null) return false;
if (isCallerCreatorOrRadio(group)) {
- return group.isOpened();
+ return true;
} else {
Log.w(TAG, "only creator or radio can query on the profile");
return false;
@@ -358,9 +358,9 @@ public final class SipService extends ISipService.Stub {
mContext.sendBroadcast(intent);
}
- private boolean anyOpened() {
+ private boolean anyOpenedToReceiveCalls() {
for (SipSessionGroupExt group : mSipGroups.values()) {
- if (group.isOpened()) return true;
+ if (group.isOpenedToReceiveCalls()) return true;
}
return false;
}
@@ -479,7 +479,7 @@ public final class SipService extends ISipService.Stub {
private class SipSessionGroupExt extends SipSessionAdapter {
private SipSessionGroup mSipGroup;
private PendingIntent mIncomingCallPendingIntent;
- private boolean mOpened;
+ private boolean mOpenedToReceiveCalls;
private AutoRegistrationProcess mAutoRegistration =
new AutoRegistrationProcess();
@@ -541,7 +541,7 @@ public final class SipService extends ISipService.Stub {
}
public void openToReceiveCalls() throws SipException {
- mOpened = true;
+ mOpenedToReceiveCalls = true;
if (mConnected) {
mSipGroup.openToReceiveCalls(this);
mAutoRegistration.start(mSipGroup);
@@ -555,9 +555,9 @@ public final class SipService extends ISipService.Stub {
mSipGroup.onConnectivityChanged();
if (connected) {
resetGroup(mLocalIp);
- if (mOpened) openToReceiveCalls();
+ if (mOpenedToReceiveCalls) openToReceiveCalls();
} else {
- // close mSipGroup but remember mOpened
+ // close mSipGroup but remember mOpenedToReceiveCalls
if (DEBUG) Log.d(TAG, " close auto reg temporarily: "
+ getUri() + ": " + mIncomingCallPendingIntent);
mSipGroup.close();
@@ -582,7 +582,7 @@ public final class SipService extends ISipService.Stub {
}
public void close() {
- mOpened = false;
+ mOpenedToReceiveCalls = false;
mSipGroup.close();
mAutoRegistration.stop();
if (DEBUG) Log.d(TAG, " close: " + getUri() + ": "
@@ -629,8 +629,8 @@ public final class SipService extends ISipService.Stub {
+ SipErrorCode.toString(errorCode) + ": " + message);
}
- public boolean isOpened() {
- return mOpened;
+ public boolean isOpenedToReceiveCalls() {
+ return mOpenedToReceiveCalls;
}
public boolean isRegistered() {
diff --git a/voip/java/com/android/server/sip/SipSessionGroup.java b/voip/java/com/android/server/sip/SipSessionGroup.java
index 50ce7dc..2fbaee2 100644
--- a/voip/java/com/android/server/sip/SipSessionGroup.java
+++ b/voip/java/com/android/server/sip/SipSessionGroup.java
@@ -190,6 +190,7 @@ class SipSessionGroup implements SipListener {
public synchronized void close() {
Log.d(TAG, " close stack for " + mLocalProfile.getUriString());
+ onConnectivityChanged();
mSessionMap.clear();
closeToNotReceiveCalls();
if (mSipStack != null) {
diff --git a/voip/jni/rtp/EchoSuppressor.cpp b/voip/jni/rtp/EchoSuppressor.cpp
index 4cff588..6127d3c 100644
--- a/voip/jni/rtp/EchoSuppressor.cpp
+++ b/voip/jni/rtp/EchoSuppressor.cpp
@@ -161,22 +161,27 @@ void EchoSuppressor::run(int16_t *playbacked, int16_t *recorded)
}
// Compute correlations.
- float corr2 = 0.0f;
int latency = 0;
+ float corr2 = 0.0f;
+ float varX = 0.0f;
float varY = mY2Sum - mWeight * mYSum * mYSum;
for (int i = mTailLength - 1; i >= 0; --i) {
- float varX = mX2Sums[i] - mWeight * mXSums[i] * mXSums[i];
float cov = mXYSums[i] - mWeight * mXSums[i] * mYSum;
- float c2 = cov * cov / (varX * varY + 1);
- if (c2 > corr2) {
- corr2 = c2;
- latency = i;
+ if (cov > 0.0f) {
+ float varXi = mX2Sums[i] - mWeight * mXSums[i] * mXSums[i];
+ float corr2i = cov * cov / (varXi * varY + 1);
+ if (corr2i > corr2) {
+ varX = varXi;
+ corr2 = corr2i;
+ latency = i;
+ }
}
}
- //LOGI("correlation^2 = %.10f, latency = %d", corr2, latency * mScale);
+ //LOGI("corr^2 %.5f, var %8.0f %8.0f, latency %d", corr2, varX, varY,
+ // latency * mScale);
// Do echo suppression.
- if (corr2 > 0.1f) {
+ if (corr2 > 0.1f && varX > 10000.0f) {
int factor = (corr2 > 1.0f) ? 0 : (1.0f - sqrtf(corr2)) * 4096;
for (int i = 0; i < mSampleCount; ++i) {
recorded[i] = recorded[i] * factor >> 16;