summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.xml1214
-rw-r--r--cmds/pm/src/com/android/commands/pm/Pm.java8
-rw-r--r--core/java/android/animation/AnimatorInflater.java126
-rw-r--r--core/java/android/animation/AnimatorSet.java42
-rwxr-xr-xcore/java/android/animation/ValueAnimator.java5
-rw-r--r--core/java/android/app/ActionBar.java48
-rw-r--r--core/java/android/app/Activity.java31
-rw-r--r--core/java/android/app/ActivityThread.java144
-rw-r--r--core/java/android/app/Dialog.java6
-rw-r--r--core/java/android/hardware/Camera.java45
-rw-r--r--core/java/android/hardware/SensorEvent.java48
-rw-r--r--core/java/android/hardware/SensorManager.java21
-rw-r--r--core/java/android/os/Debug.java33
-rw-r--r--core/java/android/os/StrictMode.java40
-rw-r--r--core/java/android/preference/PreferenceFrameLayout.java113
-rw-r--r--core/java/android/provider/Downloads.java9
-rw-r--r--core/java/android/provider/Ptp.java28
-rw-r--r--core/java/android/text/method/ArrowKeyMovementMethod.java10
-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/DragEvent.java17
-rw-r--r--core/java/android/view/HardwareRenderer.java12
-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.java108
-rw-r--r--core/java/android/view/ViewConfiguration.java2
-rw-r--r--core/java/android/view/ViewRoot.java128
-rw-r--r--core/java/android/view/WindowManagerPolicy.java29
-rw-r--r--core/java/android/webkit/CookieManager.java15
-rw-r--r--core/java/android/webkit/FindActionModeCallback.java4
-rw-r--r--core/java/android/webkit/HTML5VideoViewProxy.java11
-rw-r--r--core/java/android/webkit/SelectActionModeCallback.java4
-rw-r--r--core/java/android/webkit/WebView.java142
-rw-r--r--core/java/android/webkit/WebViewCore.java4
-rw-r--r--core/java/android/widget/LinearLayout.java240
-rw-r--r--core/java/android/widget/ListView.java6
-rw-r--r--core/java/android/widget/OverScroller.java283
-rw-r--r--core/java/android/widget/TextView.java274
-rw-r--r--core/java/com/android/internal/app/ActionBarImpl.java32
-rw-r--r--core/java/com/android/internal/app/AlertController.java37
-rw-r--r--core/java/com/android/internal/os/SamplingProfilerIntegration.java69
-rw-r--r--core/java/com/android/internal/view/StandaloneActionMode.java2
-rw-r--r--core/java/com/android/internal/view/menu/ActionMenuView.java76
-rw-r--r--core/java/com/android/internal/view/menu/MenuPopupHelper.java16
-rw-r--r--core/java/com/android/internal/widget/ActionBarContextView.java6
-rw-r--r--core/java/com/android/internal/widget/ActionBarView.java19
-rw-r--r--core/jni/android_app_NativeActivity.cpp33
-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/res/AndroidManifest.xml2
-rw-r--r--core/res/res/drawable-hdpi/textfield_activated_holo_dark.9.pngbin0 -> 281 bytes
-rw-r--r--core/res/res/drawable-hdpi/textfield_activated_holo_light.9.pngbin0 -> 279 bytes
-rw-r--r--core/res/res/drawable-hdpi/textfield_default_holo_dark.9.pngbin1082 -> 281 bytes
-rw-r--r--core/res/res/drawable-hdpi/textfield_default_holo_light.9.pngbin1088 -> 279 bytes
-rw-r--r--core/res/res/drawable-hdpi/textfield_disabled_focused_holo_dark.9.pngbin1081 -> 285 bytes
-rw-r--r--core/res/res/drawable-hdpi/textfield_disabled_focused_holo_light.9.pngbin1080 -> 285 bytes
-rw-r--r--core/res/res/drawable-hdpi/textfield_disabled_holo_dark.9.pngbin1069 -> 282 bytes
-rw-r--r--core/res/res/drawable-hdpi/textfield_disabled_holo_light.9.pngbin1078 -> 280 bytes
-rw-r--r--core/res/res/drawable-hdpi/textfield_focused_holo_dark.9.pngbin0 -> 284 bytes
-rw-r--r--core/res/res/drawable-hdpi/textfield_focused_holo_light.9.pngbin0 -> 285 bytes
-rw-r--r--core/res/res/drawable-hdpi/textfield_longpress_holo.9.pngbin0 -> 196 bytes
-rw-r--r--core/res/res/drawable-hdpi/textfield_multiline_activated_holo_dark.9.pngbin0 -> 320 bytes
-rw-r--r--core/res/res/drawable-hdpi/textfield_multiline_activated_holo_light.9.pngbin0 -> 314 bytes
-rw-r--r--core/res/res/drawable-hdpi/textfield_multiline_default_holo_dark.9.pngbin1128 -> 320 bytes
-rw-r--r--core/res/res/drawable-hdpi/textfield_multiline_default_holo_light.9.pngbin1120 -> 313 bytes
-rw-r--r--core/res/res/drawable-hdpi/textfield_multiline_disabled_focused_holo_dark.9.pngbin1113 -> 325 bytes
-rw-r--r--core/res/res/drawable-hdpi/textfield_multiline_disabled_focused_holo_light.9.pngbin1113 -> 324 bytes
-rw-r--r--core/res/res/drawable-hdpi/textfield_multiline_disabled_holo_dark.9.pngbin1117 -> 320 bytes
-rw-r--r--core/res/res/drawable-hdpi/textfield_multiline_disabled_holo_light.9.pngbin1128 -> 313 bytes
-rw-r--r--core/res/res/drawable-hdpi/textfield_multiline_focused_holo_dark.9.pngbin0 -> 325 bytes
-rw-r--r--core/res/res/drawable-hdpi/textfield_multiline_focused_holo_light.9.pngbin0 -> 325 bytes
-rw-r--r--core/res/res/drawable-hdpi/textfield_pressed_holo.9.pngbin0 -> 192 bytes
-rw-r--r--core/res/res/drawable-mdpi/textfield_activated_holo_dark.9.pngbin0 -> 281 bytes
-rw-r--r--core/res/res/drawable-mdpi/textfield_activated_holo_light.9.pngbin0 -> 279 bytes
-rw-r--r--core/res/res/drawable-mdpi/textfield_default_holo_dark.9.pngbin1068 -> 281 bytes
-rw-r--r--core/res/res/drawable-mdpi/textfield_default_holo_light.9.pngbin1071 -> 279 bytes
-rw-r--r--core/res/res/drawable-mdpi/textfield_disabled_holo_dark.9.pngbin1067 -> 282 bytes
-rw-r--r--core/res/res/drawable-mdpi/textfield_disabled_holo_light.9.pngbin1069 -> 280 bytes
-rw-r--r--core/res/res/drawable-mdpi/textfield_focused_holo_dark.9.pngbin0 -> 284 bytes
-rw-r--r--core/res/res/drawable-mdpi/textfield_focused_holo_light.9.pngbin0 -> 285 bytes
-rw-r--r--core/res/res/drawable-mdpi/textfield_longpress_holo.9.pngbin0 -> 196 bytes
-rw-r--r--core/res/res/drawable-mdpi/textfield_multiline_activated_holo_dark.9.pngbin0 -> 320 bytes
-rw-r--r--core/res/res/drawable-mdpi/textfield_multiline_activated_holo_light.9.pngbin0 -> 314 bytes
-rw-r--r--core/res/res/drawable-mdpi/textfield_multiline_active_holo_dark.9.pngbin1103 -> 232 bytes
-rw-r--r--core/res/res/drawable-mdpi/textfield_multiline_active_holo_light.9.pngbin1105 -> 223 bytes
-rw-r--r--core/res/res/drawable-mdpi/textfield_multiline_default_holo_dark.9.pngbin1101 -> 320 bytes
-rw-r--r--core/res/res/drawable-mdpi/textfield_multiline_default_holo_light.9.pngbin1106 -> 313 bytes
-rw-r--r--core/res/res/drawable-mdpi/textfield_multiline_disabled_holo_dark.9.pngbin1090 -> 320 bytes
-rw-r--r--core/res/res/drawable-mdpi/textfield_multiline_disabled_holo_light.9.pngbin1107 -> 313 bytes
-rw-r--r--core/res/res/drawable-mdpi/textfield_multiline_focused_holo_dark.9.pngbin0 -> 325 bytes
-rw-r--r--core/res/res/drawable-mdpi/textfield_multiline_focused_holo_light.9.pngbin0 -> 325 bytes
-rw-r--r--core/res/res/drawable-mdpi/textfield_pressed_holo.9.pngbin0 -> 192 bytes
-rw-r--r--core/res/res/drawable/edit_text_holo_dark.xml3
-rw-r--r--core/res/res/drawable/edit_text_holo_light.xml3
-rw-r--r--core/res/res/drawable/edit_text_multiline_holo_dark.xml3
-rw-r--r--core/res/res/drawable/edit_text_multiline_holo_light.xml3
-rw-r--r--core/res/res/layout-xlarge/alert_dialog_holo.xml23
-rw-r--r--core/res/res/layout-xlarge/select_dialog_holo.xml36
-rw-r--r--core/res/res/layout-xlarge/select_dialog_item_holo.xml36
-rw-r--r--core/res/res/layout-xlarge/select_dialog_multichoice_holo.xml29
-rw-r--r--core/res/res/layout-xlarge/select_dialog_singlechoice_holo.xml29
-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/values-ar/strings.xml2
-rw-r--r--core/res/res/values-bg/strings.xml2
-rw-r--r--core/res/res/values-ca/strings.xml2
-rw-r--r--core/res/res/values-cs/strings.xml15
-rw-r--r--core/res/res/values-da/strings.xml15
-rw-r--r--core/res/res/values-de/strings.xml15
-rw-r--r--core/res/res/values-el/strings.xml15
-rw-r--r--core/res/res/values-en-rGB/strings.xml2
-rw-r--r--core/res/res/values-es-rUS/strings.xml12
-rw-r--r--core/res/res/values-es/strings.xml15
-rw-r--r--core/res/res/values-fa/strings.xml2
-rw-r--r--core/res/res/values-fi/strings.xml2
-rw-r--r--core/res/res/values-fr/strings.xml15
-rw-r--r--core/res/res/values-he/strings.xml2
-rw-r--r--core/res/res/values-hr/strings.xml2
-rw-r--r--core/res/res/values-hu/strings.xml2
-rw-r--r--core/res/res/values-id/strings.xml2
-rw-r--r--core/res/res/values-it/strings.xml15
-rw-r--r--core/res/res/values-ja/strings.xml15
-rw-r--r--core/res/res/values-ko/strings.xml15
-rw-r--r--core/res/res/values-lt/strings.xml2
-rw-r--r--core/res/res/values-lv/strings.xml2
-rw-r--r--core/res/res/values-nb/strings.xml15
-rw-r--r--core/res/res/values-nl/strings.xml15
-rw-r--r--core/res/res/values-pl/strings.xml15
-rw-r--r--core/res/res/values-pt-rPT/strings.xml15
-rw-r--r--core/res/res/values-pt/strings.xml15
-rw-r--r--core/res/res/values-rm/strings.xml2
-rw-r--r--core/res/res/values-ro/strings.xml2
-rw-r--r--core/res/res/values-ru/strings.xml15
-rw-r--r--core/res/res/values-sk/strings.xml2
-rw-r--r--core/res/res/values-sl/strings.xml2
-rw-r--r--core/res/res/values-sr/strings.xml2
-rw-r--r--core/res/res/values-sv/strings.xml15
-rw-r--r--core/res/res/values-th/strings.xml2
-rw-r--r--core/res/res/values-tl/strings.xml2
-rw-r--r--core/res/res/values-tr/strings.xml15
-rw-r--r--core/res/res/values-uk/strings.xml2
-rw-r--r--core/res/res/values-vi/strings.xml2
-rw-r--r--core/res/res/values-zh-rCN/strings.xml15
-rw-r--r--core/res/res/values-zh-rTW/strings.xml15
-rwxr-xr-xcore/res/res/values/attrs.xml93
-rw-r--r--core/res/res/values/public.xml15
-rw-r--r--core/res/res/values/styles.xml26
-rw-r--r--core/res/res/values/themes.xml57
-rw-r--r--core/tests/coretests/src/android/net/UriTest.java16
-rw-r--r--data/keyboards/Apple_Wireless_Keyboard.kl2
-rw-r--r--data/keyboards/Logitech_USB_Receiver.kl2
-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/data/backup.jd70
-rw-r--r--docs/html/guide/topics/ui/actionbar.jd22
-rw-r--r--docs/html/resources/dashboard/platform-versions.jd36
-rw-r--r--docs/html/sdk/ndk/index.jd326
-rw-r--r--docs/html/sdk/ndk/overview.jd277
-rw-r--r--include/camera/CameraParameters.h23
-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/camera/CameraParameters.cpp9
-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/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/MediaScanner.java7
-rw-r--r--media/java/android/media/MtpDatabase.java373
-rw-r--r--media/java/android/media/MtpPropertyGroup.java442
-rw-r--r--media/java/android/media/MtpPropertyList.java28
-rwxr-xr-xmedia/java/android/media/audiofx/Visualizer.java46
-rw-r--r--media/jni/android_media_MtpDatabase.cpp31
-rw-r--r--media/libmedia/Visualizer.cpp8
-rw-r--r--media/mtp/MtpDatabase.h3
-rw-r--r--media/mtp/MtpProperty.cpp2
-rw-r--r--media/mtp/MtpServer.cpp5
-rwxr-xr-xpackages/DefaultContainerService/AndroidManifest.xml1
-rw-r--r--packages/SystemUI/res/drawable-nodpi/panel_notification.pngbin226 -> 152 bytes
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml26
-rw-r--r--packages/SystemUI/res/values-da/strings.xml26
-rw-r--r--packages/SystemUI/res/values-de/strings.xml26
-rw-r--r--packages/SystemUI/res/values-el/strings.xml26
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml26
-rw-r--r--packages/SystemUI/res/values-es/strings.xml26
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml26
-rw-r--r--packages/SystemUI/res/values-it/strings.xml26
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml26
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml26
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml26
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml26
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml26
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml26
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml26
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml26
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml26
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml26
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml26
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml26
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java34
-rw-r--r--policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java7
-rw-r--r--policy/src/com/android/internal/policy/impl/PhoneWindow.java84
-rwxr-xr-xpolicy/src/com/android/internal/policy/impl/PhoneWindowManager.java46
-rw-r--r--policy/src/com/android/internal/policy/impl/ShortcutManager.java14
-rw-r--r--services/audioflinger/AudioPolicyManagerBase.cpp104
-rw-r--r--services/java/com/android/server/InputManager.java57
-rwxr-xr-xservices/java/com/android/server/NotificationManagerService.java5
-rw-r--r--services/java/com/android/server/ScreenRotationAnimation.java4
-rw-r--r--services/java/com/android/server/WindowManagerService.java49
-rw-r--r--services/jni/com_android_server_InputManager.cpp180
-rw-r--r--services/sensorservice/GravitySensor.cpp10
-rw-r--r--services/sensorservice/GravitySensor.h4
-rw-r--r--services/sensorservice/LinearAccelerationSensor.cpp4
-rw-r--r--services/sensorservice/LinearAccelerationSensor.h1
-rw-r--r--services/sensorservice/RotationVectorSensor.cpp29
-rw-r--r--services/sensorservice/RotationVectorSensor.h2
-rw-r--r--services/sensorservice/SecondOrderLowPassFilter.cpp19
-rw-r--r--services/sensorservice/SecondOrderLowPassFilter.h12
-rw-r--r--services/sensorservice/SensorDevice.cpp22
-rw-r--r--services/sensorservice/SensorDevice.h3
-rw-r--r--services/sensorservice/SensorInterface.cpp13
-rw-r--r--services/sensorservice/SensorInterface.h3
-rw-r--r--telephony/java/com/android/internal/telephony/CallManager.java30
-rw-r--r--telephony/java/com/android/internal/telephony/CallerInfo.java175
-rwxr-xr-xtelephony/java/com/android/internal/telephony/sip/SipPhone.java9
-rw-r--r--tests/DumpRenderTree/AndroidManifest.xml4
-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/com/android/layoutlib/bridge/Bridge.java10
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeLayoutScene.java81
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/AnimationThread.java2
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutSceneImpl.java98
-rw-r--r--voip/java/android/net/rtp/AudioGroup.java110
-rw-r--r--voip/java/android/net/rtp/AudioStream.java28
-rw-r--r--voip/java/android/net/rtp/RtpStream.java7
-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.java39
-rw-r--r--voip/jni/rtp/AmrCodec.cpp2
-rw-r--r--voip/jni/rtp/AudioGroup.cpp18
-rw-r--r--voip/jni/rtp/EchoSuppressor.cpp21
294 files changed, 6654 insertions, 2993 deletions
diff --git a/api/current.xml b/api/current.xml
index 6dabecf..b7714e5 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"
@@ -2528,6 +2539,17 @@
visibility="public"
>
</field>
+<field name="borderlessButtonStyle"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843580"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="bottom"
type="int"
transient="false"
@@ -3551,6 +3573,28 @@
visibility="public"
>
</field>
+<field name="dividerHorizontal"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843581"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="dividerPadding"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843579"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="dividerVertical"
type="int"
transient="false"
@@ -7720,6 +7764,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 +7885,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"
@@ -8325,6 +8424,17 @@
visibility="public"
>
</field>
+<field name="showDividers"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843578"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="showSilent"
type="int"
transient="false"
@@ -9953,6 +10063,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"
@@ -15410,6 +15564,17 @@
visibility="public"
>
</field>
+<field name="Widget_Holo_Button_Borderless"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16974047"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="Widget_Holo_Button_Inset"
type="int"
transient="false"
@@ -18932,6 +19097,19 @@
<parameter name="items" type="android.animation.Animator...">
</parameter>
</method>
+<method name="playSequentially"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="items" type="java.util.List&lt;android.animation.Animator&gt;">
+</parameter>
+</method>
<method name="playTogether"
return="void"
abstract="false"
@@ -18945,6 +19123,19 @@
<parameter name="items" type="android.animation.Animator...">
</parameter>
</method>
+<method name="playTogether"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="items" type="java.util.Collection&lt;android.animation.Animator&gt;">
+</parameter>
+</method>
<method name="setDuration"
return="android.animation.AnimatorSet"
abstract="false"
@@ -20613,6 +20804,19 @@
visibility="public"
>
</constructor>
+<method name="addOnMenuVisibilityListener"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.app.ActionBar.OnMenuVisibilityListener">
+</parameter>
+</method>
<method name="addTab"
return="void"
abstract="true"
@@ -20862,6 +21066,19 @@
visibility="public"
>
</method>
+<method name="removeOnMenuVisibilityListener"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.app.ActionBar.OnMenuVisibilityListener">
+</parameter>
+</method>
<method name="removeTab"
return="void"
abstract="true"
@@ -20995,7 +21212,7 @@
>
<parameter name="adapter" type="android.widget.SpinnerAdapter">
</parameter>
-<parameter name="callback" type="android.app.ActionBar.NavigationCallback">
+<parameter name="callback" type="android.app.ActionBar.OnNavigationListener">
</parameter>
</method>
<method name="setDropdownNavigationMode"
@@ -21010,7 +21227,7 @@
>
<parameter name="adapter" type="android.widget.SpinnerAdapter">
</parameter>
-<parameter name="callback" type="android.app.ActionBar.NavigationCallback">
+<parameter name="callback" type="android.app.ActionBar.OnNavigationListener">
</parameter>
<parameter name="defaultSelectedPosition" type="int">
</parameter>
@@ -21027,7 +21244,7 @@
>
<parameter name="adapter" type="android.widget.SpinnerAdapter">
</parameter>
-<parameter name="callback" type="android.app.ActionBar.NavigationCallback">
+<parameter name="callback" type="android.app.ActionBar.OnNavigationListener">
</parameter>
</method>
<method name="setNavigationMode"
@@ -21339,7 +21556,28 @@
>
</field>
</class>
-<interface name="ActionBar.NavigationCallback"
+<interface name="ActionBar.OnMenuVisibilityListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onMenuVisibilityChanged"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="isVisible" type="boolean">
+</parameter>
+</method>
+</interface>
+<interface name="ActionBar.OnNavigationListener"
abstract="true"
static="true"
final="false"
@@ -23045,6 +23283,17 @@
<parameter name="exitAnim" type="int">
</parameter>
</method>
+<method name="recreate"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="registerForContextMenu"
return="void"
abstract="false"
@@ -89569,6 +89818,17 @@
visibility="public"
>
</method>
+<method name="getPreferredPreviewSizeForVideo"
+ return="android.hardware.Camera.Size"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getPreviewFormat"
return="int"
abstract="false"
@@ -89758,6 +90018,17 @@
visibility="public"
>
</method>
+<method name="getSupportedVideoSizes"
+ return="java.util.List&lt;android.hardware.Camera.Size&gt;"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getSupportedWhiteBalance"
return="java.util.List&lt;java.lang.String&gt;"
abstract="false"
@@ -160863,6 +161134,468 @@
>
</field>
</interface>
+<class name="Ptp"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="Ptp"
+ type="android.provider.Ptp"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<field name="AUTHORITY"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;ptp&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="Ptp.Device"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.provider.BaseColumns">
+</implements>
+<constructor name="Ptp.Device"
+ type="android.provider.Ptp.Device"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="getContentUri"
+ return="android.net.Uri"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="deviceID" type="int">
+</parameter>
+</method>
+<field name="CONTENT_URI"
+ type="android.net.Uri"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MANUFACTURER"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;manufacturer&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MODEL"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;model&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="Ptp.Object"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.provider.BaseColumns">
+</implements>
+<constructor name="Ptp.Object"
+ type="android.provider.Ptp.Object"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="getContentUri"
+ return="android.net.Uri"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="deviceID" type="int">
+</parameter>
+<parameter name="objectID" type="long">
+</parameter>
+</method>
+<method name="getContentUriForImport"
+ return="android.net.Uri"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="deviceID" type="int">
+</parameter>
+<parameter name="objectID" type="long">
+</parameter>
+<parameter name="destPath" type="java.lang.String">
+</parameter>
+</method>
+<method name="getContentUriForObjectChildren"
+ return="android.net.Uri"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="deviceID" type="int">
+</parameter>
+<parameter name="objectID" type="long">
+</parameter>
+</method>
+<method name="getContentUriForStorageChildren"
+ return="android.net.Uri"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="deviceID" type="int">
+</parameter>
+<parameter name="storageID" type="long">
+</parameter>
+</method>
+<field name="ASSOCIATION_DESC"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;association_desc&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="ASSOCIATION_TYPE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;association_type&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DATE_CREATED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;date_created&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DATE_MODIFIED"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;date_modified&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="FORMAT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;format&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="IMAGE_DEPTH"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;image_depth&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="IMAGE_HEIGHT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;image_height&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="IMAGE_WIDTH"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;image_width&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="KEYWORDS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;keywords&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="NAME"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;name&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PARENT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;parent&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PROTECTION_STATUS"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;protection_status&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SEQUENCE_NUMBER"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;sequence_number&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SIZE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;size&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="STORAGE_ID"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;storage_id&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="THUMB"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;thumb&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="THUMB_FORMAT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;thumb_format&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="THUMB_HEIGHT"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;thumb_height&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="THUMB_SIZE"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;thumb_size&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="THUMB_WIDTH"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;thumb_width&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<class name="Ptp.Storage"
+ extends="java.lang.Object"
+ abstract="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<implements name="android.provider.BaseColumns">
+</implements>
+<constructor name="Ptp.Storage"
+ type="android.provider.Ptp.Storage"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="getContentUri"
+ return="android.net.Uri"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="deviceID" type="int">
+</parameter>
+</method>
+<method name="getContentUri"
+ return="android.net.Uri"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="deviceID" type="int">
+</parameter>
+<parameter name="storageID" type="long">
+</parameter>
+</method>
+<field name="DESCRIPTION"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;description&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="IDENTIFIER"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;identifier&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<class name="SearchRecentSuggestions"
extends="java.lang.Object"
abstract="false"
@@ -185500,7 +186233,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"
@@ -185524,11 +186257,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"
@@ -194662,6 +195406,17 @@
visibility="public"
>
</method>
+<method name="getLocalState"
+ return="java.lang.Object"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getResult"
return="boolean"
abstract="false"
@@ -196554,7 +197309,7 @@
value="0"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -208663,6 +209418,8 @@
</parameter>
<parameter name="myWindowOnly" type="boolean">
</parameter>
+<parameter name="myLocalState" type="java.lang.Object">
+</parameter>
</method>
<method name="unscheduleDrawable"
return="void"
@@ -236689,6 +237446,17 @@
visibility="public"
>
</method>
+<method name="getShowDividers"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getWeightSum"
return="float"
abstract="false"
@@ -236769,6 +237537,19 @@
<parameter name="i" type="int">
</parameter>
</method>
+<method name="setDividerDrawable"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="divider" type="android.graphics.drawable.Drawable">
+</parameter>
+</method>
<method name="setGravity"
return="void"
abstract="false"
@@ -236821,6 +237602,19 @@
<parameter name="orientation" type="int">
</parameter>
</method>
+<method name="setShowDividers"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="showDividers" type="int">
+</parameter>
+</method>
<method name="setVerticalGravity"
return="void"
abstract="false"
@@ -236858,6 +237652,50 @@
visibility="public"
>
</field>
+<field name="SHOW_DIVIDER_BEGINNING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SHOW_DIVIDER_END"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SHOW_DIVIDER_MIDDLE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="SHOW_DIVIDER_NONE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="VERTICAL"
type="int"
transient="false"
@@ -238624,7 +239462,35 @@
>
<parameter name="context" type="android.content.Context">
</parameter>
-<parameter name="interpolator" type="android.graphics.Interpolator">
+<parameter name="interpolator" type="android.view.animation.Interpolator">
+</parameter>
+</constructor>
+<constructor name="OverScroller"
+ type="android.widget.OverScroller"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="interpolator" type="android.view.animation.Interpolator">
+</parameter>
+<parameter name="bounceCoefficientX" type="float">
+</parameter>
+<parameter name="bounceCoefficientY" type="float">
+</parameter>
+</constructor>
+<constructor name="OverScroller"
+ type="android.widget.OverScroller"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="interpolator" type="android.view.animation.Interpolator">
</parameter>
<parameter name="bounceCoefficientX" type="float">
</parameter>
@@ -244959,19 +245825,6 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="drawable" type="android.graphics.drawable.Drawable">
-</parameter>
-</method>
-<method name="setDividerDrawable"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
<parameter name="resId" type="int">
</parameter>
</method>
@@ -249214,7 +250067,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="t" type="T">
+<parameter name="arg0" type="T">
</parameter>
</method>
</interface>
@@ -249246,6 +250099,25 @@
</package>
<package name="dalvik.bytecode"
>
+<class name="OpcodeInfo"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<field name="MAXIMUM_VALUE"
+ type="int"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<interface name="Opcodes"
abstract="true"
static="false"
@@ -249601,7 +250473,7 @@
value="236"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -249942,7 +250814,7 @@
value="238"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -249953,7 +250825,7 @@
value="239"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -250250,7 +251122,7 @@
value="244"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -250261,7 +251133,7 @@
value="242"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -250294,7 +251166,7 @@
value="243"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -250305,7 +251177,7 @@
value="232"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -250404,7 +251276,7 @@
value="240"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -250481,7 +251353,7 @@
value="250"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -250492,7 +251364,7 @@
value="251"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -250525,7 +251397,7 @@
value="248"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -250536,7 +251408,7 @@
value="249"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -250613,7 +251485,7 @@
value="247"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -250624,7 +251496,7 @@
value="245"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -250657,7 +251529,7 @@
value="246"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -250668,7 +251540,7 @@
value="233"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -251416,7 +252288,7 @@
value="234"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -251625,7 +252497,7 @@
value="235"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -251735,7 +252607,7 @@
value="237"
static="true"
final="true"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</field>
@@ -334462,7 +335334,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="minSize" type="int">
+<parameter name="numElements" type="int">
</parameter>
</constructor>
<constructor name="ArrayDeque"
@@ -334728,7 +335600,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="obj" type="java.lang.Object">
+<parameter name="o" type="java.lang.Object">
</parameter>
</method>
<method name="removeLast"
@@ -334752,7 +335624,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="obj" type="java.lang.Object">
+<parameter name="o" type="java.lang.Object">
</parameter>
</method>
<method name="size"
@@ -339510,6 +340382,19 @@
>
<implements name="java.util.Queue">
</implements>
+<method name="add"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
<method name="addFirst"
return="void"
abstract="true"
@@ -339536,6 +340421,19 @@
<parameter name="e" type="E">
</parameter>
</method>
+<method name="contains"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
<method name="descendingIterator"
return="java.util.Iterator&lt;E&gt;"
abstract="true"
@@ -339547,6 +340445,17 @@
visibility="public"
>
</method>
+<method name="element"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getFirst"
return="E"
abstract="true"
@@ -339569,6 +340478,30 @@
visibility="public"
>
</method>
+<method name="iterator"
+ return="java.util.Iterator&lt;E&gt;"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="offer"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
<method name="offerFirst"
return="boolean"
abstract="true"
@@ -339595,6 +340528,17 @@
<parameter name="e" type="E">
</parameter>
</method>
+<method name="peek"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="peekFirst"
return="E"
abstract="true"
@@ -339617,6 +340561,17 @@
visibility="public"
>
</method>
+<method name="poll"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="pollFirst"
return="E"
abstract="true"
@@ -339663,6 +340618,30 @@
<parameter name="e" type="E">
</parameter>
</method>
+<method name="remove"
+ return="E"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="remove"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="o" type="java.lang.Object">
+</parameter>
+</method>
<method name="removeFirst"
return="E"
abstract="true"
@@ -339711,6 +340690,17 @@
<parameter name="o" type="java.lang.Object">
</parameter>
</method>
+<method name="size"
+ return="int"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
</interface>
<class name="Dictionary"
extends="java.lang.Object"
@@ -343635,11 +344625,24 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="endKey" type="K">
+<parameter name="toKey" type="K">
</parameter>
<parameter name="inclusive" type="boolean">
</parameter>
</method>
+<method name="headMap"
+ return="java.util.SortedMap&lt;K, V&gt;"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="toKey" type="K">
+</parameter>
+</method>
<method name="higherEntry"
return="java.util.Map.Entry&lt;K, V&gt;"
abstract="true"
@@ -343746,13 +344749,28 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="startKey" type="K">
+<parameter name="fromKey" type="K">
</parameter>
-<parameter name="startInclusive" type="boolean">
+<parameter name="fromInclusive" type="boolean">
</parameter>
-<parameter name="endKey" type="K">
+<parameter name="toKey" type="K">
</parameter>
-<parameter name="endInclusive" type="boolean">
+<parameter name="toInclusive" type="boolean">
+</parameter>
+</method>
+<method name="subMap"
+ return="java.util.SortedMap&lt;K, V&gt;"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fromKey" type="K">
+</parameter>
+<parameter name="toKey" type="K">
</parameter>
</method>
<method name="tailMap"
@@ -343765,11 +344783,24 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="startKey" type="K">
+<parameter name="fromKey" type="K">
</parameter>
<parameter name="inclusive" type="boolean">
</parameter>
</method>
+<method name="tailMap"
+ return="java.util.SortedMap&lt;K, V&gt;"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fromKey" type="K">
+</parameter>
+</method>
</interface>
<interface name="NavigableSet"
abstract="true"
@@ -343838,9 +344869,22 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="end" type="E">
+<parameter name="toElement" type="E">
</parameter>
-<parameter name="endInclusive" type="boolean">
+<parameter name="inclusive" type="boolean">
+</parameter>
+</method>
+<method name="headSet"
+ return="java.util.SortedSet&lt;E&gt;"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="toElement" type="E">
</parameter>
</method>
<method name="higher"
@@ -343856,6 +344900,17 @@
<parameter name="e" type="E">
</parameter>
</method>
+<method name="iterator"
+ return="java.util.Iterator&lt;E&gt;"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="lower"
return="E"
abstract="true"
@@ -343901,13 +344956,28 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="start" type="E">
+<parameter name="fromElement" type="E">
</parameter>
-<parameter name="startInclusive" type="boolean">
+<parameter name="fromInclusive" type="boolean">
</parameter>
-<parameter name="end" type="E">
+<parameter name="toElement" type="E">
</parameter>
-<parameter name="endInclusive" type="boolean">
+<parameter name="toInclusive" type="boolean">
+</parameter>
+</method>
+<method name="subSet"
+ return="java.util.SortedSet&lt;E&gt;"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fromElement" type="E">
+</parameter>
+<parameter name="toElement" type="E">
</parameter>
</method>
<method name="tailSet"
@@ -343920,9 +344990,22 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="start" type="E">
+<parameter name="fromElement" type="E">
</parameter>
-<parameter name="startInclusive" type="boolean">
+<parameter name="inclusive" type="boolean">
+</parameter>
+</method>
+<method name="tailSet"
+ return="java.util.SortedSet&lt;E&gt;"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fromElement" type="E">
</parameter>
</method>
</interface>
@@ -344584,6 +345667,19 @@
>
<implements name="java.util.Collection">
</implements>
+<method name="add"
+ return="boolean"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="e" type="E">
+</parameter>
+</method>
<method name="element"
return="E"
abstract="true"
@@ -344605,7 +345701,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="o" type="E">
+<parameter name="e" type="E">
</parameter>
</method>
<method name="peek"
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 040421a..f62db1c 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -341,9 +341,11 @@ public final class Pm {
if (nonLocalized != null) {
return nonLocalized.toString();
}
- Resources r = getResources(pii);
- if (r != null) {
- return r.getString(res);
+ if (res != 0) {
+ Resources r = getResources(pii);
+ if (r != null) {
+ return r.getString(res);
+ }
}
return null;
}
diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java
index b96391a..6e589e4 100644
--- a/core/java/android/animation/AnimatorInflater.java
+++ b/core/java/android/animation/AnimatorInflater.java
@@ -21,6 +21,7 @@ import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.content.res.Resources.NotFoundException;
import android.util.AttributeSet;
+import android.util.TypedValue;
import android.util.Xml;
import android.view.animation.AnimationUtils;
import org.xmlpull.v1.XmlPullParser;
@@ -195,72 +196,95 @@ public class AnimatorInflater {
anim = new ValueAnimator();
}
TypeEvaluator evaluator = null;
- boolean hasFrom = a.hasValue(com.android.internal.R.styleable.Animator_valueFrom);
- boolean hasTo = a.hasValue(com.android.internal.R.styleable.Animator_valueTo);
-
- switch (valueType) {
-
- case VALUE_TYPE_FLOAT: {
- float valueFrom;
- float valueTo;
- if (hasFrom) {
- valueFrom = a.getFloat(com.android.internal.R.styleable.Animator_valueFrom, 0f);
- if (hasTo) {
- valueTo = a.getFloat(com.android.internal.R.styleable.Animator_valueTo, 0f);
- anim.setFloatValues(valueFrom, valueTo);
+
+ int valueFromIndex = com.android.internal.R.styleable.Animator_valueFrom;
+ int valueToIndex = com.android.internal.R.styleable.Animator_valueTo;
+
+ boolean getFloats = (valueType == VALUE_TYPE_FLOAT);
+
+ TypedValue tvFrom = a.peekValue(valueFromIndex);
+ boolean hasFrom = (tvFrom != null);
+ int fromType = hasFrom ? tvFrom.type : 0;
+ TypedValue tvTo = a.peekValue(valueToIndex);
+ boolean hasTo = (tvTo != null);
+ int toType = hasTo ? tvTo.type : 0;
+
+ if ((hasFrom && (fromType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
+ (fromType <= TypedValue.TYPE_LAST_COLOR_INT)) ||
+ (hasTo && (toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
+ (toType <= TypedValue.TYPE_LAST_COLOR_INT))) {
+ // special case for colors: ignore valueType and get ints
+ getFloats = false;
+ anim.setEvaluator(new RGBEvaluator());
+ }
+
+ if (getFloats) {
+ float valueFrom;
+ float valueTo;
+ if (hasFrom) {
+ if (fromType == TypedValue.TYPE_DIMENSION) {
+ valueFrom = a.getDimension(valueFromIndex, 0f);
+ } else {
+ valueFrom = a.getFloat(valueFromIndex, 0f);
+ }
+ if (hasTo) {
+ if (toType == TypedValue.TYPE_DIMENSION) {
+ valueTo = a.getDimension(valueToIndex, 0f);
} else {
- anim.setFloatValues(valueFrom);
+ valueTo = a.getFloat(valueToIndex, 0f);
}
+ anim.setFloatValues(valueFrom, valueTo);
+ } else {
+ anim.setFloatValues(valueFrom);
+ }
+ } else {
+ if (toType == TypedValue.TYPE_DIMENSION) {
+ valueTo = a.getDimension(valueToIndex, 0f);
} else {
- valueTo = a.getFloat(com.android.internal.R.styleable.Animator_valueTo, 0f);
- anim.setFloatValues(valueTo);
+ valueTo = a.getFloat(valueToIndex, 0f);
}
+ anim.setFloatValues(valueTo);
}
- break;
-
- case VALUE_TYPE_COLOR:
- evaluator = new RGBEvaluator();
- anim.setEvaluator(evaluator);
- // fall through to pick up values
- case VALUE_TYPE_INT: {
- int valueFrom;
- int valueTo;
- if (hasFrom) {
- valueFrom = a.getInteger(com.android.internal.R.styleable.Animator_valueFrom, 0);
- if (hasTo) {
- valueTo = a.getInteger(com.android.internal.R.styleable.Animator_valueTo, 0);
- anim.setIntValues(valueFrom, valueTo);
+ } else {
+ int valueFrom;
+ int valueTo;
+ if (hasFrom) {
+ if (fromType == TypedValue.TYPE_DIMENSION) {
+ valueFrom = (int) a.getDimension(valueFromIndex, 0f);
+ } else if ((fromType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
+ (fromType <= TypedValue.TYPE_LAST_COLOR_INT)) {
+ valueFrom = a.getColor(valueFromIndex, 0);
+ } else {
+ valueFrom = a.getInt(valueFromIndex, 0);
+ }
+ if (hasTo) {
+ if (toType == TypedValue.TYPE_DIMENSION) {
+ valueTo = (int) a.getDimension(valueToIndex, 0f);
+ } else if ((toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
+ (toType <= TypedValue.TYPE_LAST_COLOR_INT)) {
+ valueTo = a.getColor(valueToIndex, 0);
} else {
- anim.setIntValues(valueFrom);
+ valueTo = a.getInt(valueToIndex, 0);
}
+ anim.setIntValues(valueFrom, valueTo);
} else {
- valueTo = a.getInteger(com.android.internal.R.styleable.Animator_valueTo, 0);
- anim.setIntValues(valueTo);
+ anim.setIntValues(valueFrom);
}
- }
- break;
-
- case VALUE_TYPE_CUSTOM: {
- // TODO: How to get an 'Object' value?
- float valueFrom;
- float valueTo;
- if (hasFrom) {
- valueFrom = a.getFloat(com.android.internal.R.styleable.Animator_valueFrom, 0f);
- if (hasTo) {
- valueTo = a.getFloat(com.android.internal.R.styleable.Animator_valueTo, 0f);
- anim.setFloatValues(valueFrom, valueTo);
+ } else {
+ if (hasTo) {
+ if (toType == TypedValue.TYPE_DIMENSION) {
+ valueTo = (int) a.getDimension(valueToIndex, 0f);
+ } else if ((toType >= TypedValue.TYPE_FIRST_COLOR_INT) &&
+ (toType <= TypedValue.TYPE_LAST_COLOR_INT)) {
+ valueTo = a.getColor(valueToIndex, 0);
} else {
- anim.setFloatValues(valueFrom);
+ valueTo = a.getInt(valueToIndex, 0);
}
- } else {
- valueTo = a.getFloat(com.android.internal.R.styleable.Animator_valueTo, 0f);
- anim.setFloatValues(valueTo);
+ anim.setIntValues(valueTo);
}
}
- break;
}
-
anim.setDuration(duration);
anim.setStartDelay(startDelay);
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index f5420d1..154e084 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -17,7 +17,9 @@
package android.animation;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
+import java.util.List;
/**
* This class plays a set of {@link Animator} objects in the specified order. Animations
@@ -117,10 +119,29 @@ public final class AnimatorSet extends Animator {
}
/**
+ * Sets up this AnimatorSet to play all of the supplied animations at the same time.
+ *
+ * @param items The animations that will be started simultaneously.
+ */
+ public void playTogether(Collection<Animator> items) {
+ if (items != null && items.size() > 0) {
+ mNeedsSort = true;
+ Builder builder = null;
+ for (Animator anim : items) {
+ if (builder == null) {
+ builder = play(anim);
+ } else {
+ builder.with(anim);
+ }
+ }
+ }
+ }
+
+ /**
* Sets up this AnimatorSet to play each of the supplied animations when the
* previous animation ends.
*
- * @param items The aniamtions that will be started one after another.
+ * @param items The animations that will be started one after another.
*/
public void playSequentially(Animator... items) {
if (items != null) {
@@ -136,6 +157,25 @@ public final class AnimatorSet extends Animator {
}
/**
+ * Sets up this AnimatorSet to play each of the supplied animations when the
+ * previous animation ends.
+ *
+ * @param items The animations that will be started one after another.
+ */
+ public void playSequentially(List<Animator> items) {
+ if (items != null && items.size() > 0) {
+ mNeedsSort = true;
+ if (items.size() == 1) {
+ play(items.get(0));
+ } else {
+ for (int i = 0; i < items.size() - 1; ++i) {
+ play(items.get(i)).before(items.get(i+1));
+ }
+ }
+ }
+ }
+
+ /**
* Returns the current list of child Animator objects controlled by this
* AnimatorSet. This is a copy of the internal list; modifications to the returned list
* will not affect the AnimatorSet, although changes to the underlying Animator objects
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/ActionBar.java b/core/java/android/app/ActionBar.java
index 7a6ad0f..2f69520 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -168,13 +168,13 @@ public abstract class ActionBar {
* @param adapter An adapter that will provide views both to display
* the current navigation selection and populate views
* within the dropdown navigation menu.
- * @param callback A NavigationCallback that will receive events when the user
+ * @param callback A OnNavigationListener that will receive events when the user
* selects a navigation item.
* @deprecated See setListNavigationCallbacks.
*/
@Deprecated
public abstract void setDropdownNavigationMode(SpinnerAdapter adapter,
- NavigationCallback callback);
+ OnNavigationListener callback);
/**
* Set the adapter and navigation callback for list navigation mode.
@@ -182,17 +182,17 @@ public abstract class ActionBar {
* The supplied adapter will provide views for the expanded list as well as
* the currently selected item. (These may be displayed differently.)
*
- * The supplied NavigationCallback will alert the application when the user
+ * The supplied OnNavigationListener will alert the application when the user
* changes the current list selection.
*
* @param adapter An adapter that will provide views both to display
* the current navigation selection and populate views
* within the dropdown navigation menu.
- * @param callback A NavigationCallback that will receive events when the user
+ * @param callback An OnNavigationListener that will receive events when the user
* selects a navigation item.
*/
public abstract void setListNavigationCallbacks(SpinnerAdapter adapter,
- NavigationCallback callback);
+ OnNavigationListener callback);
/**
* Set the action bar into dropdown navigation mode and supply an adapter that will
@@ -201,7 +201,7 @@ public abstract class ActionBar {
* @param adapter An adapter that will provide views both to display the current
* navigation selection and populate views within the dropdown
* navigation menu.
- * @param callback A NavigationCallback that will receive events when the user
+ * @param callback A OnNavigationListener that will receive events when the user
* selects a navigation item.
* @param defaultSelectedPosition Position within the provided adapter that should be
* selected from the outset.
@@ -209,7 +209,7 @@ public abstract class ActionBar {
*/
@Deprecated
public abstract void setDropdownNavigationMode(SpinnerAdapter adapter,
- NavigationCallback callback, int defaultSelectedPosition);
+ OnNavigationListener callback, int defaultSelectedPosition);
/**
* Set the selected navigation item in list or tabbed navigation modes.
@@ -532,9 +532,24 @@ public abstract class ActionBar {
public abstract boolean isShowing();
/**
- * Callback interface for ActionBar navigation events.
+ * Add a listener that will respond to menu visibility change events.
+ *
+ * @param listener The new listener to add
+ */
+ public abstract void addOnMenuVisibilityListener(OnMenuVisibilityListener listener);
+
+ /**
+ * Remove a menu visibility listener. This listener will no longer receive menu
+ * visibility change events.
+ *
+ * @param listener A listener to remove that was previously added
+ */
+ public abstract void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener);
+
+ /**
+ * Listener interface for ActionBar navigation events.
*/
- public interface NavigationCallback {
+ public interface OnNavigationListener {
/**
* This method is called whenever a navigation item in your action bar
* is selected.
@@ -547,6 +562,21 @@ public abstract class ActionBar {
}
/**
+ * Listener for receiving events when action bar menus are shown or hidden.
+ */
+ public interface OnMenuVisibilityListener {
+ /**
+ * Called when an action bar menu is shown or hidden. Applications may want to use
+ * this to tune auto-hiding behavior for the action bar or pause/resume video playback,
+ * gameplay, or other activity within the main content area.
+ *
+ * @param isVisible True if an action bar menu is now visible, false if no action bar
+ * menus are visible.
+ */
+ public void onMenuVisibilityChanged(boolean isVisible);
+ }
+
+ /**
* A tab in the action bar.
*
* <p>Tabs manage the hiding and showing of {@link Fragment}s.
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index d69a179..0a2e031 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -42,6 +42,7 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
import android.os.Parcelable;
import android.os.RemoteException;
import android.text.Selection;
@@ -78,6 +79,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
/**
* An activity is a single, focused thing that the user can do. Almost all
@@ -842,8 +844,6 @@ public class Activity extends ContextThemeWrapper
* @see #onPostCreate
*/
protected void onCreate(Bundle savedInstanceState) {
- mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
- com.android.internal.R.styleable.Window_windowNoDisplay, false);
if (mLastNonConfigurationInstances != null) {
mAllLoaderManagers = mLastNonConfigurationInstances.loaders;
}
@@ -2362,6 +2362,9 @@ public class Activity extends ContextThemeWrapper
* @return The default implementation returns true.
*/
public boolean onMenuOpened(int featureId, Menu menu) {
+ if (featureId == Window.FEATURE_ACTION_BAR) {
+ mActionBar.dispatchMenuVisibilityChanged(true);
+ }
return true;
}
@@ -2392,7 +2395,7 @@ public class Activity extends ContextThemeWrapper
return true;
}
return mFragments.dispatchContextItemSelected(item);
-
+
default:
return false;
}
@@ -2417,6 +2420,10 @@ public class Activity extends ContextThemeWrapper
case Window.FEATURE_CONTEXT_MENU:
onContextMenuClosed(menu);
break;
+
+ case Window.FEATURE_ACTION_BAR:
+ mActionBar.dispatchMenuVisibilityChanged(false);
+ break;
}
}
@@ -3502,6 +3509,22 @@ public class Activity extends ContextThemeWrapper
}
/**
+ * Cause this Activity to be recreated with a new instance. This results
+ * in essentially the same flow as when the Activity is created due to
+ * a configuration change -- the current instance will go through its
+ * lifecycle to {@link #onDestroy} and a new instance then created after it.
+ */
+ public void recreate() {
+ if (mParent != null) {
+ throw new IllegalStateException("Can only be called on top-level activity");
+ }
+ if (Looper.myLooper() != mMainThread.getLooper()) {
+ throw new IllegalStateException("Must be called from main thread");
+ }
+ mMainThread.requestRelaunchActivity(mToken, null, null, 0, false, null, false);
+ }
+
+ /**
* Call this when your activity is done and should be closed. The
* ActivityResult is propagated back to whoever launched you via
* onActivityResult().
@@ -4255,6 +4278,8 @@ public class Activity extends ContextThemeWrapper
final void performCreate(Bundle icicle) {
onCreate(icicle);
+ mVisibleFromClient = !mWindow.getWindowStyle().getBoolean(
+ com.android.internal.R.styleable.Window_windowNoDisplay, false);
mFragments.dispatchActivityCreated();
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index c0714e3..a8f08c2 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -224,6 +224,11 @@ public final class ActivityThread {
boolean startsNotResumed;
boolean isForward;
+ int pendingConfigChanges;
+ boolean onlyLocalRequest;
+
+ View mPendingRemoveWindow;
+ WindowManager mPendingRemoveWindowManager;
ActivityClientRecord() {
parent = null;
@@ -444,19 +449,8 @@ public final class ActivityThread {
public final void scheduleRelaunchActivity(IBinder token,
List<ResultInfo> pendingResults, List<Intent> pendingNewIntents,
int configChanges, boolean notResumed, Configuration config) {
- ActivityClientRecord r = new ActivityClientRecord();
-
- r.token = token;
- r.pendingResults = pendingResults;
- r.pendingIntents = pendingNewIntents;
- r.startsNotResumed = notResumed;
- r.createdConfig = config;
-
- synchronized (mPackages) {
- mRelaunchingActivities.add(r);
- }
-
- queueOrSendMessage(H.RELAUNCH_ACTIVITY, r, configChanges);
+ requestRelaunchActivity(token, pendingResults, pendingNewIntents,
+ configChanges, notResumed, config, true);
}
public final void scheduleNewIntent(List<Intent> intents, IBinder token) {
@@ -981,7 +975,7 @@ public final class ActivityThread {
} break;
case RELAUNCH_ACTIVITY: {
ActivityClientRecord r = (ActivityClientRecord)msg.obj;
- handleRelaunchActivity(r, msg.arg1);
+ handleRelaunchActivity(r);
} break;
case PAUSE_ACTIVITY:
handlePauseActivity((IBinder)msg.obj, false, msg.arg1 != 0, msg.arg2);
@@ -2183,6 +2177,19 @@ public final class ActivityThread {
return r;
}
+ final void cleanUpPendingRemoveWindows(ActivityClientRecord r) {
+ if (r.mPendingRemoveWindow != null) {
+ r.mPendingRemoveWindowManager.removeViewImmediate(r.mPendingRemoveWindow);
+ IBinder wtoken = r.mPendingRemoveWindow.getWindowToken();
+ if (wtoken != null) {
+ WindowManagerImpl.getDefault().closeAll(wtoken,
+ r.activity.getClass().getName(), "Activity");
+ }
+ }
+ r.mPendingRemoveWindow = null;
+ r.mPendingRemoveWindowManager = null;
+ }
+
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
@@ -2235,6 +2242,9 @@ public final class ActivityThread {
r.hideForNow = true;
}
+ // Get rid of anything left hanging around.
+ cleanUpPendingRemoveWindows(r);
+
// The window is now visible if it has been added, we are not
// simply finishing, and we are not starting another activity.
if (!r.activity.mFinished && willBeVisible
@@ -2267,11 +2277,14 @@ public final class ActivityThread {
}
}
- r.nextIdle = mNewActivities;
- mNewActivities = r;
- if (localLOGV) Slog.v(
- TAG, "Scheduling idle handler for " + r);
- Looper.myQueue().addIdleHandler(new Idler());
+ if (!r.onlyLocalRequest) {
+ r.nextIdle = mNewActivities;
+ mNewActivities = r;
+ if (localLOGV) Slog.v(
+ TAG, "Scheduling idle handler for " + r);
+ Looper.myQueue().addIdleHandler(new Idler());
+ }
+ r.onlyLocalRequest = false;
} else {
// If an exception was thrown when trying to resume, then
@@ -2728,6 +2741,7 @@ public final class ActivityThread {
ActivityClientRecord r = performDestroyActivity(token, finishing,
configChanges, getNonConfigInstance);
if (r != null) {
+ cleanUpPendingRemoveWindows(r);
WindowManager wm = r.activity.getWindowManager();
View v = r.activity.mDecor;
if (v != null) {
@@ -2736,16 +2750,31 @@ public final class ActivityThread {
}
IBinder wtoken = v.getWindowToken();
if (r.activity.mWindowAdded) {
- wm.removeViewImmediate(v);
+ if (r.onlyLocalRequest) {
+ // Hold off on removing this until the new activity's
+ // window is being added.
+ r.mPendingRemoveWindow = v;
+ r.mPendingRemoveWindowManager = wm;
+ } else {
+ wm.removeViewImmediate(v);
+ }
}
- if (wtoken != null) {
+ if (wtoken != null && r.mPendingRemoveWindow == null) {
WindowManagerImpl.getDefault().closeAll(wtoken,
r.activity.getClass().getName(), "Activity");
}
r.activity.mDecor = null;
}
- WindowManagerImpl.getDefault().closeAll(token,
- r.activity.getClass().getName(), "Activity");
+ if (r.mPendingRemoveWindow == null) {
+ // If we are delaying the removal of the activity window, then
+ // we can't clean up all windows here. Note that we can't do
+ // so later either, which means any windows that aren't closed
+ // by the app will leak. Well we try to warning them a lot
+ // about leaking windows, because that is a bug, so if they are
+ // using this recreate facility then they get to live with leaks.
+ WindowManagerImpl.getDefault().closeAll(token,
+ r.activity.getClass().getName(), "Activity");
+ }
// Mocked out contexts won't be participating in the normal
// process lifecycle, but if we're running with a proper
@@ -2766,17 +2795,70 @@ public final class ActivityThread {
}
}
- private final void handleRelaunchActivity(ActivityClientRecord tmp, int configChanges) {
+ public final void requestRelaunchActivity(IBinder token,
+ List<ResultInfo> pendingResults, List<Intent> pendingNewIntents,
+ int configChanges, boolean notResumed, Configuration config,
+ boolean fromServer) {
+ ActivityClientRecord target = null;
+
+ synchronized (mPackages) {
+ for (int i=0; i<mRelaunchingActivities.size(); i++) {
+ ActivityClientRecord r = mRelaunchingActivities.get(i);
+ if (r.token == token) {
+ target = r;
+ if (pendingResults != null) {
+ if (r.pendingResults != null) {
+ r.pendingResults.addAll(pendingResults);
+ } else {
+ r.pendingResults = pendingResults;
+ }
+ }
+ if (pendingNewIntents != null) {
+ if (r.pendingIntents != null) {
+ r.pendingIntents.addAll(pendingNewIntents);
+ } else {
+ r.pendingIntents = pendingNewIntents;
+ }
+ }
+ break;
+ }
+ }
+
+ if (target == null) {
+ target = new ActivityClientRecord();
+ target.token = token;
+ target.pendingResults = pendingResults;
+ target.pendingIntents = pendingNewIntents;
+ if (!fromServer) {
+ ActivityClientRecord existing = mActivities.get(token);
+ if (existing != null) {
+ target.startsNotResumed = existing.paused;
+ }
+ target.onlyLocalRequest = true;
+ }
+ mRelaunchingActivities.add(target);
+ queueOrSendMessage(H.RELAUNCH_ACTIVITY, target);
+ }
+
+ if (fromServer) {
+ target.startsNotResumed = notResumed;
+ target.onlyLocalRequest = false;
+ }
+ if (config != null) {
+ target.createdConfig = config;
+ }
+ target.pendingConfigChanges |= configChanges;
+ }
+ }
+
+ private final void handleRelaunchActivity(ActivityClientRecord tmp) {
// If we are getting ready to gc after going to the background, well
// we are back active so skip it.
unscheduleGcIdler();
Configuration changedConfig = null;
+ int configChanges = 0;
- if (DEBUG_CONFIGURATION) Slog.v(TAG, "Relaunching activity "
- + tmp.token + " with configChanges=0x"
- + Integer.toHexString(configChanges));
-
// First: make sure we have the most recent configuration and most
// recent version of the activity, or skip it if some previous call
// had taken a more recent version.
@@ -2788,6 +2870,7 @@ public final class ActivityThread {
ActivityClientRecord r = mRelaunchingActivities.get(i);
if (r.token == token) {
tmp = r;
+ configChanges |= tmp.pendingConfigChanges;
mRelaunchingActivities.remove(i);
i--;
N--;
@@ -2799,6 +2882,10 @@ public final class ActivityThread {
return;
}
+ if (DEBUG_CONFIGURATION) Slog.v(TAG, "Relaunching activity "
+ + tmp.token + " with configChanges=0x"
+ + Integer.toHexString(configChanges));
+
if (mPendingConfiguration != null) {
changedConfig = mPendingConfiguration;
mPendingConfiguration = null;
@@ -2834,6 +2921,7 @@ public final class ActivityThread {
}
r.activity.mConfigChangeFlags |= configChanges;
+ r.onlyLocalRequest = tmp.onlyLocalRequest;
Intent currentIntent = r.activity.mIntent;
Bundle savedState = null;
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 64a4d7a..f90fc59 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -735,6 +735,9 @@ public class Dialog implements DialogInterface, Window.Callback,
* @see Activity#onMenuOpened(int, Menu)
*/
public boolean onMenuOpened(int featureId, Menu menu) {
+ if (featureId == Window.FEATURE_ACTION_BAR) {
+ mActionBar.dispatchMenuVisibilityChanged(true);
+ }
return true;
}
@@ -749,6 +752,9 @@ public class Dialog implements DialogInterface, Window.Callback,
* @see Activity#onPanelClosed(int, Menu)
*/
public void onPanelClosed(int featureId, Menu menu) {
+ if (featureId == Window.FEATURE_ACTION_BAR) {
+ mActionBar.dispatchMenuVisibilityChanged(false);
+ }
}
/**
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index f3b2c81..fe4b900 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -1021,6 +1021,9 @@ public class Camera {
private static final String KEY_ZOOM_SUPPORTED = "zoom-supported";
private static final String KEY_SMOOTH_ZOOM_SUPPORTED = "smooth-zoom-supported";
private static final String KEY_FOCUS_DISTANCES = "focus-distances";
+ private static final String KEY_VIDEO_SIZE = "video-size";
+ private static final String KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO =
+ "preferred-preview-size-for-video";
// Parameter key suffix for supported values.
private static final String SUPPORTED_VALUES_SUFFIX = "-values";
@@ -1398,7 +1401,7 @@ public class Camera {
/**
* Returns the dimensions setting for preview pictures.
*
- * @return a Size object with the height and width setting
+ * @return a Size object with the width and height setting
* for the preview picture
*/
public Size getPreviewSize() {
@@ -1418,6 +1421,46 @@ public class Camera {
}
/**
+ * Gets the supported video frame sizes that can be used by
+ * MediaRecorder.
+ *
+ * If the returned list is not null, the returned list will contain at
+ * least one Size and one of the sizes in the returned list must be
+ * passed to MediaRecorder.setVideoSize() for camcorder application if
+ * camera is used as the video source. In this case, the size of the
+ * preview can be different from the resolution of the recorded video
+ * during video recording.
+ *
+ * @return a list of Size object if camera has separate preview and
+ * video output; otherwise, null is returned.
+ * @see #getPreferredPreviewSizeForVideo()
+ */
+ public List<Size> getSupportedVideoSizes() {
+ String str = get(KEY_VIDEO_SIZE + SUPPORTED_VALUES_SUFFIX);
+ return splitSize(str);
+ }
+
+ /**
+ * Returns the preferred or recommended preview size (width and height)
+ * in pixels for video recording. Camcorder applications should
+ * set the preview size to a value that is not larger than the
+ * preferred preview size. In other words, the product of the width
+ * and height of the preview size should not be larger than that of
+ * the preferred preview size. In addition, we recommend to choose a
+ * preview size that has the same aspect ratio as the resolution of
+ * video to be recorded.
+ *
+ * @return the preferred preview size (width and height) in pixels for
+ * video recording if getSupportedVideoSizes() does not return
+ * null; otherwise, null is returned.
+ * @see #getSupportedVideoSizes()
+ */
+ public Size getPreferredPreviewSizeForVideo() {
+ String pair = get(KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO);
+ return strToSize(pair);
+ }
+
+ /**
* Sets the dimensions for EXIF thumbnail in Jpeg picture. If
* applications set both width and height to 0, EXIF will not contain
* thumbnail.
diff --git a/core/java/android/hardware/SensorEvent.java b/core/java/android/hardware/SensorEvent.java
index 32ff3b3..8c55bf3 100644
--- a/core/java/android/hardware/SensorEvent.java
+++ b/core/java/android/hardware/SensorEvent.java
@@ -220,25 +220,47 @@ public class SensorEvent {
* </p>
*
* <h4>{@link android.hardware.Sensor#TYPE_GRAVITY Sensor.TYPE_GRAVITY}:</h4>
- * A three dimensional vector indicating the direction and magnitude of gravity. Units
- * are m/s^2. The coordinate system is the same as is used by the acceleration sensor.
+ * <p>A three dimensional vector indicating the direction and magnitude of gravity. Units
+ * are m/s^2. The coordinate system is the same as is used by the acceleration sensor.</p>
+ * <p><b>Note:</b> When the device is at rest, the output of the gravity sensor should be identical
+ * to that of the accelerometer.</p>
*
* <h4>{@link android.hardware.Sensor#TYPE_LINEAR_ACCELERATION Sensor.TYPE_LINEAR_ACCELERATION}:</h4>
* A three dimensional vector indicating acceleration along each device axis, not including
* gravity. All values have units of m/s^2. The coordinate system is the same as is used by the
- * acceleration sensor.
+ * acceleration sensor.
+ * <p>The output of the accelerometer, gravity and linear-acceleration sensors must obey the
+ * following relation:</p>
+ * <p><ul>acceleration = gravity + linear-acceleration</ul></p>
*
* <h4>{@link android.hardware.Sensor#TYPE_ROTATION_VECTOR Sensor.TYPE_ROTATION_VECTOR}:</h4>
- * The rotation vector represents the orientation of the device as a combination of an angle
- * and an axis, in which the device has rotated through an angle theta around an axis
- * &lt;x, y, z>. The three elements of the rotation vector are
- * &lt;x*sin(theta/2), y*sin(theta/2), z*sin(theta/2)>, such that the magnitude of the rotation
- * vector is equal to sin(theta/2), and the direction of the rotation vector is equal to the
- * direction of the axis of rotation. The three elements of the rotation vector are equal to
- * the last three components of a unit quaternion
- * &lt;cos(theta/2), x*sin(theta/2), y*sin(theta/2), z*sin(theta/2)>. Elements of the rotation
- * vector are unitless. The x,y, and z axis are defined in the same way as the acceleration
- * sensor.
+ * <p>The rotation vector represents the orientation of the device as a combination of an <i>angle</i>
+ * and an <i>axis</i>, in which the device has rotated through an angle &#952 around an axis
+ * &lt;x, y, z>.</p>
+ * <p>The three elements of the rotation vector are
+ * &lt;x*sin(&#952/2), y*sin(&#952/2), z*sin(&#952/2)>, such that the magnitude of the rotation
+ * vector is equal to sin(&#952/2), and the direction of the rotation vector is equal to the
+ * direction of the axis of rotation.</p>
+ * </p>The three elements of the rotation vector are equal to
+ * the last three components of a <b>unit</b> quaternion
+ * &lt;cos(&#952/2), x*sin(&#952/2), y*sin(&#952/2), z*sin(&#952/2)>.</p>
+ * <p>Elements of the rotation vector are unitless.
+ * The x,y, and z axis are defined in the same way as the acceleration
+ * sensor.</p>
+ * <ul>
+ * <p>
+ * values[0]: x*sin(&#952/2)
+ * </p>
+ * <p>
+ * values[1]: y*sin(&#952/2)
+ * </p>
+ * <p>
+ * values[2]: z*sin(&#952/2)
+ * </p>
+ * <p>
+ * values[3]: cos(&#952/2) <i>(optional: only if value.length = 4)</i>
+ * </p>
+ * </ul>
*
* <h4>{@link android.hardware.Sensor#TYPE_ORIENTATION
* Sensor.TYPE_ORIENTATION}:</h4> All values are angles in degrees.
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index c178aee..1b799ae 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -1938,13 +1938,18 @@ public class SensorManager
* @param R an array of floats in which to store the rotation matrix
*/
public static void getRotationMatrixFromVector(float[] R, float[] rotationVector) {
- float q0 = (float)Math.sqrt(1 - rotationVector[0]*rotationVector[0] -
- rotationVector[1]*rotationVector[1] -
- rotationVector[2]*rotationVector[2]);
+
+ float q0;
float q1 = rotationVector[0];
float q2 = rotationVector[1];
float q3 = rotationVector[2];
+ if (rotationVector.length == 4) {
+ q0 = rotationVector[3];
+ } else {
+ q0 = (float)Math.sqrt(1 - q1*q1 - q2*q2 - q3*q3);
+ }
+
float sq_q1 = 2 * q1 * q1;
float sq_q2 = 2 * q2 * q2;
float sq_q3 = 2 * q3 * q3;
@@ -1995,10 +2000,12 @@ public class SensorManager
* @param Q an array of floats in which to store the computed quaternion
*/
public static void getQuaternionFromVector(float[] Q, float[] rv) {
- float w = (float)Math.sqrt(1 - rv[0]*rv[0] - rv[1]*rv[1] - rv[2]*rv[2]);
- //In this case, the w component of the quaternion is known to be a positive number
-
- Q[0] = w;
+ if (rv.length == 4) {
+ Q[0] = rv[3];
+ } else {
+ //In this case, the w component of the quaternion is known to be a positive number
+ Q[0] = (float)Math.sqrt(1 - rv[0]*rv[0] - rv[1]*rv[1] - rv[2]*rv[2]);
+ }
Q[1] = rv[0];
Q[2] = rv[1];
Q[3] = rv[2];
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 1c295a7..9c3bc9d 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -40,6 +40,7 @@ import org.apache.harmony.dalvik.ddmc.Chunk;
import org.apache.harmony.dalvik.ddmc.ChunkHandler;
import org.apache.harmony.dalvik.ddmc.DdmServer;
+import dalvik.bytecode.OpcodeInfo;
import dalvik.bytecode.Opcodes;
import dalvik.system.VMDebug;
@@ -786,7 +787,7 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
* @hide
*/
public static long countInstancesOfClass(Class cls) {
- return VMDebug.countInstancesOfClass(cls);
+ return VMDebug.countInstancesOfClass(cls, true);
}
/**
@@ -865,7 +866,7 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
* </pre>
*/
public static class InstructionCount {
- private static final int NUM_INSTR = 256;
+ private static final int NUM_INSTR = OpcodeInfo.MAXIMUM_VALUE + 1;
private int[] mCounts;
@@ -909,8 +910,11 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
*/
public int globalTotal() {
int count = 0;
- for (int i = 0; i < NUM_INSTR; i++)
+
+ for (int i = 0; i < NUM_INSTR; i++) {
count += mCounts[i];
+ }
+
return count;
}
@@ -921,27 +925,16 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
public int globalMethodInvocations() {
int count = 0;
- //count += mCounts[Opcodes.OP_EXECUTE_INLINE];
- count += mCounts[Opcodes.OP_INVOKE_VIRTUAL];
- count += mCounts[Opcodes.OP_INVOKE_SUPER];
- count += mCounts[Opcodes.OP_INVOKE_DIRECT];
- count += mCounts[Opcodes.OP_INVOKE_STATIC];
- count += mCounts[Opcodes.OP_INVOKE_INTERFACE];
- count += mCounts[Opcodes.OP_INVOKE_VIRTUAL_RANGE];
- count += mCounts[Opcodes.OP_INVOKE_SUPER_RANGE];
- count += mCounts[Opcodes.OP_INVOKE_DIRECT_RANGE];
- count += mCounts[Opcodes.OP_INVOKE_STATIC_RANGE];
- count += mCounts[Opcodes.OP_INVOKE_INTERFACE_RANGE];
- //count += mCounts[Opcodes.OP_INVOKE_DIRECT_EMPTY];
- count += mCounts[Opcodes.OP_INVOKE_VIRTUAL_QUICK];
- count += mCounts[Opcodes.OP_INVOKE_VIRTUAL_QUICK_RANGE];
- count += mCounts[Opcodes.OP_INVOKE_SUPER_QUICK];
- count += mCounts[Opcodes.OP_INVOKE_SUPER_QUICK_RANGE];
+ for (int i = 0; i < NUM_INSTR; i++) {
+ if (OpcodeInfo.isInvoke(i)) {
+ count += mCounts[i];
+ }
+ }
+
return count;
}
}
-
/**
* A Map of typed debug properties.
*/
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 754d073..6414936 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -847,6 +847,13 @@ public final class StrictMode {
}
};
+ // Note: only access this once verifying the thread has a Looper.
+ private static final ThreadLocal<Handler> threadHandler = new ThreadLocal<Handler>() {
+ @Override protected Handler initialValue() {
+ return new Handler();
+ }
+ };
+
private static boolean tooManyViolationsThisLoop() {
return violationsBeingTimed.get().size() >= MAX_OFFENSES_PER_LOOP;
}
@@ -954,7 +961,6 @@ public final class StrictMode {
return;
}
- MessageQueue queue = Looper.myQueue();
final ArrayList<ViolationInfo> records = violationsBeingTimed.get();
if (records.size() >= MAX_OFFENSES_PER_LOOP) {
// Not worth measuring. Too many offenses in one loop.
@@ -977,9 +983,30 @@ public final class StrictMode {
}
}
- queue.addIdleHandler(new MessageQueue.IdleHandler() {
- public boolean queueIdle() {
+ // We post a runnable to a Handler (== delay 0 ms) for
+ // measuring the end time of a violation instead of using
+ // an IdleHandler (as was previously used) because an
+ // IdleHandler may not run for quite a long period of time
+ // if an ongoing animation is happening and continually
+ // posting ASAP (0 ms) animation steps. Animations are
+ // throttled back to 60fps via SurfaceFlinger/View
+ // invalidates, _not_ by posting frame updates every 16
+ // milliseconds.
+ threadHandler.get().post(new Runnable() {
+ public void run() {
long loopFinishTime = SystemClock.uptimeMillis();
+
+ // Note: we do this early, before handling the
+ // violation below, as handling the violation
+ // may include PENALTY_DEATH and we don't want
+ // to keep the red border on.
+ if (windowManager != null) {
+ try {
+ windowManager.showStrictModeViolation(false);
+ } catch (RemoteException unused) {
+ }
+ }
+
for (int n = 0; n < records.size(); ++n) {
ViolationInfo v = records.get(n);
v.violationNumThisLoop = n + 1;
@@ -988,13 +1015,6 @@ public final class StrictMode {
handleViolation(v);
}
records.clear();
- if (windowManager != null) {
- try {
- windowManager.showStrictModeViolation(false);
- } catch (RemoteException unused) {
- }
- }
- return false; // remove this idle handler from the array
}
});
}
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/provider/Downloads.java b/core/java/android/provider/Downloads.java
index 683e603..b2b8c5a 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -51,7 +51,14 @@ public final class Downloads {
"android.permission.ACCESS_DOWNLOAD_MANAGER_ADVANCED";
/**
- * The permission to directly access the download manager's cache directory
+ * The permission to access the all the downloads in the manager.
+ */
+ public static final String PERMISSION_ACCESS_ALL =
+ "android.permission.ACCESS_ALL_DOWNLOADS";
+
+ /**
+ * The permission to directly access the download manager's cache
+ * directory
*/
public static final String PERMISSION_CACHE = "android.permission.ACCESS_CACHE_FILESYSTEM";
diff --git a/core/java/android/provider/Ptp.java b/core/java/android/provider/Ptp.java
index 2c54370..0f0919e 100644
--- a/core/java/android/provider/Ptp.java
+++ b/core/java/android/provider/Ptp.java
@@ -20,10 +20,13 @@ import android.content.ContentUris;
import android.net.Uri;
import android.util.Log;
-
/**
* The PTP provider supports accessing content on PTP devices.
- * @hide
+ * Currently the provider supports:
+ * - enumerating the storage units, files and directories on PTP devices
+ * - deleting files and directories on PTP devices
+ * - importing a file from PTP device into the host device's storage
+ * and adding it to the media provider
*/
public final class Ptp
{
@@ -36,6 +39,8 @@ public final class Ptp
/**
* Contains list of all PTP devices
+ * The BaseColumns._ID column contains a hardware specific identifier for the attached
+ * USB device, and is not guaranteed to be persistent across USB disconnects.
*/
public static final class Device implements BaseColumns {
@@ -59,7 +64,8 @@ public final class Ptp
}
/**
- * Contains list of storage units for an PTP device
+ * Contains list of storage units for an PTP device.
+ * The BaseColumns._ID column contains the PTP StorageID for the storage unit.
*/
public static final class Storage implements BaseColumns {
@@ -85,7 +91,10 @@ public final class Ptp
}
/**
- * Contains list of objects on an PTP device
+ * Contains list of objects on a PTP device.
+ * The columns in this table correspond directly to the ObjectInfo dataset
+ * described in the PTP specification (PIMA 15740:2000).
+ * The BaseColumns._ID column contains the object's PTP ObjectHandle.
*/
public static final class Object implements BaseColumns {
@@ -135,14 +144,14 @@ public final class Ptp
public static final String STORAGE_ID = "storage_id";
/**
- * The object's format. Can be one of the FORMAT_* symbols below,
- * or any of the valid PTP object formats as defined in the PTP specification.
+ * The object's format. Can be any of the valid PTP object formats
+ * as defined in the PTP specification.
* <P>Type: INTEGER</P>
*/
public static final String FORMAT = "format";
/**
- * The protection status of the object. See the PROTECTION_STATUS_*symbols below.
+ * The protection status of the object.
* <P>Type: INTEGER</P>
*/
public static final String PROTECTION_STATUS = "protection_status";
@@ -154,8 +163,8 @@ public final class Ptp
public static final String SIZE = "size";
/**
- * The object's thumbnail format. Can be one of the FORMAT_* symbols below,
- * or any of the valid PTP object formats as defined in the PTP specification.
+ * The object's thumbnail format. Can be any of the valid PTP object formats
+ * as defined in the PTP specification.
* <P>Type: INTEGER</P>
*/
public static final String THUMB_FORMAT = "thumb_format";
@@ -211,7 +220,6 @@ public final class Ptp
/**
* The association type for a container object.
- * For folders this is typically {@link #ASSOCIATION_TYPE_GENERIC_FOLDER}
* <P>Type: INTEGER</P>
*/
public static final String ASSOCIATION_TYPE = "association_type";
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index 0d012d6..d724320 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -190,7 +190,9 @@ public class ArrowKeyMovementMethod implements MovementMethod {
public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
int initialScrollX = -1, initialScrollY = -1;
- if (event.getAction() == MotionEvent.ACTION_UP) {
+ final int action = event.getAction();
+
+ if (action == MotionEvent.ACTION_UP) {
initialScrollX = Touch.getInitialScrollX(widget, buffer);
initialScrollY = Touch.getInitialScrollY(widget, buffer);
}
@@ -198,7 +200,7 @@ public class ArrowKeyMovementMethod implements MovementMethod {
boolean handled = Touch.onTouchEvent(widget, buffer, event);
if (widget.isFocused() && !widget.didTouchFocusSelect()) {
- if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ if (action == MotionEvent.ACTION_DOWN) {
boolean cap = isCap(buffer);
if (cap) {
int offset = widget.getOffset((int) event.getX(), (int) event.getY());
@@ -211,7 +213,7 @@ public class ArrowKeyMovementMethod implements MovementMethod {
// mode once the view detected it needed to scroll.
widget.getParent().requestDisallowInterceptTouchEvent(true);
}
- } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
+ } else if (action == MotionEvent.ACTION_MOVE) {
boolean cap = isCap(buffer);
if (cap && handled) {
@@ -231,7 +233,7 @@ public class ArrowKeyMovementMethod implements MovementMethod {
Selection.extendSelection(buffer, offset);
return true;
}
- } else if (event.getAction() == MotionEvent.ACTION_UP) {
+ } else if (action == MotionEvent.ACTION_UP) {
// If we have scrolled, then the up shouldn't move the cursor,
// but we do need to make sure the cursor is still visible at
// the current scroll offset to avoid the scroll jumping later
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/DragEvent.java b/core/java/android/view/DragEvent.java
index 07e87d6..6634f00 100644
--- a/core/java/android/view/DragEvent.java
+++ b/core/java/android/view/DragEvent.java
@@ -29,6 +29,7 @@ public class DragEvent implements Parcelable {
float mX, mY;
ClipDescription mClipDescription;
ClipData mClipData;
+ Object mLocalState;
boolean mDragResult;
private DragEvent mNext;
@@ -139,11 +140,11 @@ public static final int ACTION_DRAG_EXITED = 6;
}
static DragEvent obtain() {
- return DragEvent.obtain(0, 0f, 0f, null, null, false);
+ return DragEvent.obtain(0, 0f, 0f, null, null, null, false);
}
/** @hide */
- public static DragEvent obtain(int action, float x, float y,
+ public static DragEvent obtain(int action, float x, float y, Object localState,
ClipDescription description, ClipData data, boolean result) {
final DragEvent ev;
synchronized (gRecyclerLock) {
@@ -167,7 +168,7 @@ public static final int ACTION_DRAG_EXITED = 6;
/** @hide */
public static DragEvent obtain(DragEvent source) {
- return obtain(source.mAction, source.mX, source.mY,
+ return obtain(source.mAction, source.mX, source.mY, source.mLocalState,
source.mClipDescription, source.mClipData, source.mDragResult);
}
@@ -218,6 +219,15 @@ public static final int ACTION_DRAG_EXITED = 6;
}
/**
+ * Provides the local state object passed as the {@code myLocalState} parameter to
+ * View.startDrag(). The object will always be null here if the application receiving
+ * the DragEvent is not the one that started the drag.
+ */
+ public Object getLocalState() {
+ return mLocalState;
+ }
+
+ /**
* Provides an indication of whether the drag operation concluded successfully.
* This method is only available on ACTION_DRAG_ENDED events.
* @return {@code true} if the drag operation ended with an accepted drop; {@code false}
@@ -249,6 +259,7 @@ public static final int ACTION_DRAG_EXITED = 6;
mClipData = null;
mClipDescription = null;
+ mLocalState = null;
synchronized (gRecyclerLock) {
if (gRecyclerUsed < MAX_RECYCLED) {
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 6f4abef..24a9f87 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -94,13 +94,18 @@ public abstract class HardwareRenderer {
*/
abstract void setup(int width, int height);
+ interface HardwareDrawCallbacks {
+ void onHardwarePreDraw(Canvas canvas);
+ void onHardwarePostDraw(Canvas canvas);
+ }
+
/**
* Draws the specified view.
*
* @param view The view to draw.
* @param attachInfo AttachInfo tied to the specified view.
*/
- abstract void draw(View view, View.AttachInfo attachInfo, int yOffset);
+ abstract void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks);
/**
* Creates a new display list that can be used to record batches of
@@ -456,7 +461,7 @@ public abstract class HardwareRenderer {
}
@Override
- void draw(View view, View.AttachInfo attachInfo, int yOffset) {
+ void draw(View view, View.AttachInfo attachInfo, HardwareDrawCallbacks callbacks) {
if (canDraw()) {
attachInfo.mDrawingTime = SystemClock.uptimeMillis();
attachInfo.mIgnoreDirtyState = true;
@@ -473,11 +478,12 @@ public abstract class HardwareRenderer {
Canvas canvas = mCanvas;
int saveCount = canvas.save();
- canvas.translate(0, -yOffset);
+ callbacks.onHardwarePreDraw(canvas);
try {
view.draw(canvas);
} finally {
+ callbacks.onHardwarePostDraw(canvas);
canvas.restoreToCount(saveCount);
}
diff --git a/core/java/android/view/KeyCharacterMap.java b/core/java/android/view/KeyCharacterMap.java
index fbd9eac..97bd8dd 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..6114800 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) {
@@ -9990,9 +10075,23 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
* onProvideThumbnailMetrics() and onDrawThumbnail() methods happen, then the drag
* operation is handed over to the OS.
* !!! TODO: real docs
+ *
+ * @param data !!! TODO
+ * @param thumbBuilder !!! TODO
+ * @param myWindowOnly When {@code true}, indicates that the drag operation should be
+ * restricted to the calling application. In this case only the calling application
+ * will see any DragEvents related to this drag operation.
+ * @param myLocalState An arbitrary object that will be passed as part of every DragEvent
+ * delivered to the calling application during the course of the current drag operation.
+ * This object is private to the application that called startDrag(), and is not
+ * visible to other applications. It provides a lightweight way for the application to
+ * propagate information from the initiator to the recipient of a drag within its own
+ * application; for example, to help disambiguate between 'copy' and 'move' semantics.
+ * @return {@code true} if the drag operation was initiated successfully; {@code false} if
+ * an error prevented the drag from taking place.
*/
public final boolean startDrag(ClipData data, DragThumbnailBuilder thumbBuilder,
- boolean myWindowOnly) {
+ boolean myWindowOnly, Object myLocalState) {
if (ViewDebug.DEBUG_DRAG) {
Log.d(VIEW_LOG_TAG, "startDrag: data=" + data + " local=" + myWindowOnly);
}
@@ -10026,8 +10125,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
surface.unlockCanvasAndPost(canvas);
}
+ final ViewRoot root = getViewRoot();
+
+ // Cache the local state object for delivery with DragEvents
+ root.setLocalDragState(myLocalState);
+
// repurpose 'thumbSize' for the last touch point
- getViewRoot().getLastTouchPoint(thumbSize);
+ root.getLastTouchPoint(thumbSize);
okay = mAttachInfo.mSession.performDrag(mAttachInfo.mWindow, token,
(float) thumbSize.x, (float) thumbSize.y,
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index bb85894..6b41ce5 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -166,7 +166,7 @@ public class ViewConfiguration {
/**
* Max distance to overfling for edge effects
*/
- private static final int OVERFLING_DISTANCE = 4;
+ private static final int OVERFLING_DISTANCE = 12;
private final int mEdgeSlop;
private final int mFadingEdgeLength;
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index cb7d0e2..5f3184d 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -25,7 +25,9 @@ import android.content.pm.PackageManager;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.graphics.PointF;
@@ -57,6 +59,8 @@ import android.util.TypedValue;
import android.view.View.MeasureSpec;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.Interpolator;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import android.widget.Scroller;
@@ -79,7 +83,8 @@ import java.util.ArrayList;
* {@hide}
*/
@SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
-public final class ViewRoot extends Handler implements ViewParent, View.AttachInfo.Callbacks {
+public final class ViewRoot extends Handler implements ViewParent,
+ View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
private static final String TAG = "ViewRoot";
private static final boolean DBG = false;
private static final boolean SHOW_FPS = false;
@@ -213,12 +218,17 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
int mScrollY;
int mCurScrollY;
Scroller mScroller;
+ Bitmap mResizeBitmap;
+ long mResizeBitmapStartTime;
+ int mResizeBitmapDuration;
+ static final Interpolator mResizeInterpolator = new AccelerateDecelerateInterpolator();
final ViewConfiguration mViewConfiguration;
/* Drag/drop */
ClipDescription mDragDescription;
View mCurrentDragView;
+ Object mLocalDragState;
final PointF mDragPoint = new PointF();
final PointF mLastTouchPoint = new PointF();
@@ -576,6 +586,9 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
dirty.inset(-1, -1);
}
}
+ if (!mDirty.isEmpty()) {
+ mAttachInfo.mIgnoreDirtyState = true;
+ }
mDirty.union(dirty);
if (!mWillDrawSoon) {
scheduleTraversals();
@@ -626,6 +639,13 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
return mAppVisible ? mView.getVisibility() : View.GONE;
}
+ void disposeResizeBitmap() {
+ if (mResizeBitmap != null) {
+ mResizeBitmap.recycle();
+ mResizeBitmap = null;
+ }
+ }
+
private void performTraversals() {
// cache mView since it is used so much below...
final View host = mView;
@@ -734,6 +754,48 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
ensureTouchModeLocally(mAddedTouchMode);
} else {
if (!mAttachInfo.mContentInsets.equals(mPendingContentInsets)) {
+ if (mWidth > 0 && mHeight > 0 &&
+ mSurface != null && mSurface.isValid() &&
+ mAttachInfo.mHardwareRenderer != null &&
+ mAttachInfo.mHardwareRenderer.isEnabled() &&
+ lp != null && !PixelFormat.formatHasAlpha(lp.format)) {
+
+ disposeResizeBitmap();
+
+ boolean completed = false;
+ try {
+ mResizeBitmap = Bitmap.createBitmap(mWidth, mHeight,
+ Bitmap.Config.ARGB_8888);
+ mResizeBitmap.setHasAlpha(false);
+ Canvas canvas = new Canvas(mResizeBitmap);
+ int yoff;
+ final boolean scrolling = mScroller != null
+ && mScroller.computeScrollOffset();
+ if (scrolling) {
+ yoff = mScroller.getCurrY();
+ mScroller.abortAnimation();
+ } else {
+ yoff = mScrollY;
+ }
+ canvas.translate(0, -yoff);
+ if (mTranslator != null) {
+ mTranslator.translateCanvas(canvas);
+ }
+ canvas.setScreenDensity(mAttachInfo.mScalingRequired
+ ? DisplayMetrics.DENSITY_DEVICE : 0);
+ mView.draw(canvas);
+ mResizeBitmapStartTime = SystemClock.uptimeMillis();
+ mResizeBitmapDuration = mView.getResources().getInteger(
+ com.android.internal.R.integer.config_mediumAnimTime);
+ completed = true;
+ } catch (OutOfMemoryError e) {
+ Log.w(TAG, "Not enough memory for content change anim buffer", e);
+ } finally {
+ if (!completed) {
+ mResizeBitmap = null;
+ }
+ }
+ }
mAttachInfo.mContentInsets.set(mPendingContentInsets);
host.fitSystemWindows(mAttachInfo.mContentInsets);
insetsChanged = true;
@@ -787,7 +849,6 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
// 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.
@@ -972,6 +1033,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
if (mScroller != null) {
mScroller.abortAnimation();
}
+ disposeResizeBitmap();
}
} catch (RemoteException e) {
}
@@ -1310,6 +1372,22 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
return measureSpec;
}
+ int mHardwareYOffset;
+ int mResizeAlpha;
+ final Paint mResizePaint = new Paint();
+
+ public void onHardwarePreDraw(Canvas canvas) {
+ canvas.translate(0, -mHardwareYOffset);
+ }
+
+ public void onHardwarePostDraw(Canvas canvas) {
+ if (mResizeBitmap != null) {
+ canvas.translate(0, mHardwareYOffset);
+ mResizePaint.setAlpha(mResizeAlpha);
+ canvas.drawBitmap(mResizeBitmap, 0, 0, mResizePaint);
+ }
+ }
+
private void draw(boolean fullRedrawNeeded) {
Surface surface = mSurface;
if (surface == null || !surface.isValid()) {
@@ -1334,8 +1412,8 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
}
int yoff;
- final boolean scrolling = mScroller != null && mScroller.computeScrollOffset();
- if (scrolling) {
+ boolean animating = mScroller != null && mScroller.computeScrollOffset();
+ if (animating) {
yoff = mScroller.getCurrY();
} else {
yoff = mScrollY;
@@ -1347,10 +1425,29 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
float appScale = mAttachInfo.mApplicationScale;
boolean scalingRequired = mAttachInfo.mScalingRequired;
+ int resizeAlpha = 0;
+ if (mResizeBitmap != null) {
+ long deltaTime = SystemClock.uptimeMillis() - mResizeBitmapStartTime;
+ if (deltaTime < mResizeBitmapDuration) {
+ float amt = deltaTime/(float)mResizeBitmapDuration;
+ amt = mResizeInterpolator.getInterpolation(amt);
+ animating = true;
+ resizeAlpha = 255 - (int)(amt*255);
+ } else {
+ disposeResizeBitmap();
+ }
+ }
+
Rect dirty = mDirty;
if (mSurfaceHolder != null) {
// The app owns the surface, we won't draw.
dirty.setEmpty();
+ if (animating) {
+ if (mScroller != null) {
+ mScroller.abortAnimation();
+ }
+ disposeResizeBitmap();
+ }
return;
}
@@ -1363,10 +1460,12 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
if (!dirty.isEmpty() || mIsAnimating) {
mIsAnimating = false;
dirty.setEmpty();
- mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, yoff);
+ mHardwareYOffset = yoff;
+ mResizeAlpha = resizeAlpha;
+ mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this);
}
- if (scrolling) {
+ if (animating) {
mFullRedrawNeeded = true;
scheduleTraversals();
}
@@ -1486,7 +1585,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost");
}
- if (scrolling) {
+ if (animating) {
mFullRedrawNeeded = true;
scheduleTraversals();
}
@@ -1600,7 +1699,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
if (scrollY != mScrollY) {
if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Pan scroll changed: old="
+ mScrollY + " , new=" + scrollY);
- if (!immediate) {
+ if (!immediate && mResizeBitmap == null) {
if (mScroller == null) {
mScroller = new Scroller(mView.getContext());
}
@@ -2585,6 +2684,10 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
}
/* drag/drop */
+ void setLocalDragState(Object obj) {
+ mLocalDragState = obj;
+ }
+
private void handleDragEvent(DragEvent event) {
// From the root, only drag start/end/location are dispatched. entered/exited
// are determined and dispatched by the viewgroup hierarchy, who then report
@@ -2643,7 +2746,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
}
}
- // Report the drop result if necessary
+ // Report the drop result when we're done
if (what == DragEvent.ACTION_DROP) {
try {
Log.i(TAG, "Reporting drop result: " + result);
@@ -2652,6 +2755,12 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
Log.e(TAG, "Unable to report drop result");
}
}
+
+ // When the drag operation ends, release any local state object
+ // that may have been in use
+ if (what == DragEvent.ACTION_DRAG_ENDED) {
+ setLocalDragState(null);
+ }
}
}
event.recycle();
@@ -2968,6 +3077,7 @@ public final class ViewRoot extends Handler implements ViewParent, View.AttachIn
} else {
what = DISPATCH_DRAG_EVENT;
}
+ event.mLocalState = mLocalDragState; // only present when this app called startDrag()
Message msg = obtainMessage(what, event);
sendMessage(msg);
}
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/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index 0e9d9b7..1647540 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -621,6 +621,20 @@ public final class CookieManager {
}
/**
+ * Tell the cookie store that this is a good time to flush cookies to flash.
+ *
+ * This should be called when the app is paused. Note that this method only
+ * acts as a hint, and may not have any effect. Flushing is asynchronous.
+ *
+ * @hide pending API council approval.
+ */
+ public void flushCookieStore() {
+ if (useChromiumHttpStack()) {
+ nativeFlushCookieStore();
+ }
+ }
+
+ /**
* Package level api, called from CookieSyncManager
*
* Get a list of cookies which are updated since a given time.
@@ -1078,4 +1092,5 @@ public final class CookieManager {
private static native void nativeRemoveSessionCookie();
private static native void nativeSetAcceptCookie(boolean accept);
private static native void nativeSetCookie(String url, String value);
+ private static native void nativeFlushCookieStore();
}
diff --git a/core/java/android/webkit/FindActionModeCallback.java b/core/java/android/webkit/FindActionModeCallback.java
index 27043e0..641604e 100644
--- a/core/java/android/webkit/FindActionModeCallback.java
+++ b/core/java/android/webkit/FindActionModeCallback.java
@@ -43,7 +43,6 @@ class FindActionModeCallback implements ActionMode.Callback, TextWatcher,
private Resources mResources;
private boolean mMatchesFound;
private int mNumberOfMatches;
- private View mTitleBar;
private ActionMode mActionMode;
FindActionModeCallback(Context context) {
@@ -62,8 +61,6 @@ class FindActionModeCallback implements ActionMode.Callback, TextWatcher,
mResources = context.getResources();
}
- void setTitleBar(View v) { mTitleBar = v; }
-
void finish() {
mActionMode.finish();
}
@@ -174,7 +171,6 @@ class FindActionModeCallback implements ActionMode.Callback, TextWatcher,
@Override
public void onDestroyActionMode(ActionMode mode) {
- if (mTitleBar != null) mWebView.setEmbeddedTitleBar(mTitleBar);
mWebView.notifyFindDialogDismissed();
mInput.hideSoftInputFromWindow(mWebView.getWindowToken(), 0);
}
diff --git a/core/java/android/webkit/HTML5VideoViewProxy.java b/core/java/android/webkit/HTML5VideoViewProxy.java
index 6769563..85bff4f 100644
--- a/core/java/android/webkit/HTML5VideoViewProxy.java
+++ b/core/java/android/webkit/HTML5VideoViewProxy.java
@@ -138,6 +138,10 @@ class HTML5VideoViewProxy extends Handler
mCurrentProxy.dispatchOnEnded();
else
mCurrentProxy.dispatchOnPaused();
+
+ // Re enable plugin views.
+ mCurrentProxy.getWebView().getViewManager().showAll();
+
isVideoSelfEnded = false;
mCurrentProxy = null;
mLayout.removeView(mVideoView);
@@ -199,6 +203,9 @@ class HTML5VideoViewProxy extends Handler
mTimer = new Timer();
mVideoView.start();
client.onShowCustomView(mLayout, mCallback);
+ // Plugins like Flash will draw over the video so hide
+ // them while we're playing.
+ mCurrentProxy.getWebView().getViewManager().hideAll();
}
public static boolean isPlaying(HTML5VideoViewProxy proxy) {
@@ -599,6 +606,10 @@ class HTML5VideoViewProxy extends Handler
return new HTML5VideoViewProxy(webViewCore.getWebView(), nativePtr);
}
+ /* package */ WebView getWebView() {
+ return mWebView;
+ }
+
private native void nativeOnPrepared(int duration, int width, int height, int nativePointer);
private native void nativeOnEnded(int nativePointer);
private native void nativeOnPaused(int nativePointer);
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 911b0b0..be475ca 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -314,6 +314,17 @@ public class WebView extends AbsoluteLayout
implements ViewTreeObserver.OnGlobalFocusChangeListener,
ViewGroup.OnHierarchyChangeListener {
+ private class InnerGlobalLayoutListener implements ViewTreeObserver.OnGlobalLayoutListener {
+ public void onGlobalLayout() {
+ if (isShown()) {
+ setGLRectViewport();
+ }
+ }
+ }
+
+ // The listener to capture global layout change event.
+ private InnerGlobalLayoutListener mListener = null;
+
// if AUTO_REDRAW_HACK is true, then the CALL key will toggle redrawing
// the screen all-the-time. Good for profiling our drawing code
static private final boolean AUTO_REDRAW_HACK = false;
@@ -2183,14 +2194,13 @@ public class WebView extends AbsoluteLayout
// look at the cursor node, and not the focus node. Also, what is
// getFocusNodePath?
public void requestFocusNodeHref(Message hrefMsg) {
- if (hrefMsg == null || mNativeClass == 0) {
+ if (hrefMsg == null) {
return;
}
- if (nativeCursorIsAnchor()) {
- mWebViewCore.sendMessage(EventHub.REQUEST_CURSOR_HREF,
- nativeCursorFramePointer(), nativeCursorNodePointer(),
- hrefMsg);
- }
+ int contentX = viewToContentX((int) mLastTouchX + mScrollX);
+ int contentY = viewToContentY((int) mLastTouchY + mScrollY);
+ mWebViewCore.sendMessage(EventHub.REQUEST_CURSOR_HREF,
+ contentX, contentY, hrefMsg);
}
/**
@@ -2254,16 +2264,6 @@ public class WebView extends AbsoluteLayout
* @hide
*/
public void setEmbeddedTitleBar(View v) {
- 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);
- }
- }
if (mTitleBar == v) return;
if (mTitleBar != null) {
removeView(mTitleBar);
@@ -2898,11 +2898,6 @@ public class WebView extends AbsoluteLayout
setFindIsUp(true);
mFindCallback.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);
- mFindCallback.setTitleBar(titleBar);
startActionMode(mFindCallback);
if (text == null) {
text = mLastFind;
@@ -3742,6 +3737,8 @@ public class WebView extends AbsoluteLayout
if (mNativeClass != 0 && nativeWordSelection(x, y)) {
nativeSetExtendSelection();
mDrawSelectionPointer = false;
+ mSelectionStarted = true;
+ mTouchMode = TOUCH_DRAG_MODE;
return true;
}
selectionDone();
@@ -4626,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);
}
@@ -4709,6 +4700,11 @@ public class WebView extends AbsoluteLayout
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (hasWindowFocus()) setActive(true);
+ final ViewTreeObserver treeObserver = getViewTreeObserver();
+ if (treeObserver != null && mListener == null) {
+ mListener = new InnerGlobalLayoutListener();
+ treeObserver.addOnGlobalLayoutListener(mListener);
+ }
}
@Override
@@ -4716,6 +4712,13 @@ public class WebView extends AbsoluteLayout
clearHelpers();
mZoomManager.dismissZoomPicker();
if (hasWindowFocus()) setActive(false);
+
+ final ViewTreeObserver treeObserver = getViewTreeObserver();
+ if (treeObserver != null && mListener != null) {
+ treeObserver.removeGlobalOnLayoutListener(mListener);
+ mListener = null;
+ }
+
super.onDetachedFromWindow();
}
@@ -4856,13 +4859,19 @@ public class WebView extends AbsoluteLayout
}
void setGLRectViewport() {
- View window = getRootView();
- int[] location = new int[2];
- getLocationInWindow(location);
- mGLRectViewport = new Rect(location[0], window.getHeight()
- - (location[1] + getHeight()),
- location[0] + getWidth(),
- window.getHeight() - location[1]);
+ // Use the getGlobalVisibleRect() to get the intersection among the parents
+ Rect webViewRect = new Rect();
+ boolean visible = getGlobalVisibleRect(webViewRect);
+
+ // Then need to invert the Y axis, just for GL
+ View rootView = getRootView();
+ int rootViewHeight = rootView.getHeight();
+ int savedWebViewBottom = webViewRect.bottom;
+ webViewRect.bottom = rootViewHeight - webViewRect.top;
+ webViewRect.top = rootViewHeight - savedWebViewBottom;
+
+ // Store the viewport
+ mGLRectViewport = webViewRect;
}
/**
@@ -4998,10 +5007,10 @@ public class WebView extends AbsoluteLayout
startTouch(detector.getFocusX(), detector.getFocusY(), mLastTouchTime);
}
- private void startScrollingLayer(float gestureX, float gestureY) {
+ private void startScrollingLayer(float x, float y) {
if (mTouchMode != TOUCH_DRAG_LAYER_MODE) {
- int contentX = viewToContentX((int) gestureX + mScrollX);
- int contentY = viewToContentY((int) gestureY + mScrollY);
+ int contentX = viewToContentX((int) x + mScrollX);
+ int contentY = viewToContentY((int) y + mScrollY);
mScrollingLayer = nativeScrollableLayer(contentX, contentY);
if (mScrollingLayer != 0) {
mTouchMode = TOUCH_DRAG_LAYER_MODE;
@@ -5034,52 +5043,12 @@ public class WebView extends AbsoluteLayout
float y = ev.getY();
long eventTime = ev.getEventTime();
- final ScaleGestureDetector detector =
- mZoomManager.getMultiTouchGestureDetector();
- boolean isScrollGesture = false;
- // Set to the mid-point of a two-finger gesture used to detect if the
- // user has touched a layer.
- float gestureX = x;
- float gestureY = y;
- if (detector == null || !detector.isInProgress()) {
- // The gesture for scrolling a layer is two fingers close together.
- // FIXME: we may consider giving WebKit an option to handle
- // multi-touch events later.
- if (ev.getPointerCount() > 1) {
- float dx = ev.getX(1) - ev.getX(0);
- float dy = ev.getY(1) - ev.getY(0);
- float dist = (dx * dx + dy * dy) *
- DRAG_LAYER_INVERSE_DENSITY_SQUARED;
- // Use the approximate center to determine if the gesture is in
- // a layer.
- gestureX = ev.getX(0) + (dx * .5f);
- gestureY = ev.getY(0) + (dy * .5f);
- // Now use a consistent point for tracking movement.
- if (ev.getX(0) < ev.getX(1)) {
- x = ev.getX(0);
- y = ev.getY(0);
- } else {
- x = ev.getX(1);
- y = ev.getY(1);
- }
- action = ev.getActionMasked();
- if (dist < DRAG_LAYER_FINGER_DISTANCE) {
- isScrollGesture = true;
- } else if (mTouchMode == TOUCH_DRAG_LAYER_MODE) {
- // Fingers moved too far apart while dragging, the user
- // might be trying to zoom.
- mTouchMode = TOUCH_INIT_MODE;
- }
- }
- }
-
- // If the page disallows zoom, pass multi-touch events to webkit.
// mDeferMultitouch is a hack for layout tests, where it is used to
// force passing multi-touch events to webkit.
// FIXME: always pass multi-touch events to webkit and remove everything
// related to mDeferMultitouch.
if (ev.getPointerCount() > 1 &&
- (mDeferMultitouch || (!isScrollGesture && mZoomManager.isZoomScaleFixed()))) {
+ (mDeferMultitouch || mZoomManager.isZoomScaleFixed())) {
if (DebugFlags.WEB_VIEW) {
Log.v(LOGTAG, "passing " + ev.getPointerCount() + " points to webkit");
}
@@ -5087,8 +5056,11 @@ public class WebView extends AbsoluteLayout
return true;
}
+ final ScaleGestureDetector detector =
+ mZoomManager.getMultiTouchGestureDetector();
+
if (mZoomManager.supportsMultiTouchZoom() && ev.getPointerCount() > 1 &&
- mTouchMode != TOUCH_DRAG_LAYER_MODE && !isScrollGesture) {
+ mTouchMode != TOUCH_DRAG_LAYER_MODE) {
if (!detector.isInProgress() &&
ev.getActionMasked() != MotionEvent.ACTION_POINTER_DOWN) {
// Insert a fake pointer down event in order to start
@@ -5378,9 +5350,7 @@ public class WebView extends AbsoluteLayout
deltaX = 0;
deltaY = 0;
- if (isScrollGesture) {
- startScrollingLayer(gestureX, gestureY);
- }
+ startScrollingLayer(x, y);
startDrag();
}
@@ -5676,8 +5646,10 @@ public class WebView extends AbsoluteLayout
deltaY = viewToContentDimension(deltaY);
if (nativeScrollLayer(mScrollingLayer, deltaX, deltaY)) {
invalidate();
+ return;
}
- return;
+ // Switch to drag mode and fall through.
+ mTouchMode = TOUCH_DRAG_MODE;
}
final int oldX = mScrollX;
@@ -7715,6 +7687,10 @@ public class WebView extends AbsoluteLayout
mWebViewCore.sendMessage(EventHub.AUTOFILL_FORM, autoFillQueryId, /* unused */0);
}
+ /* package */ ViewManager getViewManager() {
+ return mViewManager;
+ }
+
private native int nativeCacheHitFramePointer();
private native Rect nativeCacheHitNodeBounds();
private native int nativeCacheHitNodePointer();
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index b7d20b4..99a0386 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -553,8 +553,8 @@ final class WebViewCore {
private native void nativeMoveMouseIfLatest(int moveGeneration,
int framePtr, int x, int y);
- private native String nativeRetrieveHref(int framePtr, int nodePtr);
- private native String nativeRetrieveAnchorText(int framePtr, int nodePtr);
+ private native String nativeRetrieveHref(int x, int y);
+ private native String nativeRetrieveAnchorText(int x, int y);
private native void nativeTouchUp(int touchGeneration,
int framePtr, int nodePtr, int x, int y);
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index 1e5489a..99b181f 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -20,6 +20,8 @@ import com.android.internal.R;
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
@@ -57,6 +59,23 @@ public class LinearLayout extends ViewGroup {
public static final int VERTICAL = 1;
/**
+ * Don't show any dividers.
+ */
+ public static final int SHOW_DIVIDER_NONE = 0;
+ /**
+ * Show a divider at the beginning of the group.
+ */
+ public static final int SHOW_DIVIDER_BEGINNING = 1;
+ /**
+ * Show dividers between each item in the group.
+ */
+ public static final int SHOW_DIVIDER_MIDDLE = 2;
+ /**
+ * Show a divider at the end of the group.
+ */
+ public static final int SHOW_DIVIDER_END = 4;
+
+ /**
* Whether the children of this layout are baseline aligned. Only applicable
* if {@link #mOrientation} is horizontal.
*/
@@ -119,6 +138,12 @@ public class LinearLayout extends ViewGroup {
private static final int INDEX_BOTTOM = 2;
private static final int INDEX_FILL = 3;
+ private Drawable mDivider;
+ private int mDividerWidth;
+ private int mDividerHeight;
+ private int mShowDividers;
+ private int mDividerPadding;
+
public LinearLayout(Context context) {
super(context);
}
@@ -155,10 +180,158 @@ public class LinearLayout extends ViewGroup {
mUseLargestChild = a.getBoolean(R.styleable.LinearLayout_measureWithLargestChild, false);
+ setDividerDrawable(a.getDrawable(R.styleable.LinearLayout_divider));
+ mShowDividers = a.getInt(R.styleable.LinearLayout_showDividers, SHOW_DIVIDER_NONE);
+ mDividerPadding = a.getDimensionPixelSize(R.styleable.LinearLayout_dividerPadding, 0);
+
a.recycle();
}
/**
+ * Set how dividers should be shown between items in this layout
+ *
+ * @param showDividers One or more of {@link #SHOW_DIVIDER_BEGINNING},
+ * {@link #SHOW_DIVIDER_MIDDLE}, or {@link #SHOW_DIVIDER_END},
+ * or {@link #SHOW_DIVIDER_NONE} to show no dividers.
+ */
+ public void setShowDividers(int showDividers) {
+ if (showDividers != mShowDividers) {
+ requestLayout();
+ }
+ mShowDividers = showDividers;
+ }
+
+ /**
+ * @return A flag set indicating how dividers should be shown around items.
+ * @see #setShowDividers(int)
+ */
+ public int getShowDividers() {
+ return mShowDividers;
+ }
+
+ /**
+ * Set a drawable to be used as a divider between items.
+ * @param divider Drawable that will divide each item.
+ * @see #setShowDividers(int)
+ */
+ public void setDividerDrawable(Drawable divider) {
+ if (divider == mDivider) {
+ return;
+ }
+ mDivider = divider;
+ if (divider != null) {
+ mDividerWidth = divider.getIntrinsicWidth();
+ mDividerHeight = divider.getIntrinsicHeight();
+ } else {
+ mDividerWidth = 0;
+ mDividerHeight = 0;
+ }
+ setWillNotDraw(divider == null);
+ requestLayout();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if (mDivider == null) {
+ return;
+ }
+
+ if (mOrientation == VERTICAL) {
+ drawDividersVertical(canvas);
+ } else {
+ drawDividersHorizontal(canvas);
+ }
+ }
+
+ void drawDividersVertical(Canvas canvas) {
+ final boolean showDividerBeginning =
+ (mShowDividers & SHOW_DIVIDER_BEGINNING) == SHOW_DIVIDER_BEGINNING;
+ final boolean showDividerMiddle =
+ (mShowDividers & SHOW_DIVIDER_MIDDLE) == SHOW_DIVIDER_MIDDLE;
+ final boolean showDividerEnd =
+ (mShowDividers & SHOW_DIVIDER_END) == SHOW_DIVIDER_END;
+
+ final int count = getVirtualChildCount();
+ int top = getPaddingTop();
+ boolean firstVisible = true;
+ for (int i = 0; i < count; i++) {
+ final View child = getVirtualChildAt(i);
+
+ if (child == null) {
+ top += measureNullChild(i);
+ } else if (child.getVisibility() != GONE) {
+ if (firstVisible) {
+ firstVisible = false;
+ if (showDividerBeginning) {
+ drawHorizontalDivider(canvas, top);
+ top += mDividerHeight;
+ }
+ } else if (showDividerMiddle) {
+ drawHorizontalDivider(canvas, top);
+ top += mDividerHeight;
+ }
+
+ LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ top += lp.topMargin + child.getHeight() + lp.bottomMargin;
+ }
+ }
+
+ if (showDividerEnd) {
+ drawHorizontalDivider(canvas, top);
+ }
+ }
+
+ void drawDividersHorizontal(Canvas canvas) {
+ final boolean showDividerBeginning =
+ (mShowDividers & SHOW_DIVIDER_BEGINNING) == SHOW_DIVIDER_BEGINNING;
+ final boolean showDividerMiddle =
+ (mShowDividers & SHOW_DIVIDER_MIDDLE) == SHOW_DIVIDER_MIDDLE;
+ final boolean showDividerEnd =
+ (mShowDividers & SHOW_DIVIDER_END) == SHOW_DIVIDER_END;
+
+ final int count = getVirtualChildCount();
+ int left = getPaddingLeft();
+ boolean firstVisible = true;
+ for (int i = 0; i < count; i++) {
+ final View child = getVirtualChildAt(i);
+
+ if (child == null) {
+ left += measureNullChild(i);
+ } else if (child.getVisibility() != GONE) {
+ if (firstVisible) {
+ firstVisible = false;
+ if (showDividerBeginning) {
+ drawVerticalDivider(canvas, left);
+ left += mDividerWidth;
+ }
+ } else if (showDividerMiddle) {
+ drawVerticalDivider(canvas, left);
+ left += mDividerWidth;
+ }
+
+ LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ left += lp.leftMargin + child.getWidth() + lp.rightMargin;
+ }
+ }
+
+ if (showDividerEnd) {
+ drawVerticalDivider(canvas, left);
+ }
+ }
+
+ void drawHorizontalDivider(Canvas canvas, int top) {
+ mDivider.setBounds(getPaddingLeft() + mDividerPadding, top,
+ getWidth() - getPaddingRight() - mDividerPadding, top + mDividerHeight);
+ mDivider.draw(canvas);
+ }
+
+ void drawVerticalDivider(Canvas canvas, int left) {
+ mDivider.setBounds(left, getPaddingTop() + mDividerPadding,
+ left + mDividerWidth, getHeight() - getPaddingBottom() - mDividerPadding);
+ mDivider.draw(canvas);
+ }
+
+ /**
* <p>Indicates whether widgets contained within this layout are aligned
* on their baseline or not.</p>
*
@@ -380,7 +553,14 @@ public class LinearLayout extends ViewGroup {
int largestChildHeight = Integer.MIN_VALUE;
+ // A divider at the end will change how much space views can consume.
+ final boolean showDividerBeginning =
+ (mShowDividers & SHOW_DIVIDER_BEGINNING) == SHOW_DIVIDER_BEGINNING;
+ final boolean showDividerMiddle =
+ (mShowDividers & SHOW_DIVIDER_MIDDLE) == SHOW_DIVIDER_MIDDLE;
+
// See how tall everyone is. Also remember max width.
+ boolean firstVisible = true;
for (int i = 0; i < count; ++i) {
final View child = getVirtualChildAt(i);
@@ -394,6 +574,15 @@ public class LinearLayout extends ViewGroup {
continue;
}
+ if (firstVisible) {
+ firstVisible = false;
+ if (showDividerBeginning) {
+ mTotalLength += mDividerHeight;
+ }
+ } else if (showDividerMiddle) {
+ mTotalLength += mDividerHeight;
+ }
+
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
totalWeight += lp.weight;
@@ -486,6 +675,10 @@ public class LinearLayout extends ViewGroup {
i += getChildrenSkipCount(child, i);
}
+ if (mTotalLength > 0 && (mShowDividers & SHOW_DIVIDER_END) == SHOW_DIVIDER_END) {
+ mTotalLength += mDividerHeight;
+ }
+
if (useLargestChild && heightMode == MeasureSpec.AT_MOST) {
mTotalLength = 0;
@@ -679,7 +872,14 @@ public class LinearLayout extends ViewGroup {
int largestChildWidth = Integer.MIN_VALUE;
+ // A divider at the end will change how much space views can consume.
+ final boolean showDividerBeginning =
+ (mShowDividers & SHOW_DIVIDER_BEGINNING) == SHOW_DIVIDER_BEGINNING;
+ final boolean showDividerMiddle =
+ (mShowDividers & SHOW_DIVIDER_MIDDLE) == SHOW_DIVIDER_MIDDLE;
+
// See how wide everyone is. Also remember max height.
+ boolean firstVisible = true;
for (int i = 0; i < count; ++i) {
final View child = getVirtualChildAt(i);
@@ -693,6 +893,15 @@ public class LinearLayout extends ViewGroup {
continue;
}
+ if (firstVisible) {
+ firstVisible = false;
+ if (showDividerBeginning) {
+ mTotalLength += mDividerWidth;
+ }
+ } else if (showDividerMiddle) {
+ mTotalLength += mDividerWidth;
+ }
+
final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
child.getLayoutParams();
@@ -803,6 +1012,10 @@ public class LinearLayout extends ViewGroup {
i += getChildrenSkipCount(child, i);
}
+ if (mTotalLength > 0 && (mShowDividers & SHOW_DIVIDER_END) == SHOW_DIVIDER_END) {
+ mTotalLength += mDividerWidth;
+ }
+
// Check mMaxAscent[INDEX_TOP] first because it maps to Gravity.TOP,
// the most common case
if (maxAscent[INDEX_TOP] != -1 ||
@@ -1127,7 +1340,14 @@ public class LinearLayout extends ViewGroup {
}
}
-
+
+ final boolean showDividerMiddle =
+ (mShowDividers & SHOW_DIVIDER_MIDDLE) == SHOW_DIVIDER_MIDDLE;
+
+ if ((mShowDividers & SHOW_DIVIDER_BEGINNING) == SHOW_DIVIDER_BEGINNING) {
+ childTop += mDividerHeight;
+ }
+
for (int i = 0; i < count; i++) {
final View child = getVirtualChildAt(i);
if (child == null) {
@@ -1162,12 +1382,15 @@ public class LinearLayout extends ViewGroup {
break;
}
-
childTop += lp.topMargin;
setChildFrame(child, childLeft, childTop + getLocationOffset(child),
childWidth, childHeight);
childTop += childHeight + lp.bottomMargin + getNextLocationOffset(child);
+ if (showDividerMiddle) {
+ childTop += mDividerHeight;
+ }
+
i += getChildrenSkipCount(child, i);
}
}
@@ -1216,7 +1439,14 @@ public class LinearLayout extends ViewGroup {
childLeft += ((mRight - mLeft) - mTotalLength) / 2;
break;
}
- }
+ }
+
+ final boolean showDividerMiddle =
+ (mShowDividers & SHOW_DIVIDER_MIDDLE) == SHOW_DIVIDER_MIDDLE;
+
+ if ((mShowDividers & SHOW_DIVIDER_BEGINNING) == SHOW_DIVIDER_BEGINNING) {
+ childLeft += mDividerWidth;
+ }
for (int i = 0; i < count; i++) {
final View child = getVirtualChildAt(i);
@@ -1282,6 +1512,10 @@ public class LinearLayout extends ViewGroup {
childLeft += childWidth + lp.rightMargin +
getNextLocationOffset(child);
+ if (showDividerMiddle) {
+ childLeft += mDividerWidth;
+ }
+
i += getChildrenSkipCount(child, i);
}
}
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index fd4f950..c0721bc 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -3196,7 +3196,8 @@ public class ListView extends AbsListView {
}
mDivider = divider;
mDividerIsOpaque = divider == null || divider.getOpacity() == PixelFormat.OPAQUE;
- requestLayoutIfNecessary();
+ requestLayout();
+ invalidate();
}
/**
@@ -3214,7 +3215,8 @@ public class ListView extends AbsListView {
*/
public void setDividerHeight(int height) {
mDividerHeight = height;
- requestLayoutIfNecessary();
+ requestLayout();
+ invalidate();
}
/**
diff --git a/core/java/android/widget/OverScroller.java b/core/java/android/widget/OverScroller.java
index cd81e31..b9e59d6 100644
--- a/core/java/android/widget/OverScroller.java
+++ b/core/java/android/widget/OverScroller.java
@@ -17,9 +17,12 @@
package android.widget;
import android.content.Context;
-import android.graphics.Interpolator;
+import android.hardware.SensorManager;
+import android.util.FloatMath;
+import android.util.Log;
import android.view.ViewConfiguration;
import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
/**
* This class encapsulates scrolling with the ability to overshoot the bounds
@@ -27,65 +30,51 @@ import android.view.animation.AnimationUtils;
* {@link android.widget.Scroller} in most cases.
*/
public class OverScroller {
- int mMode;
+ private int mMode;
- private final MagneticOverScroller mScrollerX;
- private final MagneticOverScroller mScrollerY;
+ private final SplineOverScroller mScrollerX;
+ private final SplineOverScroller mScrollerY;
- private float mDeceleration;
- private final float mPpi;
- private final boolean mFlywheel;
+ private final Interpolator mInterpolator;
- private static float DECELERATION_RATE = (float) (Math.log(0.75) / Math.log(0.9));
- private static float ALPHA = 800; // pixels / seconds
- private static float START_TENSION = 0.4f; // Tension at start: (0.4 * total T, 1.0 * Distance)
- private static float END_TENSION = 1.0f - START_TENSION;
- private static final int NB_SAMPLES = 100;
- private static final float[] SPLINE_POSITION = new float[NB_SAMPLES + 1];
- private static final float[] SPLINE_TIME = new float[NB_SAMPLES + 1];
+ private final boolean mFlywheel;
private static final int DEFAULT_DURATION = 250;
private static final int SCROLL_MODE = 0;
private static final int FLING_MODE = 1;
- static {
- float x_min = 0.0f;
- float y_min = 0.0f;
- for (int i = 0; i < NB_SAMPLES; i++) {
- final float alpha = (float) i / NB_SAMPLES;
- {
- float x_max = 1.0f;
- float x, tx, coef;
- while (true) {
- x = x_min + (x_max - x_min) / 2.0f;
- coef = 3.0f * x * (1.0f - x);
- tx = coef * ((1.0f - x) * START_TENSION + x * END_TENSION) + x * x * x;
- if (Math.abs(tx - alpha) < 1E-5) break;
- if (tx > alpha) x_max = x;
- else x_min = x;
- }
- SPLINE_POSITION[i] = coef + x * x * x;
- }
+ /**
+ * Creates an OverScroller with a viscous fluid scroll interpolator.
+ * @param context
+ */
+ public OverScroller(Context context) {
+ this(context, null);
+ }
- {
- float y_max = 1.0f;
- float y, dy, coef;
- while (true) {
- y = y_min + (y_max - y_min) / 2.0f;
- coef = 3.0f * y * (1.0f - y);
- dy = coef + y * y * y;
- if (Math.abs(dy - alpha) < 1E-5) break;
- if (dy > alpha) y_max = y;
- else y_min = y;
- }
- SPLINE_TIME[i] = coef * ((1.0f - y) * START_TENSION + y * END_TENSION) + y * y * y;
- }
- }
- SPLINE_POSITION[NB_SAMPLES] = SPLINE_TIME[NB_SAMPLES] = 1.0f;
+ /**
+ * Creates an OverScroller with default edge bounce coefficients and flywheel enabled.
+ * @param context The context of this application.
+ * @param interpolator The scroll interpolator. If null, a default (viscous) interpolator will
+ * be used.
+ */
+ public OverScroller(Context context, Interpolator interpolator) {
+ this(context, interpolator, SplineOverScroller.DEFAULT_BOUNCE_COEFFICIENT,
+ SplineOverScroller.DEFAULT_BOUNCE_COEFFICIENT);
}
- public OverScroller(Context context) {
- this(context, null, 0.f, 0.f, true);
+ /**
+ * Creates an OverScroller with flywheel enabled.
+ * @param context The context of this application.
+ * @param interpolator The scroll interpolator. If null, a default (viscous) interpolator will
+ * be used.
+ * @param bounceCoefficientX A value between 0 and 1 that will determine the proportion of the
+ * velocity which is preserved in the bounce when the horizontal edge is reached. A null value
+ * means no bounce.
+ * @param bounceCoefficientY Same as bounceCoefficientX but for the vertical direction.
+ */
+ public OverScroller(Context context, Interpolator interpolator,
+ float bounceCoefficientX, float bounceCoefficientY) {
+ this(context, interpolator, bounceCoefficientX, bounceCoefficientY, true);
}
/**
@@ -97,20 +86,21 @@ public class OverScroller {
* velocity which is preserved in the bounce when the horizontal edge is reached. A null value
* means no bounce.
* @param bounceCoefficientY Same as bounceCoefficientX but for the vertical direction.
+ * @param flywheel If true, successive fling motions will keep on increasing scroll speed.
*/
public OverScroller(Context context, Interpolator interpolator,
float bounceCoefficientX, float bounceCoefficientY, boolean flywheel) {
+ mInterpolator = interpolator;
mFlywheel = flywheel;
- mPpi = context.getResources().getDisplayMetrics().density * 160.0f;
- mDeceleration = computeDeceleration(ViewConfiguration.getScrollFriction());
- mScrollerX = new MagneticOverScroller();
- mScrollerY = new MagneticOverScroller();
+ mScrollerX = new SplineOverScroller();
+ mScrollerY = new SplineOverScroller();
+
+ SplineOverScroller.initFromContext(context);
mScrollerX.setBounceCoefficient(bounceCoefficientX);
mScrollerY.setBounceCoefficient(bounceCoefficientY);
}
-
/**
* The amount of friction applied to flings. The default value
* is {@link ViewConfiguration#getScrollFriction}.
@@ -119,14 +109,8 @@ public class OverScroller {
* friction.
*/
public final void setFriction(float friction) {
- mDeceleration = computeDeceleration(friction);
- }
-
- private float computeDeceleration(float friction) {
- return 9.81f // g (m/s^2)
- * 39.37f // inch/meter
- * mPpi // pixels per inch
- * friction;
+ mScrollerX.setFriction(friction);
+ mScrollerY.setFriction(friction);
}
/**
@@ -178,7 +162,7 @@ public class OverScroller {
public float getCurrVelocity() {
float squaredNorm = mScrollerX.mCurrVelocity * mScrollerX.mCurrVelocity;
squaredNorm += mScrollerY.mCurrVelocity * mScrollerY.mCurrVelocity;
- return (float) Math.sqrt(squaredNorm);
+ return FloatMath.sqrt(squaredNorm);
}
/**
@@ -307,7 +291,11 @@ public class OverScroller {
if (elapsedTime < duration) {
float q = (float) (elapsedTime) / duration;
- q = Scroller.viscousFluid(q);
+ if (mInterpolator == null) {
+ q = Scroller.viscousFluid(q);
+ } else {
+ q = mInterpolator.getInterpolation(q);
+ }
mScrollerX.updateScroll(q);
mScrollerY.updateScroll(q);
@@ -496,9 +484,9 @@ public class OverScroller {
*/
public boolean isOverScrolled() {
return ((!mScrollerX.mFinished &&
- mScrollerX.mState != MagneticOverScroller.TO_EDGE) ||
+ mScrollerX.mState != SplineOverScroller.TO_EDGE) ||
(!mScrollerY.mFinished &&
- mScrollerY.mState != MagneticOverScroller.TO_EDGE));
+ mScrollerY.mState != SplineOverScroller.TO_EDGE));
}
/**
@@ -536,60 +524,126 @@ public class OverScroller {
Math.signum(yvel) == Math.signum(dy);
}
- class MagneticOverScroller {
+ static class SplineOverScroller {
// Initial position
- int mStart;
+ private int mStart;
// Current position
- int mCurrentPosition;
+ private int mCurrentPosition;
// Final position
- int mFinal;
+ private int mFinal;
// Initial velocity
- int mVelocity;
+ private int mVelocity;
// Current velocity
- float mCurrVelocity;
+ private float mCurrVelocity;
// Constant current deceleration
- float mDeceleration;
+ private float mDeceleration;
// Animation starting time, in system milliseconds
- long mStartTime;
+ private long mStartTime;
// Animation duration, in milliseconds
- int mDuration;
+ private int mDuration;
// Duration to complete spline component of animation
- int mSplineDuration;
+ private int mSplineDuration;
// Distance to travel along spline animation
- int mSplineDistance;
+ private int mSplineDistance;
// Whether the animation is currently in progress
- boolean mFinished;
+ private boolean mFinished;
- private static final int TO_EDGE = 0;
- private static final int TO_BOUNDARY = 1;
- private static final int TO_BOUNCE = 2;
+ // The allowed overshot distance before boundary is reached.
+ private int mOver;
+ // Fling friction
+ private float mFlingFriction = ViewConfiguration.getScrollFriction();
+
+ // Proportion of velocity preserved at the end of a bounce animation.
+ private float mBounceCoefficient = DEFAULT_BOUNCE_COEFFICIENT;
+
+ // Current state of the animation.
private int mState = TO_EDGE;
- // The allowed overshot distance before boundary is reached.
- private int mOver;
+ // Constant gravity value, used in the deceleration phase.
+ private static final float GRAVITY = 2000.0f;
+
+ // A device specific coefficient adjusted to physical values.
+ private static float PHYSICAL_COEF;
+
+ private static float DECELERATION_RATE = (float) (Math.log(0.75) / Math.log(0.9));
+ private static final float INFLEXION = 0.3f; // Tension lines cross at (INFLEXION, 1)
+ private static final float START_TENSION = 0.7f;
+ private static final float END_TENSION = 0.8f;
+ private static final float P1 = START_TENSION * INFLEXION;
+ private static final float P2 = 1.0f - END_TENSION * (1.0f - INFLEXION);
+
+ private static final int NB_SAMPLES = 100;
+ private static final float[] SPLINE_POSITION = new float[NB_SAMPLES + 1];
+ private static final float[] SPLINE_TIME = new float[NB_SAMPLES + 1];
+
+ private static final int TO_EDGE = 0;
+ private static final int TO_BOUNDARY = 1;
+ private static final int TO_BOUNCE = 2;
// If the velocity is smaller than this value, no bounce is triggered
- // when the edge limits are reached (would result in a zero pixels
- // displacement anyway).
- private static final float MINIMUM_VELOCITY_FOR_BOUNCE = 140.0f; //Float.MAX_VALUE;//140.0f;
+ // when the edge limits are reached.
+ private static final float MINIMUM_VELOCITY_FOR_BOUNCE = Float.MAX_VALUE;//140.0f;
// Proportion of the velocity that is preserved when the edge is reached.
- private static final float DEFAULT_BOUNCE_COEFFICIENT = 0.36f;
+ private static final float DEFAULT_BOUNCE_COEFFICIENT = 0.16f;
- private float mBounceCoefficient = DEFAULT_BOUNCE_COEFFICIENT;
+ static {
+ float x_min = 0.0f;
+ float y_min = 0.0f;
+ for (int i = 0; i < NB_SAMPLES; i++) {
+ final float alpha = (float) i / NB_SAMPLES;
- MagneticOverScroller() {
+ float x_max = 1.0f;
+ float x, tx, coef;
+ while (true) {
+ x = x_min + (x_max - x_min) / 2.0f;
+ coef = 3.0f * x * (1.0f - x);
+ tx = coef * ((1.0f - x) * P1 + x * P2) + x * x * x;
+ if (Math.abs(tx - alpha) < 1E-5) break;
+ if (tx > alpha) x_max = x;
+ else x_min = x;
+ }
+ SPLINE_POSITION[i] = coef * ((1.0f - x) * START_TENSION + x) + x * x * x;
+
+ float y_max = 1.0f;
+ float y, dy;
+ while (true) {
+ y = y_min + (y_max - y_min) / 2.0f;
+ coef = 3.0f * y * (1.0f - y);
+ dy = coef * ((1.0f - y) * START_TENSION + y) + y * y * y;
+ if (Math.abs(dy - alpha) < 1E-5) break;
+ if (dy > alpha) y_max = y;
+ else y_min = y;
+ }
+ SPLINE_TIME[i] = coef * ((1.0f - y) * P1 + y * P2) + y * y * y;
+ }
+ SPLINE_POSITION[NB_SAMPLES] = SPLINE_TIME[NB_SAMPLES] = 1.0f;
+ }
+
+ static void initFromContext(Context context) {
+ final float ppi = context.getResources().getDisplayMetrics().density * 160.0f;
+ PHYSICAL_COEF = SensorManager.GRAVITY_EARTH // g (m/s^2)
+ * 39.37f // inch/meter
+ * ppi
+ * 0.84f; // look and feel tuning
+ }
+
+ void setFriction(float friction) {
+ mFlingFriction = friction;
+ }
+
+ SplineOverScroller() {
mFinished = true;
}
@@ -600,18 +654,18 @@ public class OverScroller {
/*
* Get a signed deceleration that will reduce the velocity.
*/
- float getDeceleration(int velocity) {
- return velocity > 0 ? -OverScroller.this.mDeceleration : OverScroller.this.mDeceleration;
+ static private float getDeceleration(int velocity) {
+ return velocity > 0 ? -GRAVITY : GRAVITY;
}
/*
* Modifies mDuration to the duration it takes to get from start to newFinal using the
* spline interpolation. The previous duration was needed to get to oldFinal.
*/
- void adjustDuration(int start, int oldFinal, int newFinal) {
+ private void adjustDuration(int start, int oldFinal, int newFinal) {
final int oldDistance = oldFinal - start;
final int newDistance = newFinal - start;
- final float x = (float) Math.abs((float) newDistance / oldDistance);
+ final float x = Math.abs((float) newDistance / oldDistance);
final int index = (int) (NB_SAMPLES * x);
if (index < NB_SAMPLES) {
final float x_inf = (float) index / NB_SAMPLES;
@@ -619,7 +673,6 @@ public class OverScroller {
final float t_inf = SPLINE_TIME[index];
final float t_sup = SPLINE_TIME[index + 1];
final float timeCoef = t_inf + (x - x_inf) / (x_sup - x_inf) * (t_sup - t_inf);
-
mDuration *= timeCoef;
}
}
@@ -696,7 +749,7 @@ public class OverScroller {
mCurrVelocity = mVelocity = velocity;
mDuration = mSplineDuration = 0;
mStartTime = AnimationUtils.currentAnimationTimeMillis();
- mStart = start;
+ mCurrentPosition = mStart = start;
if (start > max || start < min) {
startAfterEdge(start, min, max, velocity);
@@ -707,10 +760,8 @@ public class OverScroller {
double totalDistance = 0.0;
if (velocity != 0) {
- final double l = Math.log(START_TENSION * Math.abs(velocity) / ALPHA);
- // Duration are expressed in milliseconds
- mDuration = mSplineDuration = (int) (1000.0 * Math.exp(l / (DECELERATION_RATE - 1.0)));
- totalDistance = (ALPHA * Math.exp(DECELERATION_RATE / (DECELERATION_RATE - 1.0) * l));
+ mDuration = mSplineDuration = getSplineFlingDuration(velocity);
+ totalDistance = getSplineFlingDistance(velocity);
}
mSplineDistance = (int) (totalDistance * Math.signum(velocity));
@@ -728,6 +779,23 @@ public class OverScroller {
}
}
+ private double getSplineDeceleration(int velocity) {
+ return Math.log(INFLEXION * Math.abs(velocity) / (mFlingFriction * PHYSICAL_COEF));
+ }
+
+ private double getSplineFlingDistance(int velocity) {
+ final double l = getSplineDeceleration(velocity);
+ final double decelMinusOne = DECELERATION_RATE - 1.0;
+ return mFlingFriction * PHYSICAL_COEF * Math.exp(DECELERATION_RATE / decelMinusOne * l);
+ }
+
+ /* Returns the duration, expressed in milliseconds */
+ private int getSplineFlingDuration(int velocity) {
+ final double l = getSplineDeceleration(velocity);
+ final double decelMinusOne = DECELERATION_RATE - 1.0;
+ return (int) (1000.0 * Math.exp(l / decelMinusOne));
+ }
+
private void fitOnBounceCurve(int start, int end, int velocity) {
// Simulate a bounce that started from edge
final float durationToApex = - velocity / mDeceleration;
@@ -748,6 +816,7 @@ public class OverScroller {
private void startAfterEdge(int start, int min, int max, int velocity) {
if (start > min && start < max) {
+ Log.e("OverScroller", "startAfterEdge called from a valid position");
mFinished = true;
return;
}
@@ -759,9 +828,7 @@ public class OverScroller {
// Will result in a bounce or a to_boundary depending on velocity.
startBounceAfterEdge(start, edge, velocity);
} else {
- final double l = Math.log(START_TENSION * Math.abs(velocity) / ALPHA);
- final double totalDistance =
- (ALPHA * Math.exp(DECELERATION_RATE / (DECELERATION_RATE - 1.0) * l));
+ final double totalDistance = getSplineFlingDistance(velocity);
if (totalDistance > Math.abs(overDistance)) {
fling(start, velocity, positive ? min : start, positive ? start : max, mOver);
} else {
@@ -771,11 +838,13 @@ public class OverScroller {
}
void notifyEdgeReached(int start, int end, int over) {
- mOver = over;
- mStartTime = AnimationUtils.currentAnimationTimeMillis();
- // We were in fling/scroll mode before: current velocity is such that distance to edge
- // is increasing. Ensures that startAfterEdge will not start a new fling.
- startAfterEdge(start, end, end, (int) mCurrVelocity);
+ if (mState == TO_EDGE) {
+ mOver = over;
+ mStartTime = AnimationUtils.currentAnimationTimeMillis();
+ // We were in fling/scroll mode before: current velocity is such that distance to
+ // edge is increasing. Ensures that startAfterEdge will not start a new fling.
+ startAfterEdge(start, end, end, (int) mCurrVelocity);
+ }
}
private void onEdgeReached() {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index c49deaa..43434d3 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -220,8 +220,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private boolean mTemporaryDetach;
private boolean mDispatchTemporaryDetach;
- private boolean mEatTouchRelease = false;
- private boolean mScrolled = false;
+ private boolean mDiscardNextActionUp = false;
+ private boolean mIgnoreActionUpEvent = false;
private Editable.Factory mEditableFactory = Editable.Factory.getInstance();
private Spannable.Factory mSpannableFactory = Spannable.Factory.getInstance();
@@ -7002,31 +7002,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
- private void onTapUpEvent(int prevStart, int prevEnd) {
- final int start = getSelectionStart();
- final int end = getSelectionEnd();
-
- if (start == end) {
- 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
- stopSelectionActionMode();
-
- if (hasInsertionController()) {
- getInsertionController().show();
- }
- }
- }
- }
-
class CommitSelectionReceiver extends ResultReceiver {
private final int mPrevStart, mPrevEnd;
@@ -7071,7 +7046,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// Reset this state; it will be re-set if super.onTouchEvent
// causes focus to move to the view.
mTouchFocusSelected = false;
- mScrolled = false;
+ mIgnoreActionUpEvent = false;
}
final boolean superResult = super.onTouchEvent(event);
@@ -7081,8 +7056,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
* move the selection away from whatever the menu action was
* trying to affect.
*/
- if (mEatTouchRelease && action == MotionEvent.ACTION_UP) {
- mEatTouchRelease = false;
+ if (mDiscardNextActionUp && action == MotionEvent.ACTION_UP) {
+ mDiscardNextActionUp = false;
return superResult;
}
@@ -7111,7 +7086,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mSelectionModifierCursorController.updatePosition();
}
}
- if (action == MotionEvent.ACTION_UP && !mScrolled && isFocused()) {
+ if (action == MotionEvent.ACTION_UP && !mIgnoreActionUpEvent && isFocused()) {
InputMethodManager imm = (InputMethodManager)
getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
@@ -7122,13 +7097,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
if (!mTextIsSelectable) {
- // Selection in read-only text should not bring up the IME.
+ // Show the IME, except when selecting in read-only text.
handled |= imm.showSoftInput(this, 0, csr) && (csr != null);
}
- // Cannot be done by CommitSelectionReceiver, which might not always be called,
- // for instance when dealing with an ExtractEditText.
- onTapUpEvent(oldSelStart, oldSelEnd);
+ stopSelectionActionMode();
+ if (hasInsertionController()) {
+ getInsertionController().show();
+ }
}
}
@@ -7186,7 +7162,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
public void cancelLongPress() {
super.cancelLongPress();
- mScrolled = true;
+ mIgnoreActionUpEvent = true;
}
@Override
@@ -7455,6 +7431,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.
*
@@ -7464,77 +7451,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))) {
@@ -7835,7 +7796,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@Override
public boolean performLongClick() {
if (super.performLongClick()) {
- mEatTouchRelease = true;
+ mDiscardNextActionUp = true;
return true;
}
@@ -7843,9 +7804,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
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);
getInsertionController().show(0);
- mEatTouchRelease = true;
+ mDiscardNextActionUp = true;
return true;
}
@@ -7856,7 +7818,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
final int end = getSelectionEnd();
CharSequence selectedText = mTransformed.subSequence(start, end);
ClipData data = ClipData.newPlainText(null, null, selectedText);
- startDrag(data, getTextThumbnailBuilder(selectedText), false);
+ startDrag(data, getTextThumbnailBuilder(selectedText), false, null);
mDragSourcePositions = packRangeInLong(start, end);
stopSelectionActionMode();
} else {
@@ -7864,13 +7826,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
getSelectionController().show();
}
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- mEatTouchRelease = true;
+ mDiscardNextActionUp = true;
return true;
}
if (startSelectionActionMode()) {
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- mEatTouchRelease = true;
+ mDiscardNextActionUp = true;
return true;
}
@@ -8678,14 +8640,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();
}
@@ -8706,19 +8660,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mEndHandle.show();
hideInsertionPointCursorController();
- hideDelayed();
}
public void hide() {
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() {
@@ -8761,7 +8708,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
Selection.setSelection((Spannable) mText, selectionStart, selectionEnd);
updatePosition();
- hideDelayed();
}
public void updatePosition() {
@@ -8798,7 +8744,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// Double tap detection
long duration = SystemClock.uptimeMillis() - mPreviousTapUpTime;
- if (duration <= ViewConfiguration.getDoubleTapTimeout()) {
+ if (duration <= ViewConfiguration.getDoubleTapTimeout() &&
+ isPositionOnText(x, y)) {
final int deltaX = x - mPreviousTapPositionX;
final int deltaY = y - mPreviousTapPositionY;
final int distanceSquared = deltaX * deltaX + deltaY * deltaY;
@@ -8807,9 +8754,7 @@ 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();
+ mDiscardNextActionUp = true;
}
}
@@ -8979,66 +8924,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
TextView.this.requestFocus();
return true;
- case DragEvent.ACTION_DRAG_LOCATION: {
+ case DragEvent.ACTION_DRAG_LOCATION:
final int offset = getOffset((int) event.getX(), (int) event.getY());
Selection.setSelection((Spannable)mText, offset);
return true;
- }
-
- case DragEvent.ACTION_DROP: {
- StringBuilder content = new StringBuilder("");
- ClipData clipData = event.getClipData();
- final int itemCount = clipData.getItemCount();
- for (int i=0; i < itemCount; i++) {
- 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);
- }
- }
+ case DragEvent.ACTION_DROP:
+ onDrop(event);
return true;
- }
case DragEvent.ACTION_DRAG_ENDED:
mDragSourcePositions = -1;
@@ -9050,6 +8943,59 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
+ private void onDrop(DragEvent event) {
+ StringBuilder content = new StringBuilder("");
+ ClipData clipData = event.getClipData();
+ final int itemCount = clipData.getItemCount();
+ for (int i=0; i < itemCount; i++) {
+ 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;
+ }
+ }
+
+ 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 if this view supports insertion handles.
*/
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index 20402a3..447a062 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -70,6 +70,10 @@ public class ActionBarImpl extends ActionBar {
private ActionMode mActionMode;
+ private boolean mLastMenuVisibility;
+ private ArrayList<OnMenuVisibilityListener> mMenuVisibilityListeners =
+ new ArrayList<OnMenuVisibilityListener>();
+
private static final int CONTEXT_DISPLAY_NORMAL = 0;
private static final int CONTEXT_DISPLAY_SPLIT = 1;
@@ -120,6 +124,26 @@ public class ActionBarImpl extends ActionBar {
CONTEXT_DISPLAY_NORMAL : CONTEXT_DISPLAY_SPLIT;
}
+ public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
+ mMenuVisibilityListeners.add(listener);
+ }
+
+ public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
+ mMenuVisibilityListeners.remove(listener);
+ }
+
+ public void dispatchMenuVisibilityChanged(boolean isVisible) {
+ if (isVisible == mLastMenuVisibility) {
+ return;
+ }
+ mLastMenuVisibility = isVisible;
+
+ final int count = mMenuVisibilityListeners.size();
+ for (int i = 0; i < count; i++) {
+ mMenuVisibilityListeners.get(i).onMenuVisibilityChanged(isVisible);
+ }
+ }
+
@Override
public void setTitle(int resId) {
setTitle(mContext.getString(resId));
@@ -138,11 +162,11 @@ public class ActionBarImpl extends ActionBar {
mActionView.setCallback(null);
}
- public void setDropdownNavigationMode(SpinnerAdapter adapter, NavigationCallback callback) {
+ public void setDropdownNavigationMode(SpinnerAdapter adapter, OnNavigationListener callback) {
setDropdownNavigationMode(adapter, callback, -1);
}
- public void setDropdownNavigationMode(SpinnerAdapter adapter, NavigationCallback callback,
+ public void setDropdownNavigationMode(SpinnerAdapter adapter, OnNavigationListener callback,
int defaultSelectedPosition) {
cleanupTabs();
setDisplayOptions(0, DISPLAY_SHOW_CUSTOM | DISPLAY_SHOW_TITLE);
@@ -516,7 +540,7 @@ public class ActionBarImpl extends ActionBar {
public void onMenuModeChange(MenuBuilder menu) {
invalidate();
- mUpperContextView.showOverflowMenu();
+ mUpperContextView.openOverflowMenu();
}
}
@@ -627,7 +651,7 @@ public class ActionBarImpl extends ActionBar {
}
@Override
- public void setListNavigationCallbacks(SpinnerAdapter adapter, NavigationCallback callback) {
+ public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) {
mActionView.setDropdownAdapter(adapter);
mActionView.setCallback(callback);
}
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index b2810b1..e384320 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -118,6 +118,12 @@ public class AlertController {
private int mCheckedItem = -1;
+ private int mAlertDialogLayout;
+ private int mListLayout;
+ private int mMultiChoiceItemLayout;
+ private int mSingleChoiceItemLayout;
+ private int mListItemLayout;
+
private Handler mHandler;
View.OnClickListener mButtonHandler = new View.OnClickListener() {
@@ -178,6 +184,27 @@ public class AlertController {
mDialogInterface = di;
mWindow = window;
mHandler = new ButtonHandler(di);
+
+ TypedArray a = context.obtainStyledAttributes(null,
+ com.android.internal.R.styleable.AlertDialog,
+ com.android.internal.R.attr.alertDialogStyle, 0);
+
+ mAlertDialogLayout = a.getResourceId(com.android.internal.R.styleable.AlertDialog_layout,
+ com.android.internal.R.layout.alert_dialog);
+ mListLayout = a.getResourceId(
+ com.android.internal.R.styleable.AlertDialog_listLayout,
+ com.android.internal.R.layout.select_dialog);
+ mMultiChoiceItemLayout = a.getResourceId(
+ com.android.internal.R.styleable.AlertDialog_multiChoiceItemLayout,
+ com.android.internal.R.layout.select_dialog_multichoice);
+ mSingleChoiceItemLayout = a.getResourceId(
+ com.android.internal.R.styleable.AlertDialog_singleChoiceItemLayout,
+ com.android.internal.R.layout.select_dialog_singlechoice);
+ mListItemLayout = a.getResourceId(
+ com.android.internal.R.styleable.AlertDialog_listItemLayout,
+ com.android.internal.R.layout.select_dialog_item);
+
+ a.recycle();
}
static boolean canTextInput(View v) {
@@ -210,7 +237,7 @@ public class AlertController {
mWindow.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
}
- mWindow.setContentView(com.android.internal.R.layout.alert_dialog);
+ mWindow.setContentView(mAlertDialogLayout);
setupView();
}
@@ -810,13 +837,13 @@ public class AlertController {
private void createListView(final AlertController dialog) {
final RecycleListView listView = (RecycleListView)
- mInflater.inflate(R.layout.select_dialog, null);
+ mInflater.inflate(dialog.mListLayout, null);
ListAdapter adapter;
if (mIsMultiChoice) {
if (mCursor == null) {
adapter = new ArrayAdapter<CharSequence>(
- mContext, R.layout.select_dialog_multichoice, R.id.text1, mItems) {
+ mContext, dialog.mMultiChoiceItemLayout, R.id.text1, mItems) {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
@@ -850,7 +877,7 @@ public class AlertController {
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
- return mInflater.inflate(R.layout.select_dialog_multichoice,
+ return mInflater.inflate(dialog.mMultiChoiceItemLayout,
parent, false);
}
@@ -858,7 +885,7 @@ public class AlertController {
}
} else {
int layout = mIsSingleChoice
- ? R.layout.select_dialog_singlechoice : R.layout.select_dialog_item;
+ ? dialog.mSingleChoiceItemLayout : dialog.mListItemLayout;
if (mCursor == null) {
adapter = (mAdapter != null) ? mAdapter
: new ArrayAdapter<CharSequence>(mContext, layout, R.id.text1, mItems);
diff --git a/core/java/com/android/internal/os/SamplingProfilerIntegration.java b/core/java/com/android/internal/os/SamplingProfilerIntegration.java
index c930c57..bfef275 100644
--- a/core/java/com/android/internal/os/SamplingProfilerIntegration.java
+++ b/core/java/com/android/internal/os/SamplingProfilerIntegration.java
@@ -27,6 +27,7 @@ import java.io.PrintStream;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.ThreadFactory;
import android.content.pm.PackageInfo;
import android.util.Log;
@@ -43,27 +44,40 @@ public class SamplingProfilerIntegration {
private static final boolean enabled;
private static final Executor snapshotWriter;
- private static final int samplingProfilerHz;
-
- /** Whether or not we've created the snapshots dir. */
- private static boolean dirMade = false;
+ private static final int samplingProfilerMilliseconds;
+ private static final int samplingProfilerDepth;
/** Whether or not a snapshot is being persisted. */
private static final AtomicBoolean pending = new AtomicBoolean(false);
static {
- samplingProfilerHz = SystemProperties.getInt("persist.sys.profiler_hz", 0);
- // Disabling this for now, as it crashes when enabled server-side. So adding
- // a new property ("REALLY") for those wanting to test and fix it.
- boolean really = SystemProperties.getInt("persist.sys.profiler_hz_REALLY", 0) > 0;
- if (samplingProfilerHz > 0 && really) {
- snapshotWriter = Executors.newSingleThreadExecutor();
- enabled = true;
- Log.i(TAG, "Profiler is enabled. Sampling Profiler Hz: " + samplingProfilerHz);
+ samplingProfilerMilliseconds = SystemProperties.getInt("persist.sys.profiler_ms", 0);
+ samplingProfilerDepth = SystemProperties.getInt("persist.sys.profiler_depth", 4);
+ if (samplingProfilerMilliseconds > 0) {
+ File dir = new File(SNAPSHOT_DIR);
+ dir.mkdirs();
+ // the directory needs to be writable to anybody to allow file writing
+ dir.setWritable(true, false);
+ // the directory needs to be executable to anybody to allow file creation
+ dir.setExecutable(true, false);
+ if (dir.isDirectory()) {
+ snapshotWriter = Executors.newSingleThreadExecutor(new ThreadFactory() {
+ public Thread newThread(Runnable r) {
+ return new Thread(r, TAG);
+ }
+ });
+ enabled = true;
+ Log.i(TAG, "Profiling enabled. Sampling interval ms: "
+ + samplingProfilerMilliseconds);
+ } else {
+ snapshotWriter = null;
+ enabled = true;
+ Log.w(TAG, "Profiling setup failed. Could not create " + SNAPSHOT_DIR);
+ }
} else {
snapshotWriter = null;
enabled = false;
- Log.i(TAG, "Profiler is disabled.");
+ Log.i(TAG, "Profiling disabled.");
}
}
@@ -85,8 +99,8 @@ public class SamplingProfilerIntegration {
}
ThreadGroup group = Thread.currentThread().getThreadGroup();
SamplingProfiler.ThreadSet threadSet = SamplingProfiler.newThreadGroupTheadSet(group);
- INSTANCE = new SamplingProfiler(4, threadSet); // TODO parameter for depth
- INSTANCE.start(1000/samplingProfilerHz);
+ INSTANCE = new SamplingProfiler(samplingProfilerDepth, threadSet);
+ INSTANCE.start(samplingProfilerMilliseconds);
}
/**
@@ -106,25 +120,8 @@ public class SamplingProfilerIntegration {
if (pending.compareAndSet(false, true)) {
snapshotWriter.execute(new Runnable() {
public void run() {
- if (!dirMade) {
- File dir = new File(SNAPSHOT_DIR);
- dir.mkdirs();
- // the directory needs to be writable to anybody
- dir.setWritable(true, false);
- // the directory needs to be executable to anybody
- // don't know why yet, but mode 723 would work, while
- // mode 722 throws FileNotFoundExecption at line 151
- dir.setExecutable(true, false);
- if (new File(SNAPSHOT_DIR).isDirectory()) {
- dirMade = true;
- } else {
- Log.w(TAG, "Creation of " + SNAPSHOT_DIR + " failed.");
- pending.set(false);
- return;
- }
- }
try {
- writeSnapshot(SNAPSHOT_DIR, processName, packageInfo);
+ writeSnapshotFile(processName, packageInfo);
} finally {
pending.set(false);
}
@@ -140,7 +137,7 @@ public class SamplingProfilerIntegration {
if (!enabled) {
return;
}
- writeSnapshot("zygote", null);
+ writeSnapshotFile("zygote", null);
INSTANCE.shutdown();
INSTANCE = null;
}
@@ -148,7 +145,7 @@ public class SamplingProfilerIntegration {
/**
* pass in PackageInfo to retrieve various values for snapshot header
*/
- private static void writeSnapshot(String dir, String processName, PackageInfo packageInfo) {
+ private static void writeSnapshotFile(String processName, PackageInfo packageInfo) {
if (!enabled) {
return;
}
@@ -161,7 +158,7 @@ public class SamplingProfilerIntegration {
*/
long start = System.currentTimeMillis();
String name = processName.replaceAll(":", ".");
- String path = dir + "/" + name + "-" +System.currentTimeMillis() + ".snapshot";
+ String path = SNAPSHOT_DIR + "/" + name + "-" +System.currentTimeMillis() + ".snapshot";
PrintStream out = null;
try {
out = new PrintStream(new BufferedOutputStream(new FileOutputStream(path)));
diff --git a/core/java/com/android/internal/view/StandaloneActionMode.java b/core/java/com/android/internal/view/StandaloneActionMode.java
index b54daba..2d067da 100644
--- a/core/java/com/android/internal/view/StandaloneActionMode.java
+++ b/core/java/com/android/internal/view/StandaloneActionMode.java
@@ -135,6 +135,6 @@ public class StandaloneActionMode extends ActionMode implements MenuBuilder.Call
public void onMenuModeChange(MenuBuilder menu) {
invalidate();
- mContextView.showOverflowMenu();
+ mContextView.openOverflowMenu();
}
}
diff --git a/core/java/com/android/internal/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java
index 621defe..84067d0 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuView.java
@@ -59,6 +59,22 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
}
};
+ private class OpenOverflowRunnable implements Runnable {
+ private MenuPopupHelper mPopup;
+
+ public OpenOverflowRunnable(MenuPopupHelper popup) {
+ mPopup = popup;
+ }
+
+ public void run() {
+ mOverflowPopup = mPopup;
+ mPopup.show();
+ mPostedOpenRunnable = null;
+ }
+ }
+
+ private OpenOverflowRunnable mPostedOpenRunnable;
+
public ActionMenuView(Context context) {
this(context, null);
}
@@ -100,6 +116,7 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
@Override
public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
final int screen = newConfig.screenLayout;
mReserveOverflow = (screen & Configuration.SCREENLAYOUT_SIZE_MASK) ==
Configuration.SCREENLAYOUT_SIZE_XLARGE;
@@ -115,6 +132,14 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
}
}
+ @Override
+ public void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ if (mOverflowPopup != null && mOverflowPopup.isShowing()) {
+ mOverflowPopup.dismiss();
+ }
+ }
+
private int getMaxActionButtons() {
return getResources().getInteger(com.android.internal.R.integer.max_action_buttons);
}
@@ -193,30 +218,34 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
}
public boolean showOverflowMenu() {
- if (mOverflowButton != null) {
- final MenuPopupHelper popup =
- new MenuPopupHelper(getContext(), mMenu, mOverflowButton, true);
- // Post this for later; we might still need a layout for the anchor to be right.
- post(new Runnable() {
- public void run() {
- popup.show();
- }
- });
- mOverflowPopup = popup;
+ if (mOverflowButton != null && !isOverflowMenuShowing()) {
+ mMenu.getCallback().onMenuModeChange(mMenu);
return true;
}
return false;
}
+ public void openOverflowMenu() {
+ OverflowPopup popup = new OverflowPopup(getContext(), mMenu, mOverflowButton, true);
+ mPostedOpenRunnable = new OpenOverflowRunnable(popup);
+ // Post this for later; we might still need a layout for the anchor to be right.
+ post(mPostedOpenRunnable);
+ }
+
public boolean isOverflowMenuShowing() {
- MenuPopupHelper popup = mOverflowPopup;
- if (popup != null) {
- return popup.isShowing();
- }
- return false;
+ return mOverflowPopup != null && mOverflowPopup.isShowing();
+ }
+
+ public boolean isOverflowMenuOpen() {
+ return mOverflowPopup != null;
}
public boolean hideOverflowMenu() {
+ if (mPostedOpenRunnable != null) {
+ removeCallbacks(mPostedOpenRunnable);
+ return true;
+ }
+
MenuPopupHelper popup = mOverflowPopup;
if (popup != null) {
popup.dismiss();
@@ -274,9 +303,22 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo
return true;
}
- // Change to overflow mode
- mMenu.getCallback().onMenuModeChange(mMenu);
+ showOverflowMenu();
return true;
}
}
+
+ private class OverflowPopup extends MenuPopupHelper {
+ public OverflowPopup(Context context, MenuBuilder menu, View anchorView,
+ boolean overflowOnly) {
+ super(context, menu, anchorView, overflowOnly);
+ }
+
+ @Override
+ public void onDismiss() {
+ super.onDismiss();
+ mMenu.getCallback().onCloseMenu(mMenu, true);
+ mOverflowPopup = null;
+ }
+ }
}
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index 1406e4e..2cb78a5 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -35,7 +35,7 @@ import java.lang.ref.WeakReference;
* @hide
*/
public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.OnKeyListener,
- ViewTreeObserver.OnGlobalLayoutListener {
+ ViewTreeObserver.OnGlobalLayoutListener, PopupWindow.OnDismissListener {
private static final String TAG = "MenuPopupHelper";
private Context mContext;
@@ -46,12 +46,6 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On
private boolean mOverflowOnly;
private ViewTreeObserver mTreeObserver;
- private PopupWindow.OnDismissListener mDismissListener = new PopupWindow.OnDismissListener() {
- public void onDismiss() {
- mPopup = null;
- }
- };
-
public MenuPopupHelper(Context context, MenuBuilder menu) {
this(context, menu, null, false);
}
@@ -77,7 +71,7 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On
public void show() {
mPopup = new ListPopupWindow(mContext, null, com.android.internal.R.attr.popupMenuStyle);
mPopup.setOnItemClickListener(this);
- mPopup.setOnDismissListener(mDismissListener);
+ mPopup.setOnDismissListener(this);
final MenuAdapter adapter = mOverflowOnly ?
mMenu.getOverflowMenuAdapter(MenuBuilder.TYPE_POPUP) :
@@ -110,8 +104,12 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On
if (isShowing()) {
mPopup.dismiss();
}
+ }
+
+ public void onDismiss() {
+ mPopup = null;
if (mTreeObserver != null) {
- mTreeObserver.removeGlobalOnLayoutListener(this);
+ mTreeObserver.removeGlobalOnLayoutListener(MenuPopupHelper.this);
mTreeObserver = null;
}
}
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index e93c414..cbf12bf 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -180,6 +180,12 @@ public class ActionBarContextView extends ViewGroup {
return false;
}
+ public void openOverflowMenu() {
+ if (mMenuView != null) {
+ mMenuView.openOverflowMenu();
+ }
+ }
+
public boolean hideOverflowMenu() {
if (mMenuView != null) {
return mMenuView.hideOverflowMenu();
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index f931217..07a65fc 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -22,7 +22,7 @@ import com.android.internal.view.menu.ActionMenuView;
import com.android.internal.view.menu.MenuBuilder;
import android.app.ActionBar;
-import android.app.ActionBar.NavigationCallback;
+import android.app.ActionBar.OnNavigationListener;
import android.app.Activity;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -114,7 +114,7 @@ public class ActionBarView extends ViewGroup {
private ActionMenuItem mLogoNavItem;
private SpinnerAdapter mSpinnerAdapter;
- private NavigationCallback mCallback;
+ private OnNavigationListener mCallback;
private final AdapterView.OnItemSelectedListener mNavItemSelectedListener =
new AdapterView.OnItemSelectedListener() {
@@ -243,7 +243,7 @@ public class ActionBarView extends ViewGroup {
return null;
}
- public void setCallback(NavigationCallback callback) {
+ public void setCallback(OnNavigationListener callback) {
mCallback = callback;
}
@@ -269,6 +269,12 @@ public class ActionBarView extends ViewGroup {
return false;
}
+ public void openOverflowMenu() {
+ if (mMenuView != null) {
+ mMenuView.openOverflowMenu();
+ }
+ }
+
public void postShowOverflowMenu() {
post(new Runnable() {
public void run() {
@@ -291,6 +297,13 @@ public class ActionBarView extends ViewGroup {
return false;
}
+ public boolean isOverflowMenuOpen() {
+ if (mMenuView != null) {
+ return mMenuView.isOverflowMenuOpen();
+ }
+ return false;
+ }
+
public boolean isOverflowReserved() {
return mMenuView != null && mMenuView.isOverflowReserved();
}
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_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/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index ddc63dd..a2666e2 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1013,7 +1013,7 @@
<permission android:name="android.permission.SHUTDOWN"
android:label="@string/permlab_shutdown"
android:description="@string/permdesc_shutdown"
- android:protectionLevel="signature" />
+ android:protectionLevel="signatureOrSystem" />
<!-- Allows an application to tell the activity manager to temporarily
stop application switches, putting it into a special mode that
diff --git a/core/res/res/drawable-hdpi/textfield_activated_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_activated_holo_dark.9.png
new file mode 100644
index 0000000..8bb4048
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_activated_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_activated_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_activated_holo_light.9.png
new file mode 100644
index 0000000..fdd3ee7
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_activated_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_default_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_default_holo_dark.9.png
index 87d9c21..ab6abdc 100644
--- a/core/res/res/drawable-hdpi/textfield_default_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/textfield_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_default_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_default_holo_light.9.png
index 720ee78..dbdfc79 100644
--- a/core/res/res/drawable-hdpi/textfield_default_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/textfield_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_disabled_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_disabled_focused_holo_dark.9.png
index 4275da0..4eba040 100644
--- a/core/res/res/drawable-hdpi/textfield_disabled_focused_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/textfield_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_disabled_focused_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_disabled_focused_holo_light.9.png
index 3ec9c1f..b186730 100644
--- a/core/res/res/drawable-hdpi/textfield_disabled_focused_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/textfield_disabled_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_disabled_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_disabled_holo_dark.9.png
index 227bde2..06190a1 100644
--- a/core/res/res/drawable-hdpi/textfield_disabled_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/textfield_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_disabled_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_disabled_holo_light.9.png
index 6ddfab0..8c16566 100644
--- a/core/res/res/drawable-hdpi/textfield_disabled_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/textfield_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_focused_holo_dark.9.png
new file mode 100644
index 0000000..0ce5d13
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_focused_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_focused_holo_light.9.png
new file mode 100644
index 0000000..945516e
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_longpress_holo.9.png b/core/res/res/drawable-hdpi/textfield_longpress_holo.9.png
new file mode 100644
index 0000000..2993b44
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_longpress_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_multiline_activated_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_multiline_activated_holo_dark.9.png
new file mode 100644
index 0000000..33e6dc8
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_multiline_activated_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_multiline_activated_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_multiline_activated_holo_light.9.png
new file mode 100644
index 0000000..eb0d90f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_multiline_activated_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_multiline_default_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_multiline_default_holo_dark.9.png
index 09ca253..74c02c2 100644
--- a/core/res/res/drawable-hdpi/textfield_multiline_default_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/textfield_multiline_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_multiline_default_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_multiline_default_holo_light.9.png
index 0a7d3a1..345f4f5 100644
--- a/core/res/res/drawable-hdpi/textfield_multiline_default_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/textfield_multiline_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_multiline_disabled_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_multiline_disabled_focused_holo_dark.9.png
index 54a1519..40e5db3 100644
--- a/core/res/res/drawable-hdpi/textfield_multiline_disabled_focused_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/textfield_multiline_disabled_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_multiline_disabled_focused_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_multiline_disabled_focused_holo_light.9.png
index 06ca0d4..0cbf6d2 100644
--- a/core/res/res/drawable-hdpi/textfield_multiline_disabled_focused_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/textfield_multiline_disabled_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_multiline_disabled_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_multiline_disabled_holo_dark.9.png
index 9015299..bc56916 100644
--- a/core/res/res/drawable-hdpi/textfield_multiline_disabled_holo_dark.9.png
+++ b/core/res/res/drawable-hdpi/textfield_multiline_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_multiline_disabled_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_multiline_disabled_holo_light.9.png
index b355cb3..84adf68 100644
--- a/core/res/res/drawable-hdpi/textfield_multiline_disabled_holo_light.9.png
+++ b/core/res/res/drawable-hdpi/textfield_multiline_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_multiline_focused_holo_dark.9.png b/core/res/res/drawable-hdpi/textfield_multiline_focused_holo_dark.9.png
new file mode 100644
index 0000000..4a98e57
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_multiline_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_multiline_focused_holo_light.9.png b/core/res/res/drawable-hdpi/textfield_multiline_focused_holo_light.9.png
new file mode 100644
index 0000000..5cf6bf3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_multiline_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_pressed_holo.9.png b/core/res/res/drawable-hdpi/textfield_pressed_holo.9.png
new file mode 100644
index 0000000..4aad237
--- /dev/null
+++ b/core/res/res/drawable-hdpi/textfield_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_activated_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_activated_holo_dark.9.png
new file mode 100644
index 0000000..8bb4048
--- /dev/null
+++ b/core/res/res/drawable-mdpi/textfield_activated_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_activated_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_activated_holo_light.9.png
new file mode 100644
index 0000000..fdd3ee7
--- /dev/null
+++ b/core/res/res/drawable-mdpi/textfield_activated_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_default_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_default_holo_dark.9.png
index c98c951..ab6abdc 100644
--- a/core/res/res/drawable-mdpi/textfield_default_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/textfield_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_default_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_default_holo_light.9.png
index 7691f81..dbdfc79 100644
--- a/core/res/res/drawable-mdpi/textfield_default_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/textfield_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_disabled_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_disabled_holo_dark.9.png
index fab86ac..06190a1 100644
--- a/core/res/res/drawable-mdpi/textfield_disabled_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/textfield_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_disabled_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_disabled_holo_light.9.png
index 876eb794..8c16566 100644
--- a/core/res/res/drawable-mdpi/textfield_disabled_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/textfield_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_focused_holo_dark.9.png
new file mode 100644
index 0000000..0ce5d13
--- /dev/null
+++ b/core/res/res/drawable-mdpi/textfield_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_focused_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_focused_holo_light.9.png
new file mode 100644
index 0000000..945516e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/textfield_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_longpress_holo.9.png b/core/res/res/drawable-mdpi/textfield_longpress_holo.9.png
new file mode 100644
index 0000000..2993b44
--- /dev/null
+++ b/core/res/res/drawable-mdpi/textfield_longpress_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_multiline_activated_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_multiline_activated_holo_dark.9.png
new file mode 100644
index 0000000..33e6dc8
--- /dev/null
+++ b/core/res/res/drawable-mdpi/textfield_multiline_activated_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_multiline_activated_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_multiline_activated_holo_light.9.png
new file mode 100644
index 0000000..eb0d90f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/textfield_multiline_activated_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_multiline_active_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_multiline_active_holo_dark.9.png
index 2646899..44a5d82 100644
--- a/core/res/res/drawable-mdpi/textfield_multiline_active_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/textfield_multiline_active_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_multiline_active_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_multiline_active_holo_light.9.png
index 374d457..6613683 100644
--- a/core/res/res/drawable-mdpi/textfield_multiline_active_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/textfield_multiline_active_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_multiline_default_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_multiline_default_holo_dark.9.png
index 65c87ba..74c02c2 100644
--- a/core/res/res/drawable-mdpi/textfield_multiline_default_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/textfield_multiline_default_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_multiline_default_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_multiline_default_holo_light.9.png
index 724b3fd..345f4f5 100644
--- a/core/res/res/drawable-mdpi/textfield_multiline_default_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/textfield_multiline_default_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_multiline_disabled_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_multiline_disabled_holo_dark.9.png
index 2cc7f62..bc56916 100644
--- a/core/res/res/drawable-mdpi/textfield_multiline_disabled_holo_dark.9.png
+++ b/core/res/res/drawable-mdpi/textfield_multiline_disabled_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_multiline_disabled_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_multiline_disabled_holo_light.9.png
index a2d9d8a..84adf68 100644
--- a/core/res/res/drawable-mdpi/textfield_multiline_disabled_holo_light.9.png
+++ b/core/res/res/drawable-mdpi/textfield_multiline_disabled_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_multiline_focused_holo_dark.9.png b/core/res/res/drawable-mdpi/textfield_multiline_focused_holo_dark.9.png
new file mode 100644
index 0000000..4a98e57
--- /dev/null
+++ b/core/res/res/drawable-mdpi/textfield_multiline_focused_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_multiline_focused_holo_light.9.png b/core/res/res/drawable-mdpi/textfield_multiline_focused_holo_light.9.png
new file mode 100644
index 0000000..5cf6bf3
--- /dev/null
+++ b/core/res/res/drawable-mdpi/textfield_multiline_focused_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_pressed_holo.9.png b/core/res/res/drawable-mdpi/textfield_pressed_holo.9.png
new file mode 100644
index 0000000..4aad237
--- /dev/null
+++ b/core/res/res/drawable-mdpi/textfield_pressed_holo.9.png
Binary files differ
diff --git a/core/res/res/drawable/edit_text_holo_dark.xml b/core/res/res/drawable/edit_text_holo_dark.xml
index 63ccd1d..29a5150 100644
--- a/core/res/res/drawable/edit_text_holo_dark.xml
+++ b/core/res/res/drawable/edit_text_holo_dark.xml
@@ -17,7 +17,8 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_window_focused="false" android:state_enabled="true" android:drawable="@drawable/textfield_default_holo_dark" />
<item android:state_window_focused="false" android:state_enabled="false" android:drawable="@drawable/textfield_disabled_holo_dark" />
- <item android:state_enabled="true" android:state_focused="true" android:drawable="@drawable/textfield_active_holo_dark" />
+ <item android:state_enabled="true" android:state_focused="true" android:drawable="@drawable/textfield_activated_holo_dark" />
+ <item android:state_enabled="true" android:state_activated="true" android:drawable="@drawable/textfield_focused_holo_dark" />
<item android:state_enabled="true" android:drawable="@drawable/textfield_default_holo_dark" />
<item android:state_focused="true" android:drawable="@drawable/textfield_disabled_focused_holo_dark" />
<item android:drawable="@drawable/textfield_disabled_holo_dark" />
diff --git a/core/res/res/drawable/edit_text_holo_light.xml b/core/res/res/drawable/edit_text_holo_light.xml
index 324acda..5426916 100644
--- a/core/res/res/drawable/edit_text_holo_light.xml
+++ b/core/res/res/drawable/edit_text_holo_light.xml
@@ -17,7 +17,8 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_window_focused="false" android:state_enabled="true" android:drawable="@drawable/textfield_default_holo_light" />
<item android:state_window_focused="false" android:state_enabled="false" android:drawable="@drawable/textfield_disabled_holo_light" />
- <item android:state_enabled="true" android:state_focused="true" android:drawable="@drawable/textfield_active_holo_light" />
+ <item android:state_enabled="true" android:state_focused="true" android:drawable="@drawable/textfield_activated_holo_light" />
+ <iten android:state_enabled="true" android:state_activated="true" android:drawable="@drawable/textfield_focused_holo_light" />
<item android:state_enabled="true" android:drawable="@drawable/textfield_default_holo_light" />
<item android:state_focused="true" android:drawable="@drawable/textfield_disabled_focused_holo_light" />
<item android:drawable="@drawable/textfield_disabled_holo_light" />
diff --git a/core/res/res/drawable/edit_text_multiline_holo_dark.xml b/core/res/res/drawable/edit_text_multiline_holo_dark.xml
index 67d2748..d20ea19 100644
--- a/core/res/res/drawable/edit_text_multiline_holo_dark.xml
+++ b/core/res/res/drawable/edit_text_multiline_holo_dark.xml
@@ -17,7 +17,8 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_window_focused="false" android:state_enabled="true" android:drawable="@drawable/textfield_multiline_default_holo_dark" />
<item android:state_window_focused="false" android:state_enabled="false" android:drawable="@drawable/textfield_multiline_disabled_holo_dark" />
- <item android:state_enabled="true" android:state_focused="true" android:drawable="@drawable/textfield_multiline_active_holo_dark" />
+ <item android:state_enabled="true" android:state_focused="true" android:drawable="@drawable/textfield_multiline_activated_holo_dark" />
+ <item android:state_enabled="true" android:state_activated="true" android:drawable="@drawable/textfield_multiline_focused_holo_dark" />
<item android:state_enabled="true" android:drawable="@drawable/textfield_multiline_default_holo_dark" />
<item android:state_focused="true" android:drawable="@drawable/textfield_multiline_disabled_focused_holo_dark" />
<item android:drawable="@drawable/textfield_multiline_disabled_holo_dark" />
diff --git a/core/res/res/drawable/edit_text_multiline_holo_light.xml b/core/res/res/drawable/edit_text_multiline_holo_light.xml
index 08b3ec6..41a4eab 100644
--- a/core/res/res/drawable/edit_text_multiline_holo_light.xml
+++ b/core/res/res/drawable/edit_text_multiline_holo_light.xml
@@ -17,7 +17,8 @@
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_window_focused="false" android:state_enabled="true" android:drawable="@drawable/textfield_multiline_default_holo_light" />
<item android:state_window_focused="false" android:state_enabled="false" android:drawable="@drawable/textfield_multiline_disabled_holo_light" />
- <item android:state_enabled="true" android:state_focused="true" android:drawable="@drawable/textfield_multiline_active_holo_light" />
+ <item android:state_enabled="true" android:state_focused="true" android:drawable="@drawable/textfield_multiline_activated_holo_light" />
+ <item android:state_enabled="true" android:state_activated="true" android:drawable="@drawable/textfield_multiline_focused_holo_light" />
<item android:state_enabled="true" android:drawable="@drawable/textfield_multiline_default_holo_light" />
<item android:state_focused="true" android:drawable="@drawable/textfield_multiline_disabled_focused_holo_light" />
<item android:drawable="@drawable/textfield_multiline_disabled_holo_light" />
diff --git a/core/res/res/layout-xlarge/alert_dialog_holo.xml b/core/res/res/layout-xlarge/alert_dialog_holo.xml
index 72b1e31..6790a81 100644
--- a/core/res/res/layout-xlarge/alert_dialog_holo.xml
+++ b/core/res/res/layout-xlarge/alert_dialog_holo.xml
@@ -74,14 +74,17 @@
<ScrollView android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginLeft="16dip"
+ android:layout_marginRight="16dip"
android:paddingTop="32dip"
android:paddingBottom="32dip"
- android:paddingLeft="32dip"
- android:paddingRight="32dip">
+ android:clipToPadding="false">
<TextView android:id="@+id/message"
style="?android:attr/textAppearanceMedium"
android:layout_width="match_parent"
- android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"
+ android:paddingLeft="16dip"
+ android:paddingRight="16dip" />
</ScrollView>
</LinearLayout>
@@ -93,19 +96,24 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="8dip"
- android:paddingBottom="8dip" />
+ android:paddingBottom="8dip"
+ android:paddingLeft="32dip"
+ android:paddingRight="32dip" />
</FrameLayout>
<LinearLayout android:id="@+id/buttonPanel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="54dip"
- android:orientation="vertical" >
+ android:orientation="vertical"
+ android:divider="?android:attr/dividerHorizontal"
+ android:showDividers="beginning"
+ android:dividerPadding="16dip">
<LinearLayout
+ style="?android:attr/buttonGroupStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
- android:paddingTop="4dip"
android:paddingLeft="2dip"
android:paddingRight="2dip"
android:measureWithLargestChild="true">
@@ -120,18 +128,21 @@
android:layout_gravity="left"
android:layout_weight="1"
android:maxLines="2"
+ style="?android:attr/borderlessButtonStyle"
android:layout_height="wrap_content" />
<Button android:id="@+id/button3"
android:layout_width="0dip"
android:layout_gravity="center_horizontal"
android:layout_weight="1"
android:maxLines="2"
+ style="?android:attr/borderlessButtonStyle"
android:layout_height="wrap_content" />
<Button android:id="@+id/button2"
android:layout_width="0dip"
android:layout_gravity="right"
android:layout_weight="1"
android:maxLines="2"
+ style="?android:attr/borderlessButtonStyle"
android:layout_height="wrap_content" />
<LinearLayout android:id="@+id/rightSpacer"
android:layout_width="0dip"
diff --git a/core/res/res/layout-xlarge/select_dialog_holo.xml b/core/res/res/layout-xlarge/select_dialog_holo.xml
new file mode 100644
index 0000000..7c95693
--- /dev/null
+++ b/core/res/res/layout-xlarge/select_dialog_holo.xml
@@ -0,0 +1,36 @@
+<?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.
+*/
+-->
+
+<!--
+ This layout file is used by the AlertDialog when displaying a list of items.
+ This layout file is inflated and used as the ListView to display the items.
+ Assign an ID so its state will be saved/restored.
+-->
+<view class="com.android.internal.app.AlertController$RecycleListView"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+android:id/select_dialog_listview"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginTop="5dip"
+ android:paddingLeft="16dip"
+ android:paddingRight="16dip"
+ android:cacheColorHint="@null"
+ android:divider="?android:attr/listDividerAlertDialog"
+ android:scrollbars="vertical"
+ android:overScrollMode="ifContentScrolls" />
diff --git a/core/res/res/layout-xlarge/select_dialog_item_holo.xml b/core/res/res/layout-xlarge/select_dialog_item_holo.xml
new file mode 100644
index 0000000..396092e
--- /dev/null
+++ b/core/res/res/layout-xlarge/select_dialog_item_holo.xml
@@ -0,0 +1,36 @@
+<?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.
+*/
+-->
+
+<!--
+ This layout file is used by the AlertDialog when displaying a list of items.
+ This layout file is inflated and used as the TextView to display individual
+ items.
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/text1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorAlertDialogListItem"
+ android:gravity="center_vertical"
+ android:paddingLeft="16dip"
+ android:paddingRight="16dip"
+ android:ellipsize="marquee"
+/>
diff --git a/core/res/res/layout-xlarge/select_dialog_multichoice_holo.xml b/core/res/res/layout-xlarge/select_dialog_multichoice_holo.xml
new file mode 100644
index 0000000..8027035
--- /dev/null
+++ b/core/res/res/layout-xlarge/select_dialog_multichoice_holo.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+
+<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/text1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorAlertDialogListItem"
+ android:gravity="center_vertical"
+ android:paddingLeft="16dip"
+ android:paddingRight="16dip"
+ android:checkMark="?android:attr/listChoiceIndicatorMultiple"
+ android:ellipsize="marquee"
+/>
diff --git a/core/res/res/layout-xlarge/select_dialog_singlechoice_holo.xml b/core/res/res/layout-xlarge/select_dialog_singlechoice_holo.xml
new file mode 100644
index 0000000..cab519f
--- /dev/null
+++ b/core/res/res/layout-xlarge/select_dialog_singlechoice_holo.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+
+<CheckedTextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/text1"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textColor="?android:attr/textColorAlertDialogListItem"
+ android:gravity="center_vertical"
+ android:paddingLeft="16dip"
+ android:paddingRight="16dip"
+ android:checkMark="?android:attr/listChoiceIndicatorSingle"
+ android:ellipsize="marquee"
+/>
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/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index fd4b32c..4abcc9f 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -925,6 +925,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"تم إرسال عدد كبير من الرسائل القصيرة SMS. حدّد \"موافق\" للمتابعة، أو \"إلغاء\" لإيقاف الإرسال."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"موافق"</string>
<string name="sms_control_no" msgid="1715320703137199869">"إلغاء"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"تعيين"</string>
<string name="default_permission_group" msgid="2690160991405646128">"افتراضي"</string>
<string name="no_permissions" msgid="7283357728219338112">"لا أذونات مطلوبة"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index e01bb9b..03206b7 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -925,6 +925,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"Изпращат се голям брой SMS съобщения. Изберете „OK“, за да продължите, или „Отказ“, за да спрете изпращането."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Отказ"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Задаване"</string>
<string name="default_permission_group" msgid="2690160991405646128">"По подразбиране"</string>
<string name="no_permissions" msgid="7283357728219338112">"Не се изискват разрешения"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index c32c95a..fd788e3 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -925,6 +925,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"S\'estan enviant molts missatges SMS. Seleccioneu \"D\'acord\" per continuar o \"Cancel·la\" per aturar l\'enviament."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"D\'acord"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Cancel·la"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Defineix"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Predeterminat"</string>
<string name="no_permissions" msgid="7283357728219338112">"No cal cap permís"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index f65f585..1c233f0 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -482,10 +482,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Bez upozornění smazat všechna data telefonu obnovením továrních dat"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Nastavit globální proxy server zařízení"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Vyberte globální proxy server, který se bude používat, když jsou zásady aktivní. Aktuální globální proxy server nastavuje pouze první správce zařízení."</string>
- <!-- no translation found for policylab_expirePassword (2314569545488269564) -->
- <skip />
- <!-- no translation found for policydesc_expirePassword (7276906351852798814) -->
- <skip />
+ <string name="policylab_expirePassword" msgid="2314569545488269564">"Nastavit konec platnosti hesla"</string>
+ <string name="policydesc_expirePassword" msgid="7276906351852798814">"Ovládání doby, po jejímž uplynutí je nutné změnit heslo pro odemknutí obrazovky"</string>
<string-array name="phoneTypes">
<item msgid="8901098336658710359">"Domů"</item>
<item msgid="869923650527136615">"Mobil"</item>
@@ -668,8 +666,7 @@
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
- <!-- no translation found for autofill_address_summary_separator (7483307893170324129) -->
- <skip />
+ <string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<!-- no translation found for autofill_address_summary_format (4874459455786827344) -->
<skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"čtení historie a záložek Prohlížeče"</string>
@@ -869,6 +866,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"Je odesílán velký počet zpráv SMS. Vyberte OK, chcete-li pokračovat, nebo Zrušit, chcete-li odesílání ukončit."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Zrušit"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Nastavit"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Výchozí"</string>
<string name="no_permissions" msgid="7283357728219338112">"Nejsou vyžadována žádná oprávnění"</string>
@@ -876,8 +875,8 @@
<string name="perms_show_all" msgid="2671791163933091180"><b>"Zobrazit vše"</b></string>
<string name="usb_storage_activity_title" msgid="2399289999608900443">"Úložiště USB"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"USB připojeno"</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Připojili jste telefon k počítači pomocí rozhraní USB. Chcete-li kopírovat soubory z počítače do úložiště USB zařízení Android či obráceně, vyberte následující tlačítko."</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Připojili jste telefon k počítači pomocí rozhraní USB. Chcete-li kopírovat soubory z počítače do úložiště USB zařízení Android či obráceně, vyberte následující tlačítko."</string>
+ <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Připojili jste se k počítači pomocí rozhraní USB. Chcete-li kopírovat soubory z počítače do úložiště USB v zařízení Android či obráceně, stiskněte tlačítko níže."</string>
+ <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Připojili jste se k počítači pomocí rozhraní USB. Chcete-li kopírovat soubory z počítače na kartu SD v zařízení Android či obráceně, stiskněte tlačítko níže."</string>
<string name="usb_storage_button_mount" msgid="1052259930369508235">"Zapnout úložiště USB"</string>
<string name="usb_storage_error_message" product="nosdcard" msgid="3276413764430468454">"Problém s použitím úložiště USB jako velkokapacitního úložiště."</string>
<string name="usb_storage_error_message" product="default" msgid="120810397713773275">"Problém s použitím karty SD jako velkokapacitního úložiště USB."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 8bb762b..5f96369 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -482,10 +482,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Slet telefonens data uden varsel ved at gendanne fabriksindstillinger"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Angiv enhedens globale proxy"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Angiv enhedens globale proxy, der skal bruges, mens politikken er aktiveret. Kun den første enhedsadministrator angiver den effektive globale proxy."</string>
- <!-- no translation found for policylab_expirePassword (2314569545488269564) -->
- <skip />
- <!-- no translation found for policydesc_expirePassword (7276906351852798814) -->
- <skip />
+ <string name="policylab_expirePassword" msgid="2314569545488269564">"Indstil udløb for adgangskode"</string>
+ <string name="policydesc_expirePassword" msgid="7276906351852798814">"Kontroller, hvor lang tid der skal gå, før adgangskoden til skærmlåsen skal ændres."</string>
<string-array name="phoneTypes">
<item msgid="8901098336658710359">"Hjem"</item>
<item msgid="869923650527136615">"Mobil"</item>
@@ -668,8 +666,7 @@
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
- <!-- no translation found for autofill_address_summary_separator (7483307893170324129) -->
- <skip />
+ <string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<!-- no translation found for autofill_address_summary_format (4874459455786827344) -->
<skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"læs browserens oversigt og bogmærker"</string>
@@ -869,6 +866,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"Der sendes et stort antal sms-beskeder. Vælg \"OK\" for at fortsætte eller \"Annuller\" for at stoppe afsendelsen."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Annuller"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Angiv"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Standard"</string>
<string name="no_permissions" msgid="7283357728219338112">"Der kræves ingen tilladelser"</string>
@@ -876,8 +875,8 @@
<string name="perms_show_all" msgid="2671791163933091180"><b>"Vis alle"</b></string>
<string name="usb_storage_activity_title" msgid="2399289999608900443">"USB-masselagring"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"USB er tilsluttet"</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Du har forbundet din telefon til din computer via USB. Vælg knappen nedenfor, hvis du vil kopiere filer mellem din computer og din Androids USB-lager."</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Du har forbundet din telefon til din computer via USB. Vælg knappen nedenfor, hvis du vil kopiere filer mellem din computer og din Androids USB-lager."</string>
+ <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Du har fået forbindelse til din computer via USB. Vælg knappen nedenfor, hvis du vil kopiere filer mellem din computer og din Androids USB-lager."</string>
+ <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Du har fået forbindelse til din computer via USB. Vælg knappen nedenfor, hvis du ønsker at kopiere filer mellem din computer og din Androids SD-kort."</string>
<string name="usb_storage_button_mount" msgid="1052259930369508235">"Slå USB-lagringen til"</string>
<string name="usb_storage_error_message" product="nosdcard" msgid="3276413764430468454">"Der opstod et problem med at bruge USB-lager til USB-masselager."</string>
<string name="usb_storage_error_message" product="default" msgid="120810397713773275">"Der opstod et problem med at bruge dit SD-kort til USB-masselager."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 87e57ce..8aa24d9 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -482,10 +482,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Auf Werkseinstellungen zurücksetzen und Daten auf dem Telefon ohne Warnung löschen"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Den globalen Proxy des Geräts festlegen"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Den globalen Proxy des Geräts zur Verwendung während der Aktivierung der Richtlinie festlegen. Nur der erste Geräteadministrator kann den gültigen globalen Proxy festlegen."</string>
- <!-- no translation found for policylab_expirePassword (2314569545488269564) -->
- <skip />
- <!-- no translation found for policydesc_expirePassword (7276906351852798814) -->
- <skip />
+ <string name="policylab_expirePassword" msgid="2314569545488269564">"Ablauf des Passworts festlegen"</string>
+ <string name="policydesc_expirePassword" msgid="7276906351852798814">"Zeitraum bis zur Änderung des Passworts für die Bildschirmsperre festlegen"</string>
<string-array name="phoneTypes">
<item msgid="8901098336658710359">"Privat"</item>
<item msgid="869923650527136615">"Mobil"</item>
@@ -668,8 +666,7 @@
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
- <!-- no translation found for autofill_address_summary_separator (7483307893170324129) -->
- <skip />
+ <string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<!-- no translation found for autofill_address_summary_format (4874459455786827344) -->
<skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"Browserverlauf und Lesezeichen lesen"</string>
@@ -869,6 +866,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"Es werden eine große Anzahl an Kurznachrichten versendet. Wählen Sie \"OK\", um fortzufahren, oder drücken Sie auf \"Abbrechen\", um den Sendevorgang zu beenden."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Abbrechen"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Einstellen"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Standard"</string>
<string name="no_permissions" msgid="7283357728219338112">"Keine Berechtigungen erforderlich"</string>
@@ -876,8 +875,8 @@
<string name="perms_show_all" msgid="2671791163933091180"><b>"Alle anzeigen"</b></string>
<string name="usb_storage_activity_title" msgid="2399289999608900443">"USB-Massenspeicher"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"USB-Verbindung"</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Sie haben Ihr Telefon über USB mit Ihrem Computer verbunden. Wählen Sie die Schaltfläche unten aus, wenn Sie Dateien von Ihrem Computer in den USB-Speicher Ihres Android-Geräts und umgekehrt kopieren möchten."</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Sie haben Ihr Telefon über USB mit Ihrem Computer verbunden. Wählen Sie die Schaltfläche unten aus, wenn Sie Dateien von Ihrem Computer in den USB-Speicher Ihres Android-Geräts und umgekehrt kopieren möchten."</string>
+ <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Sie haben Ihr Telefon über USB mit Ihrem Computer verbunden. Berühren Sie die Schaltfläche unten, wenn Sie Dateien von Ihrem Computer in den USB-Speicher Ihres Android-Geräts und umgekehrt kopieren möchten."</string>
+ <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Sie haben Ihr Telefon über USB mit Ihrem Computer verbunden. Berühren Sie die Schaltfläche unten, wenn Sie Dateien von Ihrem Computer auf die SD-Karte Ihres Android-Geräts und umgekehrt kopieren möchten."</string>
<string name="usb_storage_button_mount" msgid="1052259930369508235">"USB-Speicher aktivieren"</string>
<string name="usb_storage_error_message" product="nosdcard" msgid="3276413764430468454">"Bei der Verwendung Ihres USB-Speichers als USB-Massenspeicher ist ein Problem aufgetreten."</string>
<string name="usb_storage_error_message" product="default" msgid="120810397713773275">"Bei der Verwendung Ihrer SD-Karte als USB-Massenspeicher ist ein Problem aufgetreten."</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index bbd02f2..c74839f 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -482,10 +482,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Διαγραφή των δεδομένων του τηλεφώνου χωρίς προειδοποίηση με επαναφορά των εργοστασιακών δεδομένων"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Ρύθμιση του γενικού διακομιστή μεσολάβησης της συσκευής"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Ορίστε τη χρήση του γενικού διακομιστή μεσολάβησης της συσκευής όταν είναι ενεργοποιημένη η πολιτική. Μόνο ο διαχειριστής της πρώτης συσκευής ορίζει τον ισχύοντα γενικό διακομιστή μεσολάβησης."</string>
- <!-- no translation found for policylab_expirePassword (2314569545488269564) -->
- <skip />
- <!-- no translation found for policydesc_expirePassword (7276906351852798814) -->
- <skip />
+ <string name="policylab_expirePassword" msgid="2314569545488269564">"Ορισμός λήξης κωδ. πρόσβασης"</string>
+ <string name="policydesc_expirePassword" msgid="7276906351852798814">"Ελέγξτε πόσος χρόνος απομένει προτού πρέπει να αλλάξετε τον κωδικό πρόσβασης κλειδώματος της οθόνης"</string>
<string-array name="phoneTypes">
<item msgid="8901098336658710359">"Οικία"</item>
<item msgid="869923650527136615">"Κινητό"</item>
@@ -668,8 +666,7 @@
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
- <!-- no translation found for autofill_address_summary_separator (7483307893170324129) -->
- <skip />
+ <string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<!-- no translation found for autofill_address_summary_format (4874459455786827344) -->
<skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"ανάγνωση ιστορικού και σελιδοδεικτών προγράμματος περιήγησης"</string>
@@ -869,6 +866,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"Αποστέλλεται μεγάλος αριθμός μηνυμάτων SMS. Επιλέξτε \"OK\" για συνέχεια, ή \"Ακύρωση\" για διακοπή αποστολής."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Ακύρωση"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Ορισμός"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Προεπιλεγμένο"</string>
<string name="no_permissions" msgid="7283357728219338112">"Δεν απαιτούνται άδειες"</string>
@@ -876,8 +875,8 @@
<string name="perms_show_all" msgid="2671791163933091180"><b>"Εμφάνιση όλων"</b></string>
<string name="usb_storage_activity_title" msgid="2399289999608900443">"Μαζική αποθήκευση USB"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"Το USB είναι συνδεδεμένο"</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Συνδέσατε το τηλέφωνό σας στον υπολογιστή μέσω USB. Επιλέξτε το παρακάτω κουμπί αν θέλετε να αντιγράψετε αρχεία μεταξύ του υπολογιστή και του χώρου αποθήκευσης USB του Android."</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Συνδέσατε το τηλέφωνό σας στον υπολογιστή μέσω USB. Επιλέξτε το παρακάτω κουμπί αν θέλετε να αντιγράψετε αρχεία μεταξύ του υπολογιστή και του χώρου αποθήκευσης USB του Android."</string>
+ <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Συνδεθήκατε στον υπολογιστή σας μέσω USB. Αγγίξτε το παρακάτω κουμπί, αν θέλετε να αντιγράψετε αρχεία ανάμεσα στον υπολογιστή σας και τον χώρο αποθήκευσης USB του Android."</string>
+ <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Συνδεθήκατε στον υπολογιστή σας μέσω USB. Αγγίξτε το παρακάτω κουμπί, αν θέλετε να αντιγράψετε αρχεία ανάμεσα στον υπολογιστή σας και την κάρτα SD του Android."</string>
<string name="usb_storage_button_mount" msgid="1052259930369508235">"Ενεργοποίηση αποθηκευτικού χώρου USB"</string>
<string name="usb_storage_error_message" product="nosdcard" msgid="3276413764430468454">"Παρουσιάστηκε ένα πρόβλημα στη χρήση του αποθηκευτικού χώρου USB ως χώρο USB μαζικής αποθήκευσης."</string>
<string name="usb_storage_error_message" product="default" msgid="120810397713773275">"Παρουσιάστηκε ένα πρόβλημα στη χρήση της κάρτας SD ως χώρο USB μαζικής αποθήκευσης."</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index eab891f..11ae9f4 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -905,6 +905,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"A large number of SMS messages are being sent. Select \"OK\" to continue or \"Cancel\" to stop sending."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Cancel"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Set"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Default"</string>
<string name="no_permissions" msgid="7283357728219338112">"No permission required"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 7fc79b1..abce7dd 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -481,10 +481,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Borrar los datos del teléfono sin advertencias al restablecer la configuración original"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Configura el proxy global de dispositivo"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Configuración del proxy global de dispositivo que se utilizará mientras se habilita la política. Sólo la primera administración de dispositivo configura el proxy global efectivo."</string>
- <!-- no translation found for policylab_expirePassword (2314569545488269564) -->
- <skip />
- <!-- no translation found for policydesc_expirePassword (7276906351852798814) -->
- <skip />
+ <string name="policylab_expirePassword" msgid="2314569545488269564">"Establecer la caducidad de la contraseña"</string>
+ <string name="policydesc_expirePassword" msgid="7276906351852798814">"Verifica cuánto tiempo antes debes cambiar la contraseña de la pantalla de bloqueo"</string>
<string-array name="phoneTypes">
<item msgid="8901098336658710359">"Casa"</item>
<item msgid="869923650527136615">"Celular"</item>
@@ -867,6 +865,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"Se envía una gran cantidad de mensajes SMS. Selecciona \"Aceptar\" para continuar o \"Cancelar\" para detener el envío."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"Aceptar"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Cancelar"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Establecer"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Predeterminado"</string>
<string name="no_permissions" msgid="7283357728219338112">"No se requieren permisos"</string>
@@ -874,8 +874,8 @@
<string name="perms_show_all" msgid="2671791163933091180"><b>"Mostrar todos"</b></string>
<string name="usb_storage_activity_title" msgid="2399289999608900443">"Almacenamiento masivo USB"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"conectado al USB"</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Has conectado tu teléfono a tu computadora mediante USB. Selecciona el botón a continuación si deseas copiar los archivos entre tu computadora y el almacenamiento USB de Android."</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Has conectado tu teléfono a tu computadora mediante USB. Selecciona el botón a continuación si deseas copiar los archivos entre tu computadora y el almacenamiento USB de Android."</string>
+ <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Has conectado tu teléfono a tu computadora mediante USB. Selecciona el botón a continuación si deseas copiar los archivos entre tu computadora y el almacenamiento USB de Android."</string>
+ <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Has conectado tu teléfono a tu computadora mediante USB. Selecciona el botón a continuación si deseas copiar los archivos entre tu computadora y la tarjeta SD de Android."</string>
<string name="usb_storage_button_mount" msgid="1052259930369508235">"Activar el almacenamiento USB"</string>
<string name="usb_storage_error_message" product="nosdcard" msgid="3276413764430468454">"Hay un problema para utilizar el almacenamiento USB en el almacenamiento masivo USB."</string>
<string name="usb_storage_error_message" product="default" msgid="120810397713773275">"Hay un problema para utilizar tu tarjeta SD en el almacenamiento masivo USB."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 1b28dca..8c3543c 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -482,10 +482,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Borrado de los datos del teléfono sin avisar restableciendo datos de fábrica"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Definir el servidor proxy global"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Define el servidor proxy global que se debe utilizar mientras la política esté habilitada. Solo el primer administrador de dispositivos define el servidor proxy global efectivo."</string>
- <!-- no translation found for policylab_expirePassword (2314569545488269564) -->
- <skip />
- <!-- no translation found for policydesc_expirePassword (7276906351852798814) -->
- <skip />
+ <string name="policylab_expirePassword" msgid="2314569545488269564">"Definir caducidad contraseña"</string>
+ <string name="policydesc_expirePassword" msgid="7276906351852798814">"Permite controlar cuándo se debe cambiar la contraseña de bloqueo de la pantalla."</string>
<string-array name="phoneTypes">
<item msgid="8901098336658710359">"Casa"</item>
<item msgid="869923650527136615">"Móvil"</item>
@@ -668,8 +666,7 @@
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
- <!-- no translation found for autofill_address_summary_separator (7483307893170324129) -->
- <skip />
+ <string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<!-- no translation found for autofill_address_summary_format (4874459455786827344) -->
<skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"leer información de marcadores y del historial del navegador"</string>
@@ -869,6 +866,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"Se ha enviado un número elevado de mensajes SMS. Selecciona \"Aceptar\" para continuar o \"Cancelar\" para interrumpir el envío."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"Aceptar"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Cancelar"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Establecer"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Predeterminado"</string>
<string name="no_permissions" msgid="7283357728219338112">"No es necesario ningún permiso"</string>
@@ -876,8 +875,8 @@
<string name="perms_show_all" msgid="2671791163933091180"><b>"Mostrar todos"</b></string>
<string name="usb_storage_activity_title" msgid="2399289999608900443">"Almacenamiento USB masivo"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"Conectado por USB"</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Has conectado el teléfono al equipo mediante USB. Selecciona el botón situado debajo si deseas copiar archivos entre el equipo y el almacenamiento USB del teléfono con Android."</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Has conectado el teléfono al equipo mediante USB. Selecciona el botón situado debajo si deseas copiar archivos entre el equipo y el almacenamiento USB del teléfono con Android."</string>
+ <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Has conectado el teléfono al equipo mediante USB. Toca el botón situado debajo si deseas copiar archivos entre el equipo y el almacenamiento USB del teléfono Android."</string>
+ <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Has conectado el teléfono al equipo mediante USB. Toca el botón situado debajo si deseas copiar archivos entre el equipo y la tarjeta SD del teléfono Android."</string>
<string name="usb_storage_button_mount" msgid="1052259930369508235">"Activar almacenamiento USB"</string>
<string name="usb_storage_error_message" product="nosdcard" msgid="3276413764430468454">"Se ha producido un problema al utilizar el almacenamiento USB para el almacenamiento masivo USB."</string>
<string name="usb_storage_error_message" product="default" msgid="120810397713773275">"Se ha producido un problema al utilizar la tarjeta SD para el almacenamiento USB masivo."</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index cbb5fe3..068bfe0 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -925,6 +925,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"تعداد زیادی پیامک ارسال شده است. برای ادامه، \"تأیید\" را کلیک کرده و برای توقف ارسال، \"لغو\" را کلیک کنید."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"تأیید"</string>
<string name="sms_control_no" msgid="1715320703137199869">"لغو"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"تنظیم"</string>
<string name="default_permission_group" msgid="2690160991405646128">"پیش فرض"</string>
<string name="no_permissions" msgid="7283357728219338112">"مجوزی لازم نیست"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 3390669..bddb852 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -925,6 +925,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"Olet lähettämässä suurta määrää tekstiviestejä. Jatka valitsemalla OK tai peruuta lähetys valitsemalla Peruuta."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Peruuta"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Aseta"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Oletus"</string>
<string name="no_permissions" msgid="7283357728219338112">"Lupia ei tarvita"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index f618070..700674c 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -482,10 +482,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Effacer les données du téléphone sans avertissement, en restaurant les valeurs d\'usine"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Définir le proxy global du mobile"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Indiquez le proxy global à utiliser pour ce mobile lorsque les règles sont activées. Seul l\'administrateur principal du mobile peut définir le proxy global utilisé."</string>
- <!-- no translation found for policylab_expirePassword (2314569545488269564) -->
- <skip />
- <!-- no translation found for policydesc_expirePassword (7276906351852798814) -->
- <skip />
+ <string name="policylab_expirePassword" msgid="2314569545488269564">"Définir date exp. mot de passe"</string>
+ <string name="policydesc_expirePassword" msgid="7276906351852798814">"Définir la fréquence de changement du mot de passe de verrouillage d\'écran"</string>
<string-array name="phoneTypes">
<item msgid="8901098336658710359">"Domicile"</item>
<item msgid="869923650527136615">"Mobile"</item>
@@ -668,8 +666,7 @@
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
- <!-- no translation found for autofill_address_summary_separator (7483307893170324129) -->
- <skip />
+ <string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<!-- no translation found for autofill_address_summary_format (4874459455786827344) -->
<skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"lire l\'historique et les favoris du navigateur"</string>
@@ -869,6 +866,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"Vous êtes sur le point d\'envoyer un grand nombre de messages SMS. Sélectionnez OK pour continuer ou Annuler pour interrompre l\'envoi."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Annuler"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Définir"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Par défaut"</string>
<string name="no_permissions" msgid="7283357728219338112">"Aucune autorisation requise"</string>
@@ -876,8 +875,8 @@
<string name="perms_show_all" msgid="2671791163933091180"><b>"Tout afficher"</b></string>
<string name="usb_storage_activity_title" msgid="2399289999608900443">"Stockage de masse USB"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"Connecté à l\'aide d\'un câble USB"</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Vous avez connecté votre téléphone à votre ordinateur à l\'aide d\'un câble USB. Sélectionnez le bouton ci-dessous pour copier des fichiers de votre ordinateur vers la mémoire de stockage USB de votre Android, ou inversement."</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Vous avez connecté votre téléphone à votre ordinateur à l\'aide d\'un câble USB. Sélectionnez le bouton ci-dessous pour copier des fichiers de votre ordinateur vers la mémoire de stockage USB de votre Android, ou inversement."</string>
+ <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Vous êtes connecté à votre ordinateur via un câble USB. Appuyez sur le bouton ci-dessous pour copier des fichiers de votre ordinateur vers la mémoire de stockage USB de votre Android, ou inversement."</string>
+ <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Vous êtes connecté à votre ordinateur via un câble USB. Appuyez sur le bouton ci-dessous pour copier des fichiers de votre ordinateur vers la carte SD de votre Android, ou inversement."</string>
<string name="usb_storage_button_mount" msgid="1052259930369508235">"Activer la mémoire de stockage USB"</string>
<string name="usb_storage_error_message" product="nosdcard" msgid="3276413764430468454">"Un problème est survenu lors de l\'utilisation de votre mémoire de stockage USB comme mémoire de stockage de masse."</string>
<string name="usb_storage_error_message" product="default" msgid="120810397713773275">"Un problème est survenu lors de l\'utilisation de votre carte SD comme mémoire de stockage de masse USB."</string>
diff --git a/core/res/res/values-he/strings.xml b/core/res/res/values-he/strings.xml
index c5d945c..25074ea 100644
--- a/core/res/res/values-he/strings.xml
+++ b/core/res/res/values-he/strings.xml
@@ -925,6 +925,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"מספר גדול של הודעות SMS נשלח. בחר \'אישור\' כדי להמשיך או \'ביטול\' כדי לעצור את השליחה."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"אישור"</string>
<string name="sms_control_no" msgid="1715320703137199869">"ביטול"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"הגדר"</string>
<string name="default_permission_group" msgid="2690160991405646128">"ברירת מחדל"</string>
<string name="no_permissions" msgid="7283357728219338112">"לא דרושים אישורים"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index bc6d451..a075566 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -925,6 +925,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"Šalje se velika količina SMS poruka. Odaberite \"U redu\" za nastavak, ili za prekid slanja odaberite \"Odustani\"."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"U redu"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Odustani"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Postavi"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Zadano"</string>
<string name="no_permissions" msgid="7283357728219338112">"Nije potrebno dopuštenje"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 36aea65..3a4bf8d 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -925,6 +925,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"Nagyszámú SMS-t kíván elküldeni. A folytatáshoz válassza az \"OK\", a küldés leállításához a \"Mégse\" lehetőséget."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Mégse"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Beállítás"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Alapértelmezett"</string>
<string name="no_permissions" msgid="7283357728219338112">"Nincs szükség engedélyre"</string>
diff --git a/core/res/res/values-id/strings.xml b/core/res/res/values-id/strings.xml
index 2d07b33..aa243e0 100644
--- a/core/res/res/values-id/strings.xml
+++ b/core/res/res/values-id/strings.xml
@@ -925,6 +925,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"Sejumlah besar pesan SMS sedang dikirimkan. Pilih \"OK\" untuk melanjutkan, atau \"Batal\" untuk menghentikan pengiriman."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Batal"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Setel"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Bawaan"</string>
<string name="no_permissions" msgid="7283357728219338112">"Tidak perlu izin"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 238a748..0b74664 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -482,10 +482,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Cancella i dati del telefono senza preavviso eseguendo un ripristino dati di fabbrica"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Imposta il proxy globale del dispositivo"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Imposta il proxy globale del dispositivo in modo da utilizzarlo mentre la norma è attiva. Il proxy globale effettivo è impostabile solo dal primo amministratore del dispositivo."</string>
- <!-- no translation found for policylab_expirePassword (2314569545488269564) -->
- <skip />
- <!-- no translation found for policydesc_expirePassword (7276906351852798814) -->
- <skip />
+ <string name="policylab_expirePassword" msgid="2314569545488269564">"Imposta scadenza password"</string>
+ <string name="policydesc_expirePassword" msgid="7276906351852798814">"Stabilisci la scadenza della password di blocco dello schermo"</string>
<string-array name="phoneTypes">
<item msgid="8901098336658710359">"Casa"</item>
<item msgid="869923650527136615">"Cellulare"</item>
@@ -668,8 +666,7 @@
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
- <!-- no translation found for autofill_address_summary_separator (7483307893170324129) -->
- <skip />
+ <string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<!-- no translation found for autofill_address_summary_format (4874459455786827344) -->
<skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"lettura cronologia e segnalibri del browser"</string>
@@ -869,6 +866,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"È in corso l\'invio di numerosi SMS. Seleziona \"OK\" per continuare, oppure \"Annulla\" per interrompere l\'invio."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Annulla"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Imposta"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Predefinito"</string>
<string name="no_permissions" msgid="7283357728219338112">"Nessuna autorizzazione richiesta"</string>
@@ -876,8 +875,8 @@
<string name="perms_show_all" msgid="2671791163933091180"><b>"Mostra tutto"</b></string>
<string name="usb_storage_activity_title" msgid="2399289999608900443">"Archivio di massa USB"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"USB collegata"</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Il telefono è stato collegato al computer tramite USB. Seleziona il pulsante sottostante se desideri copiare file tra il computer e l\'archivio USB di Android."</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Il telefono è stato collegato al computer tramite USB. Seleziona il pulsante sottostante se desideri copiare file tra il computer e l\'archivio USB di Android."</string>
+ <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Ti sei collegato al computer tramite USB. Tocca il pulsante sotto se desideri copiare file tra il computer e l\'archivio USB di Android."</string>
+ <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Ti sei collegato al computer tramite USB. Tocca il pulsante sotto se desideri copiare file tra il computer e la scheda SD di Android."</string>
<string name="usb_storage_button_mount" msgid="1052259930369508235">"Attiva archivio USB"</string>
<string name="usb_storage_error_message" product="nosdcard" msgid="3276413764430468454">"Problema di utilizzo dell\'archivio USB come archivio di massa USB."</string>
<string name="usb_storage_error_message" product="default" msgid="120810397713773275">"Problema di utilizzo della scheda SD come archivio di massa USB."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 75d3722..e8bb57a 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -482,10 +482,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"警告せずにデータの初期化を実行して端末内のデータを消去します。"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"端末のグローバルプロキシを設定"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"ポリシーが有効になっている場合は端末のグローバルプロキシが使用されるように設定します。有効なグローバルプロキシを設定できるのは最初のデバイス管理者だけです。"</string>
- <!-- no translation found for policylab_expirePassword (2314569545488269564) -->
- <skip />
- <!-- no translation found for policydesc_expirePassword (7276906351852798814) -->
- <skip />
+ <string name="policylab_expirePassword" msgid="2314569545488269564">"パスワードの有効期限の設定"</string>
+ <string name="policydesc_expirePassword" msgid="7276906351852798814">"画面ロックパスワードの変更が必要になるまでの期間を指定します"</string>
<string-array name="phoneTypes">
<item msgid="8901098336658710359">"自宅"</item>
<item msgid="869923650527136615">"携帯"</item>
@@ -668,8 +666,7 @@
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
- <!-- no translation found for autofill_address_summary_separator (7483307893170324129) -->
- <skip />
+ <string name="autofill_address_summary_separator" msgid="7483307893170324129">"、 "</string>
<!-- no translation found for autofill_address_summary_format (4874459455786827344) -->
<skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"ブラウザの履歴とブックマークを読み取る"</string>
@@ -869,6 +866,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"大量のSMSメッセージを送信しようとしています。[OK]で送信、[キャンセル]で中止します。"</string>
<string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
<string name="sms_control_no" msgid="1715320703137199869">"キャンセル"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"設定"</string>
<string name="default_permission_group" msgid="2690160991405646128">"端末既定"</string>
<string name="no_permissions" msgid="7283357728219338112">"権限の許可は必要ありません"</string>
@@ -876,8 +875,8 @@
<string name="perms_show_all" msgid="2671791163933091180"><b>"すべて表示"</b></string>
<string name="usb_storage_activity_title" msgid="2399289999608900443">"USBマスストレージ"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"USB接続"</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"携帯端末をUSBでパソコンに接続しています。パソコンとAndroidのUSBストレージの間でファイルをコピーするには、下のボタンを選択します。"</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="default" msgid="4510858346516069238">"携帯端末をUSBでパソコンに接続しています。パソコンとAndroidのUSBストレージの間でファイルをコピーするには、下のボタンを選択します。"</string>
+ <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"USBでパソコンに接続しています。パソコンとAndroidのUSBストレージ間でファイルをコピーするには下のボタンをタップします。"</string>
+ <string name="usb_storage_message" product="default" msgid="4510858346516069238">"USBでパソコンに接続しています。パソコンとAndroidのSDカード間でファイルをコピーするには下のボタンをタップします。"</string>
<string name="usb_storage_button_mount" msgid="1052259930369508235">"USBストレージをONにする"</string>
<string name="usb_storage_error_message" product="nosdcard" msgid="3276413764430468454">"USBストレージをUSBマスストレージとして使用する際に問題が発生しました。"</string>
<string name="usb_storage_error_message" product="default" msgid="120810397713773275">"USBをUSBマスストレージとして使用する際に問題が発生しました。"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 1ed8492..ab873be 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -482,10 +482,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"초기화를 수행하여 경고 없이 휴대전화 데이터를 지웁니다."</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"기기 전체 프록시 설정"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"정책이 사용 설정되어 있는 동안 사용될 기기 전체 프록시를 설정합니다. 첫 번째 기기 관리자가 설정한 전체 프록시만 유효합니다."</string>
- <!-- no translation found for policylab_expirePassword (2314569545488269564) -->
- <skip />
- <!-- no translation found for policydesc_expirePassword (7276906351852798814) -->
- <skip />
+ <string name="policylab_expirePassword" msgid="2314569545488269564">"비밀번호 만료 설정"</string>
+ <string name="policydesc_expirePassword" msgid="7276906351852798814">"화면 잠금 비밀번호를 변경해야 하는 기간 변경"</string>
<string-array name="phoneTypes">
<item msgid="8901098336658710359">"집"</item>
<item msgid="869923650527136615">"모바일"</item>
@@ -668,8 +666,7 @@
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
- <!-- no translation found for autofill_address_summary_separator (7483307893170324129) -->
- <skip />
+ <string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<!-- no translation found for autofill_address_summary_format (4874459455786827344) -->
<skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"브라우저의 기록 및 북마크 읽기"</string>
@@ -869,6 +866,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"여러 개의 SMS 메시지를 보내는 중입니다. 계속하려면 \'확인\'을 선택하고 전송을 중지하려면 \'취소\'를 선택하세요."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"확인"</string>
<string name="sms_control_no" msgid="1715320703137199869">"취소"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"설정"</string>
<string name="default_permission_group" msgid="2690160991405646128">"기본값"</string>
<string name="no_permissions" msgid="7283357728219338112">"권한 필요 없음"</string>
@@ -876,8 +875,8 @@
<string name="perms_show_all" msgid="2671791163933091180"><b>"모두 표시"</b></string>
<string name="usb_storage_activity_title" msgid="2399289999608900443">"USB 대용량 저장소"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"USB 연결됨"</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"USB를 통해 휴대전화를 컴퓨터에 연결했습니다. 컴퓨터와 Android의 USB 저장소 간에 파일을 복사하려면 아래의 버튼을 선택하세요."</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="default" msgid="4510858346516069238">"USB를 통해 휴대전화를 컴퓨터에 연결했습니다. 컴퓨터와 Android의 USB 저장소 간에 파일을 복사하려면 아래의 버튼을 선택하세요."</string>
+ <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"USB를 통해 컴퓨터에 연결했습니다. 컴퓨터와 Android의 USB 저장소 간에 파일을 복사하려면 아래의 버튼을 터치하세요."</string>
+ <string name="usb_storage_message" product="default" msgid="4510858346516069238">"USB를 통해 컴퓨터에 연결했습니다. 컴퓨터와 Android의 SD 카드 간에 파일을 복사하려면 아래의 버튼을 터치하세요."</string>
<string name="usb_storage_button_mount" msgid="1052259930369508235">"USB 저장소 사용"</string>
<string name="usb_storage_error_message" product="nosdcard" msgid="3276413764430468454">"USB 대용량 저장소로 공유 저장용량을 사용하는 동안 문제가 발생했습니다."</string>
<string name="usb_storage_error_message" product="default" msgid="120810397713773275">"USB 대용량 저장소로 SD 카드를 사용하는 동안 문제가 발생했습니다."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 41d9fbd..c9059cb 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -925,6 +925,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"Siunčiama daug SMS pranešimų. Pasirinkite „Gerai“, jei norite tęsti, arba „Atšaukti“, jei norite sustabdyti siuntimą."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"Gerai"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Atšaukti"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Nustatyti"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Numatytasis"</string>
<string name="no_permissions" msgid="7283357728219338112">"Nereikia leidimų"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index d706ed5..ee3def8 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -925,6 +925,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"Tiek sūtīts liels īsziņu skaits. Atlasiet Labi, lai turpinātu, vai Atcelt, lai apturētu sūtīšanu."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"Labi"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Atcelt"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Iestatīt"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Noklusējums"</string>
<string name="no_permissions" msgid="7283357728219338112">"Atļaujas nav nepieciešamas."</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 96d9c32..a7e1879 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -482,10 +482,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Tilbakestill telefonens data uten advarsel ved å utføre tilbakestilling til fabrikkstandard"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Angi enhetens globale mellomtjener"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Angir den globale mellomtjeneren på enheten som skal brukes når regelen er aktivert. Kun den opprinnelige administratoren av enheten kan angi den globale mellomtjeneren."</string>
- <!-- no translation found for policylab_expirePassword (2314569545488269564) -->
- <skip />
- <!-- no translation found for policydesc_expirePassword (7276906351852798814) -->
- <skip />
+ <string name="policylab_expirePassword" msgid="2314569545488269564">"Angi utløpsdato for passordet"</string>
+ <string name="policydesc_expirePassword" msgid="7276906351852798814">"Velg hvor lenge det skal gå før passordet til låseskjermen må byttes"</string>
<string-array name="phoneTypes">
<item msgid="8901098336658710359">"Hjemmenummer"</item>
<item msgid="869923650527136615">"Mobil"</item>
@@ -668,8 +666,7 @@
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
- <!-- no translation found for autofill_address_summary_separator (7483307893170324129) -->
- <skip />
+ <string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<!-- no translation found for autofill_address_summary_format (4874459455786827344) -->
<skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"lese nettleserens logg og bokmerker"</string>
@@ -869,6 +866,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"Et stort antall SMS-meldinger blir sendt. Velg «OK» for å fortsette, eller «Avbryt» for å avbryte sendingen."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Avbryt"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Lagre"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Standard"</string>
<string name="no_permissions" msgid="7283357728219338112">"Trenger ingen rettigheter"</string>
@@ -876,8 +875,8 @@
<string name="perms_show_all" msgid="2671791163933091180"><b>"Vis alle"</b></string>
<string name="usb_storage_activity_title" msgid="2399289999608900443">"USB-masselagring"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"USB koblet til"</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Du har koblet telefonen til datamaskinen via USB. Velg knappen nedenfor hvis du vil kopiere filer mellom datamaskinen og USB-lagring for Android."</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Du har koblet telefonen til datamaskinen via USB. Velg knappen nedenfor hvis du vil kopiere filer mellom datamaskinen og USB-lagring for Android."</string>
+ <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Du har koblet telefonen til datamaskinen via USB. Trykk på knappen nedenfor hvis du vil kopiere filer mellom datamaskinen og Android-telefonens USB-lagring."</string>
+ <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Du har koblet telefonen til datamaskinen via USB. Trykk på knappen nedenfor hvis du vil kopiere filer mellom datamaskinen og SD-kortet i Android-telefonen."</string>
<string name="usb_storage_button_mount" msgid="1052259930369508235">"Slå på USB-lagring"</string>
<string name="usb_storage_error_message" product="nosdcard" msgid="3276413764430468454">"Det oppstod et problem under USB-lagring for USB-enheten."</string>
<string name="usb_storage_error_message" product="default" msgid="120810397713773275">"Det oppstod et problem under SD-kortet for USB-enheten."</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 8998fba..3f4c7d4 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -482,10 +482,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"De gegevens van de telefoon zonder waarschuwing wissen door de fabrieksinstellingen te herstellen"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Algemene proxy voor het apparaat instellen"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Stel de algemene proxy voor het apparaat in die moet worden gebruikt terwijl het beleid is geactiveerd. Alleen de eerste apparaatbeheerder stelt de algemene proxy in."</string>
- <!-- no translation found for policylab_expirePassword (2314569545488269564) -->
- <skip />
- <!-- no translation found for policydesc_expirePassword (7276906351852798814) -->
- <skip />
+ <string name="policylab_expirePassword" msgid="2314569545488269564">"Verval wachtwoord instellen"</string>
+ <string name="policydesc_expirePassword" msgid="7276906351852798814">"Beheren hoe lang het duurt voordat het wachtwoord voor schermvergrendeling moet worden gewijzigd"</string>
<string-array name="phoneTypes">
<item msgid="8901098336658710359">"Thuis"</item>
<item msgid="869923650527136615">"Mobiel"</item>
@@ -668,8 +666,7 @@
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
- <!-- no translation found for autofill_address_summary_separator (7483307893170324129) -->
- <skip />
+ <string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<!-- no translation found for autofill_address_summary_format (4874459455786827344) -->
<skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"browsergeschiedenis en bladwijzers lezen"</string>
@@ -869,6 +866,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"Er wordt een groot aantal SMS-berichten verzonden. Selecteer \'OK\' om door te gaan of \'Annuleren\' om de verzending te stoppen."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Annuleren"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Instellen"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Standaard"</string>
<string name="no_permissions" msgid="7283357728219338112">"Geen machtigingen vereist"</string>
@@ -876,8 +875,8 @@
<string name="perms_show_all" msgid="2671791163933091180"><b>"Alles weergeven"</b></string>
<string name="usb_storage_activity_title" msgid="2399289999608900443">"USB-massaopslag"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"USB-verbinding"</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"U heeft uw telefoon via USB op uw computer aangesloten. Selecteer de onderstaande knop als u bestanden tussen uw computer en de USB-opslag van uw Android wilt kopiëren."</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="default" msgid="4510858346516069238">"U heeft uw telefoon via USB op uw computer aangesloten. Selecteer de onderstaande knop als u bestanden tussen uw computer en de USB-opslag van uw Android wilt kopiëren."</string>
+ <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"U heeft uw telefoon via USB op uw computer aangesloten. Raak de onderstaande knop aan als u bestanden tussen uw computer en de USB-opslag van uw Android wilt kopiëren."</string>
+ <string name="usb_storage_message" product="default" msgid="4510858346516069238">"U heeft uw telefoon via USB op uw computer aangesloten. Raak de onderstaande knop aan als u bestanden tussen uw computer en de SD-kaart van uw Android wilt kopiëren."</string>
<string name="usb_storage_button_mount" msgid="1052259930369508235">"USB-opslag inschakelen"</string>
<string name="usb_storage_error_message" product="nosdcard" msgid="3276413764430468454">"Er is een probleem bij het gebruik van uw USB-opslag voor USB-massaopslag."</string>
<string name="usb_storage_error_message" product="default" msgid="120810397713773275">"Er is een probleem bij het gebruik van uw SD-kaart voor USB-massaopslag."</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index ec80f83..fcd7275 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -482,10 +482,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Wymazywanie danych z telefonu bez ostrzeżenia, przez przywrócenie danych fabrycznych"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Ustaw globalny serwer proxy urządzenia"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Ustaw globalny serwer proxy urządzenia do wykorzystywania przy włączonych zasadach. Tylko pierwszy administrator urządzenia ustawia obowiązujący globalny serwer proxy."</string>
- <!-- no translation found for policylab_expirePassword (2314569545488269564) -->
- <skip />
- <!-- no translation found for policydesc_expirePassword (7276906351852798814) -->
- <skip />
+ <string name="policylab_expirePassword" msgid="2314569545488269564">"Ustaw wygasanie hasła"</string>
+ <string name="policydesc_expirePassword" msgid="7276906351852798814">"Kontrola czasu, po którym należy zmienić hasło blokowania ekranu"</string>
<string-array name="phoneTypes">
<item msgid="8901098336658710359">"Dom"</item>
<item msgid="869923650527136615">"Komórka"</item>
@@ -668,8 +666,7 @@
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
- <!-- no translation found for autofill_address_summary_separator (7483307893170324129) -->
- <skip />
+ <string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<!-- no translation found for autofill_address_summary_format (4874459455786827344) -->
<skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"odczyt historii i zakładek przeglądarki"</string>
@@ -869,6 +866,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"Wysyłana jest duża liczba wiadomości SMS. Wybierz „OK”, aby kontynuować, lub „Anuluj”, aby zatrzymać wysyłanie."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Anuluj"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Ustaw"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Domyślne"</string>
<string name="no_permissions" msgid="7283357728219338112">"Nie są wymagane żadne uprawnienia"</string>
@@ -876,8 +875,8 @@
<string name="perms_show_all" msgid="2671791163933091180"><b>"Pokaż wszystko"</b></string>
<string name="usb_storage_activity_title" msgid="2399289999608900443">"Pamięć masowa USB"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"Połączenie przez USB"</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Telefon został połączony z komputerem za pośrednictwem USB. Wybierz poniższy przycisk, aby skopiować pliki między komputerem a nośnikiem USB systemu Android."</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Telefon został połączony z komputerem za pośrednictwem USB. Wybierz poniższy przycisk, aby skopiować pliki między komputerem a nośnikiem USB systemu Android."</string>
+ <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Nawiązano połączenie z komputerem za pośrednictwem USB. Dotknij poniższego przycisku, aby skopiować pliki między komputerem a nośnikiem USB systemu Android."</string>
+ <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Nawiązano połączenie z komputerem za pośrednictwem USB. Dotknij poniższego przycisku, aby skopiować pliki między komputerem a kartą SD systemu Android."</string>
<string name="usb_storage_button_mount" msgid="1052259930369508235">"Włącz nośnik USB"</string>
<string name="usb_storage_error_message" product="nosdcard" msgid="3276413764430468454">"Wystąpił problem z użyciem nośnika USB jako pamięci masowej USB."</string>
<string name="usb_storage_error_message" product="default" msgid="120810397713773275">"Wystąpił problem z użyciem karty SD jako nośnika pamięci masowej USB."</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 5e9b0a4..47a9ed7 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -482,10 +482,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Apagar os dados do telefone sem avisar, ao efectuar uma reposição de dados de fábrica"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Definir o proxy global do aparelho"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Definir o proxy global do aparelho a ser utilizado quando a política estiver activada. Só o primeiro administrador do aparelho define o proxy global efectivo."</string>
- <!-- no translation found for policylab_expirePassword (2314569545488269564) -->
- <skip />
- <!-- no translation found for policydesc_expirePassword (7276906351852798814) -->
- <skip />
+ <string name="policylab_expirePassword" msgid="2314569545488269564">"Def. valid. da palavra-passe"</string>
+ <string name="policydesc_expirePassword" msgid="7276906351852798814">"Controle com que antecedência é necessário alterar a palavra-passe de bloqueio do ecrã"</string>
<string-array name="phoneTypes">
<item msgid="8901098336658710359">"Residência"</item>
<item msgid="869923650527136615">"Móvel"</item>
@@ -668,8 +666,7 @@
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
- <!-- no translation found for autofill_address_summary_separator (7483307893170324129) -->
- <skip />
+ <string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<!-- no translation found for autofill_address_summary_format (4874459455786827344) -->
<skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"ler histórico e marcadores do browser"</string>
@@ -869,6 +866,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"Está a ser enviado um grande número de mensagens SMS. Seleccione \"OK\" para continuar ou \"Cancelar\" para parar o envio."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Cancelar"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Definir"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Predefinido"</string>
<string name="no_permissions" msgid="7283357728219338112">"Não são necessárias permissões"</string>
@@ -876,8 +875,8 @@
<string name="perms_show_all" msgid="2671791163933091180"><b>"Mostrar tudo"</b></string>
<string name="usb_storage_activity_title" msgid="2399289999608900443">"Armazenamento em massa USB"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"Ligado através de USB"</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Ligou o telemóvel ao computador através de USB. Seleccione o botão abaixo se pretender copiar ficheiros entre o computador e o armazenamento USB do Android."</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Ligou o telemóvel ao computador através de USB. Seleccione o botão abaixo se pretender copiar ficheiros entre o computador e o armazenamento USB do Android."</string>
+ <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Ligou ao computador através de USB. Toque no botão abaixo se pretender copiar ficheiros entre o computador e o armazenamento USB do Android."</string>
+ <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Ligou ao computador através de USB. Toque no botão abaixo se pretender copiar ficheiros entre o computador e o cartão SD do Android."</string>
<string name="usb_storage_button_mount" msgid="1052259930369508235">"Activar armazenamento USB"</string>
<string name="usb_storage_error_message" product="nosdcard" msgid="3276413764430468454">"Existe um problema ao utilizar o armazenamento USB para o armazenamento em massa USB."</string>
<string name="usb_storage_error_message" product="default" msgid="120810397713773275">"Existe um problema ao utilizar o cartão SD para armazenamento em massa USB."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index ad8f64a..5aeb79f 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -482,10 +482,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Apaga os dados do telefone sem aviso, executando uma redefinição da configuração original"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Definir o proxy global do dispositivo"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Configura o proxy global do dispositivo para ser usado enquanto a política estiver ativada. Somente o primeiro administrador do dispositivo pode configurar um verdadeiro proxy global."</string>
- <!-- no translation found for policylab_expirePassword (2314569545488269564) -->
- <skip />
- <!-- no translation found for policydesc_expirePassword (7276906351852798814) -->
- <skip />
+ <string name="policylab_expirePassword" msgid="2314569545488269564">"Definir validade da senha"</string>
+ <string name="policydesc_expirePassword" msgid="7276906351852798814">"Controle quanto tempo uma senha de bloqueio de tela deve ficar ativa antes de ser alterada"</string>
<string-array name="phoneTypes">
<item msgid="8901098336658710359">"Residencial"</item>
<item msgid="869923650527136615">"Celular"</item>
@@ -668,8 +666,7 @@
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
- <!-- no translation found for autofill_address_summary_separator (7483307893170324129) -->
- <skip />
+ <string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<!-- no translation found for autofill_address_summary_format (4874459455786827344) -->
<skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"ler histórico e favoritos do Navegador"</string>
@@ -869,6 +866,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"Muitas mensagens SMS estão sendo enviadas. Selecione \"OK\" para continuar ou \"Cancelar\" para interromper o envio."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Cancelar"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Definir"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Padrão"</string>
<string name="no_permissions" msgid="7283357728219338112">"Nenhuma permissão necessária"</string>
@@ -876,8 +875,8 @@
<string name="perms_show_all" msgid="2671791163933091180"><b>"Mostrar todas"</b></string>
<string name="usb_storage_activity_title" msgid="2399289999608900443">"Armazenamento USB em massa"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"Conectado por USB"</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Você conectou o telefone ao computador via USB. Selecione o botão abaixo se quiser copiar arquivos entre seu computador e o armazenamento USB do Android."</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Você conectou o telefone ao computador via USB. Selecione o botão abaixo se quiser copiar arquivos entre seu computador e o armazenamento USB do Android."</string>
+ <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Você conectou ao computador via USB. Toque no botão abaixo se quiser copiar arquivos entre o computador e o armazenamento USB do seu Android."</string>
+ <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Você conectou ao computador via USB. Toque no botão abaixo se quiser copiar arquivos entre o computador e o cartão SD do seu Android."</string>
<string name="usb_storage_button_mount" msgid="1052259930369508235">"Ativar o armazenamento USB"</string>
<string name="usb_storage_error_message" product="nosdcard" msgid="3276413764430468454">"Há um problema com o uso do seu armazenamento USB para armazenamento USB em massa."</string>
<string name="usb_storage_error_message" product="default" msgid="120810397713773275">"Há um problema com o uso do seu cartão SD para armazenamento USB em massa."</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index 527e4e1..a1cbc4a 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -904,6 +904,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"Vulais Vus trametter in grond dumber da messadis SMS? Tschernì OK per cuntinuar u Interrumper per annullar la spediziun."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Interrumper"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Definir"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Standard"</string>
<string name="no_permissions" msgid="7283357728219338112">"Naginas permissiuns obligatoricas"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 486591c..f235957 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -925,6 +925,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"În acest moment se trimit multe mesaje SMS. Selectaţi „OK” pentru a continua sau „Anulaţi” pentru a opri trimiterea."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Anulaţi"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Setaţi"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Prestabilit"</string>
<string name="no_permissions" msgid="7283357728219338112">"Nu se solicită nicio permisiune"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 976a006..4e4bee8 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -482,10 +482,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Уничтожить все данные на телефоне без предупреждения путем сброса настроек"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Глобальный прокси-сервер"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Настройте глобальный прокси-сервер устройства, который будет использоваться при активной политике. Глобальный прокси-сервер должен настроить первый администратор устройства."</string>
- <!-- no translation found for policylab_expirePassword (2314569545488269564) -->
- <skip />
- <!-- no translation found for policydesc_expirePassword (7276906351852798814) -->
- <skip />
+ <string name="policylab_expirePassword" msgid="2314569545488269564">"Задать время действия пароля"</string>
+ <string name="policydesc_expirePassword" msgid="7276906351852798814">"Задать время действия пароля перед появлением экрана блокировки"</string>
<string-array name="phoneTypes">
<item msgid="8901098336658710359">"Домашний"</item>
<item msgid="869923650527136615">"Мобильный"</item>
@@ -668,8 +666,7 @@
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
- <!-- no translation found for autofill_address_summary_separator (7483307893170324129) -->
- <skip />
+ <string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<!-- no translation found for autofill_address_summary_format (4874459455786827344) -->
<skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"считывать историю и закладки браузера"</string>
@@ -869,6 +866,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"Отправляется большое количество SMS-сообщений. Нажмите \"ОК\" для продолжения или \"Отмена\" для прекращения отправки."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"ОК"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Отмена"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Установить"</string>
<string name="default_permission_group" msgid="2690160991405646128">"По умолчанию"</string>
<string name="no_permissions" msgid="7283357728219338112">"Не требуется разрешений"</string>
@@ -876,8 +875,8 @@
<string name="perms_show_all" msgid="2671791163933091180"><b>"Показать все"</b></string>
<string name="usb_storage_activity_title" msgid="2399289999608900443">"Запоминающее устройство USB"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"USB-подключение установлено"</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Телефон подключен к компьютеру через порт USB. Для копирования файлов между компьютером и USB-накопителем Android нажмите кнопку ниже."</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Телефон подключен к компьютеру через порт USB. Для копирования файлов между компьютером и USB-накопителем Android нажмите кнопку ниже."</string>
+ <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Телефон подключен к компьютеру через порт USB. Нажмите приведенную ниже кнопку, чтобы скопировать файлы с компьютера на USB-накопитель устройства Android."</string>
+ <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Телефон подключен к компьютеру через порт USB. Нажмите приведенную ниже кнопку, чтобы скопировать файлы с компьютера на SD-карту устройства Android."</string>
<string name="usb_storage_button_mount" msgid="1052259930369508235">"Включить USB-накопитель"</string>
<string name="usb_storage_error_message" product="nosdcard" msgid="3276413764430468454">"При использовании USB-накопителя в качестве запоминающего устройства USB возникла неполадка."</string>
<string name="usb_storage_error_message" product="default" msgid="120810397713773275">"При использовании SD-карты в качестве запоминающего устройства USB возникла неполадка."</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 7e21ae5..d0413cf 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -925,6 +925,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"Odosiela sa veľký počet správ SMS. Ak chcete pokračovať, vyberte OK. Ak chcete odosielanie ukončiť, vyberte Zrušiť."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Zrušiť"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Nastaviť"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Predvolené"</string>
<string name="no_permissions" msgid="7283357728219338112">"Nevyžadujú sa žiadne oprávnenia."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 68eb899..ddcc6e5 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -925,6 +925,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"V pošiljanju je veliko sporočil SMS. Če želite nadaljevati, izberite »V redu«. Če želite pošiljanje ustaviti, izberite »Prekliči«."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"V redu"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Prekliči"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Nastavi"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Privzeto"</string>
<string name="no_permissions" msgid="7283357728219338112">"Ni zahtevanih dovoljenj"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 5cf7223..7287793 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -925,6 +925,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"Шаље се велики број SMS порука. Кликните на „Потврди“ да бисте наставили или на „Откажи“ да бисте зауставили слање."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"Потврди"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Откажи"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Подеси"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Подразумевано"</string>
<string name="no_permissions" msgid="7283357728219338112">"Није потребна ниједна дозвола"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index e5de6ad..3ace2e3 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -482,10 +482,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Ta bort data från telefonen utan förvarning genom att återställa standardinställningarna"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Ange global proxyserver"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Ange vilken global proxyserver som ska användas när policyn är aktiverad. Endast den första enhetsadministratören anger den faktiska globala proxyservern."</string>
- <!-- no translation found for policylab_expirePassword (2314569545488269564) -->
- <skip />
- <!-- no translation found for policydesc_expirePassword (7276906351852798814) -->
- <skip />
+ <string name="policylab_expirePassword" msgid="2314569545488269564">"Ange lösenordets utgångsdatum"</string>
+ <string name="policydesc_expirePassword" msgid="7276906351852798814">"Se hur långt det är kvar till du måste ändra lösenordet till låsningsskärmen"</string>
<string-array name="phoneTypes">
<item msgid="8901098336658710359">"Hem"</item>
<item msgid="869923650527136615">"Mobil"</item>
@@ -668,8 +666,7 @@
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
- <!-- no translation found for autofill_address_summary_separator (7483307893170324129) -->
- <skip />
+ <string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<!-- no translation found for autofill_address_summary_format (4874459455786827344) -->
<skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"läsa webbläsarhistorik och bokmärken"</string>
@@ -869,6 +866,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"Flera SMS-meddelanden skickas. Tryck på OK om du vill fortsätta eller på Avbryt om du vill avsluta sändningen."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Avbryt"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Ställ in"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Standardinställning"</string>
<string name="no_permissions" msgid="7283357728219338112">"Inga behörigheter krävs"</string>
@@ -876,8 +875,8 @@
<string name="perms_show_all" msgid="2671791163933091180"><b>"Visa alla"</b></string>
<string name="usb_storage_activity_title" msgid="2399289999608900443">"USB-masslagring"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"USB-ansluten"</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Du har anslutit telefonen till datorn via USB. Välj knappen nedan om du vill kopiera filer mellan datorn och Android-telefonens USB-lagringsenhet."</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Du har anslutit telefonen till datorn via USB. Välj knappen nedan om du vill kopiera filer mellan datorn och Android-telefonens USB-lagringsenhet."</string>
+ <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Du har anslutit telefonen till datorn via USB. Tryck på knappen nedan om du vill kopiera filer mellan datorn och Android-telefonens USB-lagringsenhet."</string>
+ <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Du har anslutit telefonen till datorn via USB. Tryck på knappen nedan om du vill kopiera filer mellan datorn och SD-kortet i din Android."</string>
<string name="usb_storage_button_mount" msgid="1052259930369508235">"Aktivera USB-lagring"</string>
<string name="usb_storage_error_message" product="nosdcard" msgid="3276413764430468454">"Det gick inte att använda din USB-lagringsenhet för USB-masslagring."</string>
<string name="usb_storage_error_message" product="default" msgid="120810397713773275">"Det gick inte att använda ditt SD-kort för USB-masslagring."</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 0113275..d1adc6a 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -925,6 +925,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"กำลังส่งข้อความ SMS จำนวนมาก เลือก \"ตกลง\" เพื่อทำงานต่อหรือ \"ยกเลิก\" เพื่อหยุดส่ง"</string>
<string name="sms_control_yes" msgid="2532062172402615953">"ตกลง"</string>
<string name="sms_control_no" msgid="1715320703137199869">"ยกเลิก"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"ตั้งค่า"</string>
<string name="default_permission_group" msgid="2690160991405646128">"เริ่มต้น"</string>
<string name="no_permissions" msgid="7283357728219338112">"ไม่ต้องการการอนุญาต"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 0e28a1a..209b4b2 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -925,6 +925,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"Pinapadala ang malaking bilang ng mga SMS na mensahe. Piliin ang \"OK\" upang magpatuloy, o \"Kanselahin\" upang itigil ang pagpapadala."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Kanselahin"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Itakda"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Default"</string>
<string name="no_permissions" msgid="7283357728219338112">"Walang mga kinakailangang pahintulot"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index a1abbeb..d24df0c 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -482,10 +482,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"Fabrika verilerine sıfırlama işlemi gerçekleştirerek telefondaki verileri uyarıda bulunmadan silin"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"Cihaz genelinde geçerli proxy\'i ayarla"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"Politika etkin olduğunda kullanılacak cihaz genelinde geçerli proxy\'yi ayarlayın. Etkin genel proxy\'yi yalnızca ilk cihaz yöneticisi ayarlar."</string>
- <!-- no translation found for policylab_expirePassword (2314569545488269564) -->
- <skip />
- <!-- no translation found for policydesc_expirePassword (7276906351852798814) -->
- <skip />
+ <string name="policylab_expirePassword" msgid="2314569545488269564">"Şifre süre sonu tarihi ayarla"</string>
+ <string name="policydesc_expirePassword" msgid="7276906351852798814">"Ekran kilitleme şifresinin ne kadar süre sonra değiştirilmesi gerekeceğini denetleyin."</string>
<string-array name="phoneTypes">
<item msgid="8901098336658710359">"Ev"</item>
<item msgid="869923650527136615">"Mobil"</item>
@@ -668,8 +666,7 @@
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
- <!-- no translation found for autofill_address_summary_separator (7483307893170324129) -->
- <skip />
+ <string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<!-- no translation found for autofill_address_summary_format (4874459455786827344) -->
<skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"Tarayıcı geçmişini ve favorileri oku"</string>
@@ -869,6 +866,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"Çok sayıda SMS mesajı gönderiliyor. Devam etmek için \"Tamam\"ı, göndermeyi durdurmak için \"İptal\"i seçin."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"Tamam"</string>
<string name="sms_control_no" msgid="1715320703137199869">"İptal"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Ayarla"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Varsayılan"</string>
<string name="no_permissions" msgid="7283357728219338112">"İzin gerektirmez"</string>
@@ -876,8 +875,8 @@
<string name="perms_show_all" msgid="2671791163933091180"><b>"Tümünü göster"</b></string>
<string name="usb_storage_activity_title" msgid="2399289999608900443">"USB Yığın Depolama"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"USB bağlandı"</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Telefonunuzu USB ile bilgisayarınıza bağladınız. Bilgisayarınız ile Android\'inizin USB depolama birimi arasında dosya kopyalamak istiyorsanız aşağıdaki düğmeyi seçin."</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Telefonunuzu USB ile bilgisayarınıza bağladınız. Bilgisayarınız ile Android\'inizin USB depolama birimi arasında dosya kopyalamak istiyorsanız aşağıdaki düğmeyi seçin."</string>
+ <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"Cihazınızı USB ile bilgisayarınıza bağladınız. Bilgisayarınız ile Android\'inizin USB depolama birimi arasında dosya kopyalamak istiyorsanız aşağıdaki düğmeye dokunun."</string>
+ <string name="usb_storage_message" product="default" msgid="4510858346516069238">"Cihazınızı USB ile bilgisayarınıza bağladınız. Bilgisayarınız ile Android\'inizin SD kartı arasında dosya kopyalamak istiyorsanız aşağıdaki düğmeye dokunun."</string>
<string name="usb_storage_button_mount" msgid="1052259930369508235">"USB depolama birimini aç"</string>
<string name="usb_storage_error_message" product="nosdcard" msgid="3276413764430468454">"USB depolama biriminizi USB yığın depolama amaçlı kullanmayla ilgili bir sorun var."</string>
<string name="usb_storage_error_message" product="default" msgid="120810397713773275">"SD kartınızı USB yığın dep br amaçlı kullanmada sorun var."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index f9eacb9..a029694 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -925,6 +925,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"Надсил-ся завелика к-сть SMS повідомл. Натисн. \"OK\", щоб продовж, або \"Скасувати\", щоб припин. надсил."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Скасувати"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Устан."</string>
<string name="default_permission_group" msgid="2690160991405646128">"За умовч."</string>
<string name="no_permissions" msgid="7283357728219338112">"Дозвіл не потрібний"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index e33b7be..9c61058 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -925,6 +925,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"Một số lượng lớn các tin nhắn SMS đang được gửi. Chọn \"OK\" để tiếp tục hoặc \"Huỷ\" để dừng gửi."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
<string name="sms_control_no" msgid="1715320703137199869">"Huỷ"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"Đặt"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Mặc định"</string>
<string name="no_permissions" msgid="7283357728219338112">"Không yêu cầu quyền"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 031d488..e67e102 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -482,10 +482,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"恢复出厂设置时,将擦除手机上的数据而不发送警告"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"设置设备全局代理"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"请设置在启用政策的情况下要使用的设备全局代理。只有第一设备管理员才可设置有效的全局代理。"</string>
- <!-- no translation found for policylab_expirePassword (2314569545488269564) -->
- <skip />
- <!-- no translation found for policydesc_expirePassword (7276906351852798814) -->
- <skip />
+ <string name="policylab_expirePassword" msgid="2314569545488269564">"设置密码有效期"</string>
+ <string name="policydesc_expirePassword" msgid="7276906351852798814">"控制屏幕锁定密码的使用期限"</string>
<string-array name="phoneTypes">
<item msgid="8901098336658710359">"住宅"</item>
<item msgid="869923650527136615">"手机"</item>
@@ -668,8 +666,7 @@
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
- <!-- no translation found for autofill_address_summary_separator (7483307893170324129) -->
- <skip />
+ <string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<!-- no translation found for autofill_address_summary_format (4874459455786827344) -->
<skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"读取浏览器的历史记录和书签"</string>
@@ -869,6 +866,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"正在发送大量短信。选择“确定”继续,或选择“取消”停止发送。"</string>
<string name="sms_control_yes" msgid="2532062172402615953">"确定"</string>
<string name="sms_control_no" msgid="1715320703137199869">"取消"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"设置"</string>
<string name="default_permission_group" msgid="2690160991405646128">"默认"</string>
<string name="no_permissions" msgid="7283357728219338112">"不需要任何权限"</string>
@@ -876,8 +875,8 @@
<string name="perms_show_all" msgid="2671791163933091180"><b>"全部显示"</b></string>
<string name="usb_storage_activity_title" msgid="2399289999608900443">"USB 大容量存储设备"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"USB 已连接"</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"您已通过 USB 将手机连接至计算机。如果您要在计算机与 Android 手机的 USB 存储设备之间复制文件,请点击下面的按钮。"</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="default" msgid="4510858346516069238">"您已通过 USB 将手机连接至计算机。如果您要在计算机与 Android 手机的 USB 存储设备之间复制文件,请点击下面的按钮。"</string>
+ <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"您已通过 USB 连接至计算机。如果您要在计算机与 Android 设备的 USB 存储设备之间复制文件,请触摸下面的按钮。"</string>
+ <string name="usb_storage_message" product="default" msgid="4510858346516069238">"您已通过 USB 连接至计算机。如果您要在计算机和 Android 设备的 SD 卡之间复制文件,请触摸下面的按钮。"</string>
<string name="usb_storage_button_mount" msgid="1052259930369508235">"打开 USB 存储设备"</string>
<string name="usb_storage_error_message" product="nosdcard" msgid="3276413764430468454">"使用 USB 存储设备作为 USB 大容量存储设备时出现问题。"</string>
<string name="usb_storage_error_message" product="default" msgid="120810397713773275">"使用 SD 卡作为 USB 大容量存储设备时出现问题。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index c7cfe8e..bab4dfb 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -482,10 +482,8 @@
<string name="policydesc_wipeData" product="default" msgid="7669895333814222586">"執行重設為原廠設定時,系統會直接清除手機資料而不提出警告"</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"設定裝置全域 Proxy"</string>
<string name="policydesc_setGlobalProxy" msgid="6387497466660154931">"設定政策啟用時所要使用的裝置全域 Proxy,只有第一個裝置管理員所設定的全域 Proxy 具有效力。"</string>
- <!-- no translation found for policylab_expirePassword (2314569545488269564) -->
- <skip />
- <!-- no translation found for policydesc_expirePassword (7276906351852798814) -->
- <skip />
+ <string name="policylab_expirePassword" msgid="2314569545488269564">"設定密碼到期日"</string>
+ <string name="policydesc_expirePassword" msgid="7276906351852798814">"控制螢幕鎖定密碼的使用期限"</string>
<string-array name="phoneTypes">
<item msgid="8901098336658710359">"住家電話"</item>
<item msgid="869923650527136615">"行動電話"</item>
@@ -668,8 +666,7 @@
<string name="autofill_address_name_separator" msgid="2504700673286691795">" "</string>
<!-- no translation found for autofill_address_summary_name_format (3268041054899214945) -->
<skip />
- <!-- no translation found for autofill_address_summary_separator (7483307893170324129) -->
- <skip />
+ <string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<!-- no translation found for autofill_address_summary_format (4874459455786827344) -->
<skip />
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"讀取瀏覽器的記錄與書籤"</string>
@@ -869,6 +866,8 @@
<string name="sms_control_message" msgid="1289331457999236205">"即將傳送大量 SMS 簡訊。選取 [確定] 繼續或 [取消] 停止傳送。"</string>
<string name="sms_control_yes" msgid="2532062172402615953">"確定"</string>
<string name="sms_control_no" msgid="1715320703137199869">"取消"</string>
+ <!-- no translation found for time_picker_dialog_title (8349362623068819295) -->
+ <skip />
<string name="date_time_set" msgid="5777075614321087758">"設定"</string>
<string name="default_permission_group" msgid="2690160991405646128">"預設值"</string>
<string name="no_permissions" msgid="7283357728219338112">"無須許可"</string>
@@ -876,8 +875,8 @@
<string name="perms_show_all" msgid="2671791163933091180"><b>"顯示全部"</b></string>
<string name="usb_storage_activity_title" msgid="2399289999608900443">"USB 大量儲存裝置"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"USB 已連接"</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"已透過 USB 連接手機與電腦。如要在電腦和 Android 的 USB 儲存裝置之間複製檔案,請選取下方按鈕。"</string>
- <!-- outdated translation 115779324551502062 --> <string name="usb_storage_message" product="default" msgid="4510858346516069238">"已透過 USB 連接手機與電腦。如要在電腦和 Android 的 USB 儲存裝置之間複製檔案,請選取下方按鈕。"</string>
+ <string name="usb_storage_message" product="nosdcard" msgid="6631094834151575841">"您已透過 USB 與電腦建立連線。如要在電腦和 Android 的 USB 儲存裝置之間複製檔案,請輕觸下方按鈕。"</string>
+ <string name="usb_storage_message" product="default" msgid="4510858346516069238">"您已透過 USB 與電腦建立連線。如要在電腦和 Android 的 SD 卡之間複製檔案,請輕觸下方按鈕。"</string>
<string name="usb_storage_button_mount" msgid="1052259930369508235">"開啟 USB 儲存裝置"</string>
<string name="usb_storage_error_message" product="nosdcard" msgid="3276413764430468454">"使用您的 USB 儲存裝置作為 USB 大量儲存裝置時發生問題。"</string>
<string name="usb_storage_error_message" product="default" msgid="120810397713773275">"使用您的 SD 卡作為 USB 大量儲存裝置時發生問題。"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index dfbcafc0a..78465cf 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -602,9 +602,12 @@
<!-- Theme to use for alert dialogs spawned from this theme. -->
<attr name="alertDialogTheme" format="reference" />
- <!-- Drawable to use for vertical dividers. -->
+ <!-- Drawable to use for generic vertical dividers. -->
<attr name="dividerVertical" format="reference" />
+ <!-- Drawable to use for generic horizontal dividers. -->
+ <attr name="dividerHorizontal" format="reference" />
+
<!-- Style for button groups -->
<attr name="buttonGroupStyle" format="reference" />
@@ -614,6 +617,9 @@
<!-- Background drawable for standalone items that need focus/pressed states. -->
<attr name="selectableItemBackground" format="reference" />
+ <!-- Style for buttons without an explicit border, often used in groups. -->
+ <attr name="borderlessButtonStyle" format="reference" />
+
<!-- ============================ -->
<!-- SearchView styles and assets -->
<!-- ============================ -->
@@ -1293,6 +1299,11 @@
<attr name="bottomBright" format="reference|color" />
<attr name="bottomMedium" format="reference|color" />
<attr name="centerMedium" format="reference|color" />
+ <attr name="layout" />
+ <attr name="listLayout" format="reference" />
+ <attr name="multiChoiceItemLayout" format="reference" />
+ <attr name="singleChoiceItemLayout" format="reference" />
+ <attr name="listItemLayout" format="reference" />
</declare-styleable>
<!-- Fragment animation class attributes. -->
@@ -1674,6 +1685,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
@@ -2142,6 +2189,17 @@
the minimum size of the largest child. If false, all children are
measured normally. -->
<attr name="measureWithLargestChild" format="boolean" />
+ <!-- Drawable to use as a vertical divider between buttons. -->
+ <attr name="divider" />
+ <!-- Setting for which dividers to show. -->
+ <attr name="showDividers">
+ <flag name="none" value="0" />
+ <flag name="beginning" value="1" />
+ <flag name="middle" value="2" />
+ <flag name="end" value="4" />
+ </attr>
+ <!-- Size of padding on either end of a divider. -->
+ <attr name="dividerPadding" format="dimension" />
</declare-styleable>
<declare-styleable name="ListView">
<!-- Reference to an array resource that will populate the ListView. For static content,
@@ -2165,9 +2223,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. -->
@@ -3374,21 +3440,18 @@
greater than 0 or infinite. The default value is restart. -->
<attr name="repeatMode"/>
<!-- Value the animation starts from. -->
- <attr name="valueFrom" format="float|integer"/>
+ <attr name="valueFrom" format="float|integer|color|dimension"/>
<!-- Value the animation animates to. -->
- <attr name="valueTo" format="float|integer"/>
+ <attr name="valueTo" format="float|integer|color|dimension"/>
<!-- The type of valueFrom and valueTo. -->
<attr name="valueType">
- <!-- valueFrom and valueTo are floats. -->
+ <!-- valueFrom and valueTo are floats. This is the default value is valueType is
+ unspecified. Note that if either valueFrom or valueTo represent colors
+ (beginning with "#"), then this attribute is ignored and the color values are
+ interpreted as integers. -->
<enum name="floatType" value="0" />
<!-- valueFrom and valueTo are integers. -->
<enum name="intType" value="1" />
- <!-- valueFrom and valueTo are doubles. -->
- <enum name="doubleType" value="2" />
- <!-- valueFrom and valueTo are colors. -->
- <enum name="colorType" value="3" />
- <!-- valueFrom and valueTo are a custom type. -->
- <enum name="customType" value="4" />
</attr>
</declare-styleable>
@@ -4506,11 +4569,7 @@
<!-- Drawable to use as a background for buttons added to this group. -->
<attr name="buttonBackground" format="reference" />
<!-- Setting for which dividers to show. -->
- <attr name="showDividers">
- <flag name="beginning" value="1" />
- <flag name="middle" value="2" />
- <flag name="end" value="4" />
- </attr>
+ <attr name="showDividers" />
</declare-styleable>
<declare-styleable name="ActionBar_LayoutParams">
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index f2ab5cd..3fac653 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1382,6 +1382,20 @@
<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="attr" name="showDividers" />
+ <public type="attr" name="dividerPadding" />
+ <public type="attr" name="borderlessButtonStyle" />
+ <public type="attr" name="dividerHorizontal" />
<public type="anim" name="animator_fade_in" />
<public type="anim" name="animator_fade_out" />
@@ -1545,6 +1559,7 @@
<public type="style" name="Widget.Holo.Light.ActionMode" />
<public type="style" name="Widget.Holo.Light.ActionButton.CloseMode" />
<public type="style" name="Widget.Holo.Light.ActionBar" />
+ <public type="style" name="Widget.Holo.Button.Borderless" />
<public type="string" name="selectTextMode" />
</resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index b3c3e0d..b7c11a8 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. -->
@@ -1058,7 +1060,6 @@
</style>
<style name="TextAppearance.Holo.Medium" parent="TextAppearance.Medium">
- <item name="android:textLineHeight">24dip</item>
</style>
<style name="TextAppearance.Holo.Small" parent="TextAppearance.Small">
@@ -1302,6 +1303,10 @@
<item name="android:paddingBottom">4dip</item>
</style>
+ <style name="Widget.Holo.Button.Borderless">
+ <item name="android:background">?android:attr/selectableItemBackground</item>
+ </style>
+
<style name="Widget.Holo.Button.Small">
<item name="android:background">@android:drawable/btn_default_holo_dark</item>
<item name="android:textAppearance">?android:attr/textAppearanceSmall</item>
@@ -1331,7 +1336,7 @@
<style name="Widget.Holo.ButtonGroup" parent="Widget.ButtonGroup">
<item name="divider">?android:attr/dividerVertical</item>
<item name="showDividers">middle</item>
- <item name="android:background">@android:drawable/btn_default_holo_dark</item>
+ <item name="dividerPadding">8dip</item>
</style>
<style name="Widget.Holo.ButtonGroup.AlertDialog">
@@ -1699,7 +1704,7 @@
<style name="Widget.Holo.Light.ListView.DropDown">
</style>
- <style name="Widget.Holo.Light.EditText" parent="Widget.EditText">
+ <style name="Widget.Holo.Light.EditText" parent="Widget.Holo.EditText">
</style>
<style name="Widget.Holo.Light.ExpandableListView" parent="Widget.ExpandableListView">
@@ -1922,6 +1927,11 @@
<item name="bottomBright">@android:drawable/dialog_bottom_holo_dark</item>
<item name="bottomMedium">@android:drawable/dialog_bottom_holo_dark</item>
<item name="centerMedium">@android:drawable/dialog_middle_holo_dark</item>
+ <item name="layout">@android:layout/alert_dialog_holo</item>
+ <item name="listLayout">@android:layout/select_dialog_holo</item>
+ <item name="listItemLayout">@android:layout/select_dialog_item_holo</item>
+ <item name="multiChoiceItemLayout">@android:layout/select_dialog_multichoice_holo</item>
+ <item name="singleChoiceItemLayout">@android:layout/select_dialog_singlechoice_holo</item>
</style>
<style name="AlertDialog.Holo.Light">
@@ -1962,7 +1972,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 e1040d9..8c59360 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -92,6 +92,7 @@
<item name="groupButtonBackground">@null</item>
<item name="selectableItemBackground">@android:drawable/item_background</item>
+ <item name="borderlessButtonStyle">?android:attr/buttonStyle</item>
<item name="homeAsUpIndicator">@android:drawable/ic_ab_back_holo_dark</item>
<!-- List attributes -->
@@ -258,6 +259,7 @@
<item name="actionBarSize">56dip</item>
<item name="dividerVertical">@drawable/divider_vertical_dark</item>
+ <item name="dividerHorizontal">@drawable/divider_vertical_dark</item>
<item name="buttonGroupStyle">@android:style/Widget.ButtonGroup</item>
<!-- SearchView attributes -->
@@ -723,6 +725,7 @@
<item name="groupButtonBackground">@android:drawable/group_button_background_holo_dark</item>
<item name="selectableItemBackground">@android:drawable/item_background_holo_dark</item>
+ <item name="borderlessButtonStyle">@android:style/Widget.Holo.Button.Borderless</item>
<item name="homeAsUpIndicator">@android:drawable/ic_ab_back_holo_dark</item>
<!-- List attributes -->
@@ -883,6 +886,7 @@
<item name="actionBarSize">56dip</item>
<item name="dividerVertical">@drawable/divider_vertical_holo_dark</item>
+ <item name="dividerHorizontal">@drawable/divider_vertical_holo_dark</item>
<item name="buttonGroupStyle">@android:style/Widget.Holo.ButtonGroup</item>
<!-- SearchView attributes -->
@@ -1046,20 +1050,20 @@
<item name="textSelectHandleWindowStyle">@android:style/Widget.Holo.TextSelectHandle</item>
<!-- Widget styles -->
- <item name="absListViewStyle">@android:style/Widget.Holo.AbsListView</item>
+ <item name="absListViewStyle">@android:style/Widget.Holo.Light.AbsListView</item>
<item name="autoCompleteTextViewStyle">@android:style/Widget.Holo.Light.AutoCompleteTextView</item>
- <item name="checkboxStyle">@android:style/Widget.Holo.CompoundButton.CheckBox</item>
+ <item name="checkboxStyle">@android:style/Widget.Holo.Light.CompoundButton.CheckBox</item>
<item name="dropDownListViewStyle">@android:style/Widget.Holo.ListView.DropDown</item>
- <item name="editTextStyle">@android:style/Widget.Holo.EditText</item>
- <item name="expandableListViewStyle">@android:style/Widget.Holo.ExpandableListView</item>
- <item name="expandableListViewWhiteStyle">@android:style/Widget.Holo.ExpandableListView.White</item>
- <item name="galleryStyle">@android:style/Widget.Holo.Gallery</item>
- <item name="gestureOverlayViewStyle">@android:style/Widget.Holo.GestureOverlayView</item>
- <item name="gridViewStyle">@android:style/Widget.Holo.GridView</item>
- <item name="imageButtonStyle">@android:style/Widget.Holo.ImageButton</item>
- <item name="imageWellStyle">@android:style/Widget.Holo.ImageWell</item>
- <item name="listViewStyle">@android:style/Widget.Holo.ListView</item>
- <item name="listViewWhiteStyle">@android:style/Widget.Holo.ListView.White</item>
+ <item name="editTextStyle">@android:style/Widget.Holo.Light.EditText</item>
+ <item name="expandableListViewStyle">@android:style/Widget.Holo.Light.ExpandableListView</item>
+ <item name="expandableListViewWhiteStyle">@android:style/Widget.Holo.Light.ExpandableListView.White</item>
+ <item name="galleryStyle">@android:style/Widget.Holo.Light.Gallery</item>
+ <item name="gestureOverlayViewStyle">@android:style/Widget.Holo.Light.GestureOverlayView</item>
+ <item name="gridViewStyle">@android:style/Widget.Holo.Light.GridView</item>
+ <item name="imageButtonStyle">@android:style/Widget.Holo.Light.ImageButton</item>
+ <item name="imageWellStyle">@android:style/Widget.Holo.Light.ImageWell</item>
+ <item name="listViewStyle">@android:style/Widget.Holo.Light.ListView</item>
+ <item name="listViewWhiteStyle">@android:style/Widget.Holo.Light.ListView.White</item>
<item name="popupWindowStyle">@android:style/Widget.Holo.Light.PopupWindow</item>
<item name="progressBarStyle">@android:style/Widget.Holo.Light.ProgressBar</item>
<item name="progressBarStyleHorizontal">@android:style/Widget.Holo.Light.ProgressBar.Horizontal</item>
@@ -1069,22 +1073,22 @@
<item name="progressBarStyleInverse">@android:style/Widget.Holo.Light.ProgressBar.Inverse</item>
<item name="progressBarStyleSmallInverse">@android:style/Widget.Holo.Light.ProgressBar.Small.Inverse</item>
<item name="progressBarStyleLargeInverse">@android:style/Widget.Holo.Light.ProgressBar.Large.Inverse</item>
- <item name="seekBarStyle">@android:style/Widget.Holo.SeekBar</item>
- <item name="ratingBarStyle">@android:style/Widget.Holo.RatingBar</item>
- <item name="ratingBarStyleIndicator">@android:style/Widget.Holo.RatingBar.Indicator</item>
- <item name="ratingBarStyleSmall">@android:style/Widget.Holo.RatingBar.Small</item>
- <item name="radioButtonStyle">@android:style/Widget.Holo.CompoundButton.RadioButton</item>
- <item name="scrollViewStyle">@android:style/Widget.Holo.ScrollView</item>
- <item name="horizontalScrollViewStyle">@android:style/Widget.Holo.HorizontalScrollView</item>
+ <item name="seekBarStyle">@android:style/Widget.Holo.Light.SeekBar</item>
+ <item name="ratingBarStyle">@android:style/Widget.Holo.Light.RatingBar</item>
+ <item name="ratingBarStyleIndicator">@android:style/Widget.Holo.Light.RatingBar.Indicator</item>
+ <item name="ratingBarStyleSmall">@android:style/Widget.Holo.Light.RatingBar.Small</item>
+ <item name="radioButtonStyle">@android:style/Widget.Holo.Light.CompoundButton.RadioButton</item>
+ <item name="scrollViewStyle">@android:style/Widget.Holo.Light.ScrollView</item>
+ <item name="horizontalScrollViewStyle">@android:style/Widget.Holo.Light.HorizontalScrollView</item>
<item name="spinnerStyle">?android:attr/dropDownSpinnerStyle</item>
<item name="dropDownSpinnerStyle">@android:style/Widget.Holo.Light.Spinner.DropDown</item>
- <item name="starStyle">@android:style/Widget.Holo.CompoundButton.Star</item>
- <item name="tabWidgetStyle">@android:style/Widget.Holo.TabWidget</item>
- <item name="textViewStyle">@android:style/Widget.Holo.TextView</item>
- <item name="webTextViewStyle">@android:style/Widget.Holo.WebTextView</item>
- <item name="webViewStyle">@android:style/Widget.Holo.WebView</item>
- <item name="dropDownItemStyle">@android:style/Widget.Holo.DropDownItem</item>
- <item name="spinnerDropDownItemStyle">@android:style/Widget.Holo.DropDownItem.Spinner</item>
+ <item name="starStyle">@android:style/Widget.Holo.Light.CompoundButton.Star</item>
+ <item name="tabWidgetStyle">@android:style/Widget.Holo.Light.TabWidget</item>
+ <item name="textViewStyle">@android:style/Widget.Holo.Light.TextView</item>
+ <item name="webTextViewStyle">@android:style/Widget.Holo.Light.WebTextView</item>
+ <item name="webViewStyle">@android:style/Widget.Holo.Light.WebView</item>
+ <item name="dropDownItemStyle">@android:style/Widget.Holo.Light.DropDownItem</item>
+ <item name="spinnerDropDownItemStyle">@android:style/Widget.Holo.Light.DropDownItem.Spinner</item>
<item name="spinnerItemStyle">@android:style/Widget.Holo.TextView.SpinnerItem</item>
<item name="dropDownHintAppearance">@android:style/TextAppearance.Holo.Widget.DropDownHint</item>
<item name="keyboardViewStyle">@android:style/Widget.Holo.KeyboardView</item>
@@ -1128,6 +1132,7 @@
<item name="actionBarSize">56dip</item>
<item name="dividerVertical">@drawable/divider_vertical_holo_light</item>
+ <item name="dividerHorizontal">@drawable/divider_vertical_holo_light</item>
<item name="buttonGroupStyle">@android:style/Widget.Holo.Light.ButtonGroup</item>
<!-- SearchView attributes -->
diff --git a/core/tests/coretests/src/android/net/UriTest.java b/core/tests/coretests/src/android/net/UriTest.java
index c8ad60d..b878aa5 100644
--- a/core/tests/coretests/src/android/net/UriTest.java
+++ b/core/tests/coretests/src/android/net/UriTest.java
@@ -732,4 +732,20 @@ public class UriTest extends TestCase {
assertEquals(1, names.size());
assertEquals("foo", names.iterator().next());
}
+
+ /**
+ * Query parameters may omit the '='. http://b/3124097
+ */
+ public void testGetQueryParametersEmptyValue() {
+ assertEquals(Arrays.asList(""),
+ Uri.parse("http://foo/path?abc").getQueryParameters("abc"));
+ assertEquals(Arrays.asList(""),
+ Uri.parse("http://foo/path?foo=bar&abc").getQueryParameters("abc"));
+ assertEquals(Arrays.asList(""),
+ Uri.parse("http://foo/path?abcd=abc&abc").getQueryParameters("abc"));
+ assertEquals(Arrays.asList("a", "", ""),
+ Uri.parse("http://foo/path?abc=a&abc=&abc").getQueryParameters("abc"));
+ assertEquals(Arrays.asList("a", "", ""),
+ Uri.parse("http://foo/path?abc=a&abc=&abc=").getQueryParameters("abc"));
+ }
}
diff --git a/data/keyboards/Apple_Wireless_Keyboard.kl b/data/keyboards/Apple_Wireless_Keyboard.kl
index 9262a03..5234d58 100644
--- a/data/keyboards/Apple_Wireless_Keyboard.kl
+++ b/data/keyboards/Apple_Wireless_Keyboard.kl
@@ -101,7 +101,7 @@ key 108 DPAD_DOWN
key 109 PAGE_DOWN
key 110 NUMPAD_ENTER
key 111 FORWARD_DEL
-key 113 VALUME_MUTE
+key 113 VOLUME_MUTE
key 114 VOLUME_DOWN
key 115 VOLUME_UP
# key 120 switch applications
diff --git a/data/keyboards/Logitech_USB_Receiver.kl b/data/keyboards/Logitech_USB_Receiver.kl
index 23a8f54..aa7c0ee 100644
--- a/data/keyboards/Logitech_USB_Receiver.kl
+++ b/data/keyboards/Logitech_USB_Receiver.kl
@@ -105,7 +105,7 @@ key 108 DPAD_DOWN
key 109 PAGE_DOWN
key 110 NUMPAD_ENTER
key 111 FORWARD_DEL
-key 113 VALUME_MUTE
+key 113 VOLUME_MUTE
key 114 VOLUME_DOWN
key 115 VOLUME_UP
key 119 MEDIA_PAUSE
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/data/backup.jd b/docs/html/guide/topics/data/backup.jd
index 6c02031..623ee22 100644
--- a/docs/html/guide/topics/data/backup.jd
+++ b/docs/html/guide/topics/data/backup.jd
@@ -7,7 +7,9 @@ page.title=Data Backup
<h2>Quickview</h2>
<ul>
- <li>Back up your data to the cloud in case the user looses it</li>
+ <li>Back up the user's data to the cloud in case the user loses it</li>
+ <li>If the user upgrades to a new Android-powered device, your app can restore the user's
+data onto the new device</li>
<li>Easily back up SharedPreferences and private files with BackupAgentHelper</li>
<li>Requires API Level 8</li>
</ul>
@@ -389,7 +391,7 @@ conceptually a set of key-value pairs.</p>
<p>To add an entity to your backup data set, you must:</p>
<ol>
<li>Call {@link android.app.backup.BackupDataOutput#writeEntityHeader(String,int)
-writeEntityheader()}, passing a unique string key for the data you're about to write and the data
+writeEntityHeader()}, passing a unique string key for the data you're about to write and the data
size.</li>
<li>Call {@link android.app.backup.BackupDataOutput#writeEntityData(byte[],int)
writeEntityData()}, passing a byte buffer that contains your data and the number of bytes to write
@@ -403,8 +405,8 @@ single entity:</p>
ByteArrayOutputStream bufStream = new ByteArrayOutputStream();
DataOutputStream outWriter = new DataOutputStream(bufStream);
// Write structured data
-outWriter.writeString(playerName);
-outWriter.writeInt(playerScore);
+outWriter.writeUTF(mPlayerName);
+outWriter.writeInt(mPlayerScore);
// Send the data to the Backup Manager via the BackupDataOutput
byte[] buffer = bufStream.toByteArray();
int len = buffer.length;
@@ -422,10 +424,10 @@ android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,Pa
onBackup()} so you can determine whether another backup is necessary (as handled in step 1). If you
do not write the current data state to this file, then
{@code oldState} will be empty during the next callback.
- <p>Again, the following example saves a representation of the data using the file's
-last-modified timestamp:</p>
+ <p>The following example saves a representation of the current data into {@code newState} using
+the file's last-modified timestamp:</p>
<pre>
-FileOutputStream outstream = new FileOutputStream(stateFile.getFileDescriptor());
+FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
DataOutputStream out = new DataOutputStream(outstream);
long modified = mDataFile.lastModified();
@@ -493,7 +495,8 @@ onBackup()} is called after the device is restored.</dd>
<p>In your implementation of {@link
android.app.backup.BackupAgent#onRestore(BackupDataInput,int,ParcelFileDescriptor)
-onRestore()}, you should call {@link android.app.backup.BackupDataInput#readNextHeader()} to iterate
+onRestore()}, you should call {@link android.app.backup.BackupDataInput#readNextHeader()} on the
+{@code data} to iterate
through all entities in the data set. For each entity found, do the following:</p>
<ol>
@@ -517,6 +520,54 @@ android.app.backup.BackupAgent#onBackup(ParcelFileDescriptor,BackupDataOutput,Pa
onBackup()}.
</ol>
+<p>For example, here's how you can restore the data backed up by the example in the previous
+section:</p>
+
+<pre>
+&#64;Override
+public void onRestore(BackupDataInput data, int appVersionCode,
+ ParcelFileDescriptor newState) throws IOException {
+ // There should be only one entity, but the safest
+ // way to consume it is using a while loop
+ while (data.readNextHeader()) {
+ String key = data.getKey();
+ int dataSize = data.getDataSize();
+
+ // If the key is ours (for saving top score). Note this key was used when
+ // we wrote the backup entity header
+ if (TOPSCORE_BACKUP_KEY.equals(key)) {
+ // Create an input stream for the BackupDataInput
+ byte[] dataBuf = new byte[dataSize];
+ data.readEntityData(dataBuf, 0, dataSize);
+ ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf);
+ DataInputStream in = new DataInputStream(baStream);
+
+ // Read the player name and score from the backup data
+ mPlayerName = in.readUTF();
+ mPlayerScore = in.readInt();
+
+ // Record the score on the device (to a file or something)
+ recordScore(mPlayerName, mPlayerScore);
+ } else {
+ // We don't know this entity key. Skip it. (Shouldn't happen.)
+ data.skipEntityData();
+ }
+ }
+
+ // Finally, write to the state blob (newState) that describes the restored data
+ FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
+ DataOutputStream out = new DataOutputStream(outstream);
+ out.writeUTF(mPlayerName);
+ out.writeInt(mPlayerScore);
+}
+</pre>
+
+<p>In this example, the {@code appVersionCode} parameter passed to {@link
+android.app.backup.BackupAgent#onRestore onRestore()} is not used. However, you might want to use
+it if you've chosen to perform backup when the user's version of the application has actually moved
+backward (for example, the user went from version 1.5 of your app to 1.0). For more information, see
+the section about <a href="#RestoreVersion">Checking the Restore Data Version</a>.</p>
+
<div class="special">
<p>For an example implementation of {@link android.app.backup.BackupAgent}, see the <a
href="{@docRoot}resources/samples/BackupRestore/src/com/example/android/backuprestore/ExampleAgent.html">{@code
@@ -592,7 +643,8 @@ public class MyPrefsBackupAgent extends BackupAgentHelper {
static final String PREFS_BACKUP_KEY = "prefs";
// Allocate a helper and add it to the backup agent
- void onCreate() {
+ &#64;Override
+ public void onCreate() {
SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, PREFS);
addHelper(PREFS_BACKUP_KEY, helper);
}
diff --git a/docs/html/guide/topics/ui/actionbar.jd b/docs/html/guide/topics/ui/actionbar.jd
index c3d3482..44d75c1 100644
--- a/docs/html/guide/topics/ui/actionbar.jd
+++ b/docs/html/guide/topics/ui/actionbar.jd
@@ -455,7 +455,7 @@ Action Bar.</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
+ <li>Implement {@link android.app.ActionBar.OnNavigationListener} 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:
@@ -472,17 +472,17 @@ android.app.ActionBar#setListNavigationCallbacks setListNavigationCallbacks()}.
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>
+android.app.ActionBar.OnNavigationListener}. 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
+android.app.ActionBar.OnNavigationListener} 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
+android.widget.SpinnerAdapter} and {@link android.app.ActionBar.OnNavigationListener} to get you
started.</p>
@@ -520,24 +520,24 @@ defined as a resource looks like this:</p>
</pre>
-<h3 id="NavigationCallback">Example: simple NavigationCallback</h3>
+<h3 id="OnNavigationListener">Example: simple OnNavigationListener</h3>
-<p>Your implementation of {@link android.app.ActionBar.NavigationCallback} is where you handle
+<p>Your implementation of {@link android.app.ActionBar.OnNavigationListener} 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>
+android.app.ActionBar.OnNavigationListener#onNavigationItemSelected onNavigationItemSelected()}.</p>
<p>The {@link
-android.app.ActionBar.NavigationCallback#onNavigationItemSelected onNavigationItemSelected()}
+android.app.ActionBar.OnNavigationListener#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
+android.app.ActionBar.OnNavigationListener}, which inserts a {@link android.app.Fragment} into the
layout container identified by {@code R.id.fragment_container}:</p>
<pre>
-mNavigationCallback = new NavigationCallback() {
+mOnNavigationListener = new OnNavigationListener() {
// Get the same strings provided for the drop-down's ArrayAdapter
String[] strings = getResources().getStringArray(R.array.action_list);
@@ -556,7 +556,7 @@ mNavigationCallback = new NavigationCallback() {
};
</pre>
-<p>This instance of {@link android.app.ActionBar.NavigationCallback} can be given to {@link
+<p>This instance of {@link android.app.ActionBar.OnNavigationListener} can be given to {@link
android.app.ActionBar#setListNavigationCallbacks setListNavigationCallbacks()}, in step 4 from
above.</p>
diff --git a/docs/html/resources/dashboard/platform-versions.jd b/docs/html/resources/dashboard/platform-versions.jd
index cef057e..7416764 100644
--- a/docs/html/resources/dashboard/platform-versions.jd
+++ b/docs/html/resources/dashboard/platform-versions.jd
@@ -52,9 +52,8 @@ Android Market within a 14-day period ending on the data collection date noted b
<div class="dashboard-panel">
<img alt="" height="250" width="460"
-src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:7.9,15.0,0.1,40.8,36.2&chl=
-Android%201.5|Android%201.6|Other*|Android%202.1|Android%202.2&chco=c4df9b,
-6fad0c" />
+src="http://chart.apis.google.com/chart?&cht=p&chs=460x250&chd=t:6.3,10.6,0.1,39.6,43.4&chl
+=Android%201.5|Android%201.6|Other*|Android%202.1|Android%202.2&chco=c4df9b,6fad0c" />
<table>
<tr>
@@ -62,13 +61,13 @@ Android%201.5|Android%201.6|Other*|Android%202.1|Android%202.2&chco=c4df9b,
<th>API Level</th>
<th>Distribution</th>
</tr>
-<tr><td>Android 1.5</td><td>3</td><td>7.9%</td></tr>
-<tr><td>Android 1.6</td><td>4</td><td>15.0%</td></tr>
-<tr><td>Android 2.1</td><td>7</td><td>40.8%</td></tr>
-<tr><td>Android 2.2</td><td>8</td><td>36.2%</td></tr>
+<tr><td>Android 1.5</td><td>3</td><td>6.3%</td></tr>
+<tr><td>Android 1.6</td><td>4</td><td>10.6%</td></tr>
+<tr><td>Android 2.1</td><td>7</td><td>39.6%</td></tr>
+<tr><td>Android 2.2</td><td>8</td><td>43.4%</td></tr>
</table>
-<p><em>Data collected during two weeks ending on November 1, 2010</em></p>
+<p><em>Data collected during two weeks ending on December 1, 2010</em></p>
<p style="font-size:.9em">* <em>Other: 0.1% of devices running obsolete versions</em></p>
</div><!-- end dashboard-panel -->
@@ -97,17 +96,16 @@ Android Market within a 14-day period ending on the date indicated on the x-axis
<img alt="" height="250" width="660" style="padding:5px;background:#fff"
src="http://chart.apis.google.com/chart?&cht=lc&chs=660x250&chxt=x,y,r&chxr=0,0,12|1,0,100|2,0,100&
-chxl=0%3A%7C2010/05/01%7C05/15%7C06/01%7C06/15%7C07/01%7C07/15%7C08/01%7C08/15%7C09/01%7C09/15%7C10/
-01%7C10/15%7C2010/11/01%7C1%3A%7C0%25%7C25%25%7C50%25%7C75%25%7C100%25%7C2%3A%7C0%25%7C25%25%7C50%25
-%7C75%25%7C100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&chxtc=0,5&chd=t:98.9,99.3,100.3,100.8,99.7,99.
-8,99.8,99.7,99.8,99.9,99.9,99.9,99.9|61.6,63.1,72.7,76.1,78.4,80.9,84.3,86.5,87.9,89.2,90.2,91.1,92.
-0|32.0,34.9,45.9,51.0,54.9,58.8,64.0,68.1,70.3,72.1,73.8,75.3,77.0|0.0,0.0,0.8,1.2,1.8,3.3,4.3,11.3,
-27.8,32.1,33.4,34.5,36.2&chm=tAndroid%201.5,7caa36,0,0,15,,t::-5|b,c3df9b,0,1,0|tAndroid%201.6,
-5b831d,1,0,15,,t::-5|b,aadb5e,1,2,0|tAndroid%202.1,38540b,2,0,15,,t::-5|b,91da1e,2,3,0|tAndroid%202.
-2,131d02,3,7,15,,t::-5|B,6fad0c,3,4,0&chg=7,25&chdl=Android%201.5|Android%201.6|Android%202.1|
-Android%202.2&chco=add274,94d134,73ad18,507d08" />
-
-<p><em>Last historical dataset collected during two weeks ending on November 1, 2010</em></p>
+chxl=0:|2010/06/01|06/15|07/01|07/15|08/01|08/15|09/01|09/15|10/01|10/15|11/01|11/15|2010/12/01|1:|0
+%25|25%25|50%25|75%25|100%25|2:|0%25|25%25|50%25|75%25|100%25&chxp=0,0,1,2,3,4,5,6,7,8,9,10,11,12&
+chxtc=0,5&chd=t:100.3,100.8,99.7,99.8,99.8,99.7,99.8,99.9,99.9,99.9,99.9,99.9,99.9|72.7,76.1,78.4,80
+.9,84.3,86.5,87.9,89.2,90.2,91.1,92.0,92.7,93.6|45.9,51.0,54.9,58.8,64.0,68.1,70.3,72.1,73.8,75.3,77
+.0,79.0,83.0|0.8,1.2,1.8,3.3,4.3,11.3,27.8,32.1,33.4,34.5,36.2,38.3,43.4&chm=tAndroid%201.5,7caa36,0
+,0,15,,t::-5|b,c3df9b,0,1,0|tAndroid%201.6,5b831d,1,0,15,,t::-5|b,aadb5e,1,2,0|tAndroid%202.1,38540b
+,2,0,15,,t::-5|b,91da1e,2,3,0|tAndroid%202.2,131d02,3,5,15,,t::-5|B,6fad0c,3,4,0&chg=7,25&chdl=
+Android%201.5|Android%201.6|Android%202.1|Android%202.2&chco=add274,94d134,73ad18,507d08" />
+
+<p><em>Last historical dataset collected during two weeks ending on December 1, 2010</em></p>
</div><!-- end dashboard-panel -->
diff --git a/docs/html/sdk/ndk/index.jd b/docs/html/sdk/ndk/index.jd
index 0f36345..2c8e4c2 100644
--- a/docs/html/sdk/ndk/index.jd
+++ b/docs/html/sdk/ndk/index.jd
@@ -67,73 +67,71 @@ padding: .25em 1em;
width="9px" /> Android NDK, Revision 5</a> <em>(November 2010)</em>
<div class="toggleme">
- <dl>
- <dt>NDK r5 notes:</dt>
-
- <dd>
- <p>The r5 release of the NDK includes many new APIs, many of which are introduced to
- support native game development and applications that require similar requirements. Most
- notably, native activities are now supported, which allow you to write an application
- entirely with native code. For detailed information describing the changes in this
- release, read the CHANGES.HTML document included in the downloaded NDK package.</p>
- </dd>
- </dl>
-
+ <p>This release of the NDK includes many new APIs, most of which are introduced to
+ support the development of games and similar applications that make extensive use
+ of native code. Using the APIs, developers have direct native access to events, audio,
+ graphics and window management, assets, and storage. Developers can also implement the
+ Android application lifecycle in native code with help from the new
+ {@link android.app.NativeActivity} class. For detailed information describing the changes in this
+ release, read the CHANGES.HTML document included in the downloaded NDK package.
+ </p>
<dl>
<dt>General notes:</dt>
-
<dd>
<ul>
-
- <li>A new toolchain (based on GCC 4.4.3), which generates better code, and can also now
-be used as a standalone cross-compiler, for people who want to build their stuff with
-<code>./configure &amp;&amp; make</code>. See
-docs/STANDALONE-TOOLCHAIN.html for the details. The binaries for GCC 4.4.0 are still provided,
-but the 4.2.1 binaries were removed.</li>
-
- <li>Support for prebuilt static and shared libraries (docs/PREBUILTS.html), module
-exports and imports to make sharing and reuse of third-party modules much easier
-(docs/IMPORT-MODULE.html explains why).</li>
-
- <li>A C++ STL implementation (based on STLport) is now provided as a helper module. It
-can be used either as a static or shared library (details and usage exemple under
-sources/android/stlport/README). <strong>Note:</strong> For now, C++ Exceptions and RTTI are still
-not supported.</li>
-
- <li>Improvements to the <code>cpufeatures</code> helper library to deal with buggy
-kernel that incorrectly report they run on an ARMv7 CPU (while the device really is an ARMv6). We
-recommend developers that use it to simply rebuild their applications to benefit from it, then
-upload to Market.</li>
-
- <li>Adds support for native activities, which allows you to write completely native
- applications.</li>
-
- <li>Adds an EGL library that lets you create and manage OpenGL ES textures and
- services.</li>
+ <li>Adds support for native activities, which allows you to implement the
+ Android application lifecycle in native code.</li>
<li>Adds native support for the following:
<ul>
+
<li>Input subsystem (such as the keyboard and touch screen)</li>
+ <li>Access to sensor data (accelerometer, compass, gyroscope, etc).</li>
+
+ <li>Event loop APIs to wait for things such as input and sensor events.</li>
+
<li>Window and surface subsystem</li>
<li>Audio APIs based on the OpenSL ES standard that support playback and recording
as well as control over platform audio effects</li>
- <li>Event loop APIs to wait for things such as input and sensor events</li>
-
- <li>Access to assets packaged in the <code>.apk</code></li>
-
- <li>Access to sensor data (accelerometer, compass, gyroscope, etc.)</li>
+ <li>Access to assets packaged in an <code>.apk</code> file.</li>
+
</ul>
</li>
- <li>New sample applications, <code>native-plasma</code> and
- <code>native-activity</code>, to demonstrate how to write a native activity.</li>
-
- <li>Plus many bugfixes and other small improvements; see docs/CHANGES.html for a more
-detailed list of changes.</li>
+ <li>Includes a new toolchain (based on GCC 4.4.3), which generates better code, and can also now
+ be used as a standalone cross-compiler, for people who want to build their stuff with
+ <code>./configure &amp;&amp; make</code>. See
+ docs/STANDALONE-TOOLCHAIN.html for the details. The binaries for GCC 4.4.0 are still provided,
+ but the 4.2.1 binaries were removed.</li>
+
+ <li>Adds support for prebuilt static and shared libraries (docs/PREBUILTS.html) and module
+ exports and imports to make sharing and reuse of third-party modules much easier
+ (docs/IMPORT-MODULE.html explains why).</li>
+
+ <li>Provides a default C++ STL implementation (based on STLport) as a helper module. It can be used either
+ as a static or shared library (details and usage examples are in sources/android/stlport/README). Prebuilt
+ binaries for STLport (static or shared) and GNU libstdc++ (static only) are also provided if you choose to
+ compile against those libraries instead of the default C++ STL implementation.
+ C++ Exceptions and RTTI are not supported in the default STL implementation. For more information, see
+ docs/CPLUSPLUS-SUPPORT.HTML.</li>
+
+ <li>Includes improvements to the <code>cpufeatures</code> helper library that improves reporting
+ of the CPU type (some devices previously reported ARMv7 CPU when the device really was an ARMv6). We
+ recommend developers that use this library to rebuild their applications then
+ upload to Market to benefit from the improvements.</li>
+
+ <li>Adds an EGL library that lets you create and manage OpenGL ES textures and
+ services.</li>
+
+ <li>Adds new sample applications, <code>native-plasma</code> and <code>native-activity</code>,
+ to demonstrate how to write a native activity.</li>
+
+ <li>Includes many bugfixes and other small improvements; see docs/CHANGES.html for a more
+ detailed list of changes.</li>
</ul>
</dd>
</dl>
@@ -296,14 +294,13 @@ detailed list of changes.</li>
<h2 id="installing">Installing the NDK</h2>
<p>Installing the NDK on your development computer is straightforward and involves extracting the
- NDK from its download package. Unlike previous releases, there is no need to run a host-setup
- script.</p>
+ NDK from its download package.</p>
<p>Before you get started make sure that you have downloaded the latest <a href=
"{@docRoot}sdk/index.html">Android SDK</a> and upgraded your applications and environment as
- needed. The NDK will not work with older versions of the Android SDK. Also, take a moment to
- review the <a href="{@docRoot}sdk/ndk/reqs.html">System and Software Requirements</a> for the
- NDK, if you haven't already.</p>
+ needed. The NDK is compatible with older platform versions but not older versions of the SDK tools.
+ Also, take a moment to review the <a href="{@docRoot}sdk/ndk/reqs.html">System and Software Requirements</a>
+ for the NDK, if you haven't already.</p>
<p>To install the NDK, follow these steps:</p>
@@ -318,7 +315,7 @@ detailed list of changes.</li>
<code>&lt;ndk&gt;</code>.</li>
</ol>
- <p>You are now ready start working with the NDK.</p>
+ <p>You are now ready to start working with the NDK.</p>
<h2 id="gettingstarted">Getting Started with the NDK</h2>
@@ -342,8 +339,7 @@ detailed list of changes.</li>
<li>Build your native code by running the 'ndk-build' script from your project's directory. It
is located in the top-level NDK directory:
- <pre class="no-pretty-print">
-cd &lt;project&gt;
+ <pre class="no-pretty-print">cd &lt;project&gt;
&lt;ndk&gt;/ndk-build
</pre>
@@ -360,220 +356,10 @@ cd &lt;project&gt;
<h2 id="samples">Sample Applications</h2>
- <p>The NDK includes sample applications that illustrate how to use native code in your Android
- applications:</p>
-
- <ul>
- <li><code>hello-jni</code> &mdash; a simple application that loads a string from a native
- method implemented in a shared library and then displays it in the application UI.</li>
-
- <li><code>two-libs</code> &mdash; a simple application that loads a shared library dynamically
- and calls a native method provided by the library. In this case, the method is implemented in a
- static library imported by the shared library.</li>
-
- <li><code>san-angeles</code> &mdash; a simple application that renders 3D graphics through the
- native OpenGL ES APIs, while managing activity lifecycle with a {@link
- android.opengl.GLSurfaceView} object.</li>
-
- <li><code>hello-gl2</code> &mdash; a simple application that renders a triangle using OpenGL ES
- 2.0 vertex and fragment shaders.</li>
-
- <li><code>hello-neon</code> &mdash; a simple application that shows how to use the
- <code>cpufeatures</code> library to check CPU capabilities at runtime, then use NEON intrinsics
- if supported by the CPU. Specifically, the application implements two versions of a tiny
- benchmark for a FIR filter loop, a C version and a NEON-optimized version for devices that
- support it.</li>
-
- <li><code>bitmap-plasma</code> &mdash; a simple application that demonstrates how to access the
- pixel buffers of Android {@link android.graphics.Bitmap} objects from native code, and uses
- this to generate an old-school "plasma" effect.</li>
-
- <li><code>native-activity</code> &mdash; a simple application that demonstrates how to use the
- native-app-glue static library to create a native activity</li>
-
- <li><code>native-plasma</code> &mdash; a version of bitmap-plasma implemented with a native
- activity.</li>
- </ul>
-
- <p>For each sample, the NDK includes the corresponding C source code and the necessary Android.mk
- and Application.mk files. There are located under <code>&lt;ndk&gt;/samples/&lt;name&gt;/</code>
- and their source code can be found under <code>&lt;ndk&gt;/samples/&lt;name&gt;/jni/</code>.</p>
-
- <p>You can build the shared libraries for the sample apps by going into
- <code>&lt;ndk&gt;/samples/&lt;name&gt;/</code> then calling the <code>ndk-build</code> command.
- The generated shared libraries will be located under
- <code>&lt;ndk&gt;/samples/&lt;name&gt;/libs/armeabi/</code> for (ARMv5TE machine code) and/or
- <code>&lt;ndk&gt;/samples/&lt;name&gt;/libs/armeabi-v7a/</code> for (ARMv7 machine code).</p>
-
- <p>Next, build the sample Android applications that use the shared libraries:</p>
-
- <ul>
- <li>If you are developing in Eclipse with ADT, use the New Project Wizard to create a new
- Android project for each sample, using the "Import from Existing Source" option and importing
- the source from <code>&lt;ndk&gt;/apps/&lt;app_name&gt;/project/</code>. Then, set up an AVD,
- if necessary, and build/run the application in the emulator. For more information about
- creating a new Android project in Eclipse, see <a href=
- "{@docRoot}guide/developing/eclipse-adt.html">Developing in Eclipse</a>.</li>
-
- <li>If you are developing with Ant, use the <code>android</code> tool to create the build file
- for each of the sample projects at <code>&lt;ndk&gt;/apps/&lt;app_name&gt;/project/</code>.
- Then set up an AVD, if necessary, build your project in the usual way, and run it in the
- emulator. For more information, see <a href=
- "{@docRoot}guide/developing/other-ide.html">Developing in Other IDEs</a>.</li>
- </ul>
-
- <h3 id="hello-jni">Exploring the hello-jni Sample</h3>
-
- <p>The hello-jni sample is a simple demonstration on how to use JNI from an Android application.
- The HelloJni activity receives a string from a simple C function and displays it in a
- TextView.</p>
-
- <p>The main components of the sample include:</p>
-
- <ul>
- <li>The familiar basic structure of an Android application (an <code>AndroidManifest.xml</code>
- file, a <code>src/</code> and <code>res</code> directories, and a main activity)</li>
-
- <li>A <code>jni/</code> directory that includes the implemented source file for the native code
- as well as the Android.mk file</li>
-
- <li>A <code>tests/</code> directory that contains unit test code.</li>
- </ul>
-
- <ol>
- <li>Create a new project in Eclipse from the existing sample source or use the
- <code>android</code> tool to update the project so it generates a build.xml file that you can
- use to build the sample.
-
- <ul>
- <li>In Eclipse:
-
- <ol type="a">
- <li>Click <strong>File &gt; New Android Project...</strong></li>
+ <p>The NDK includes sample Android applications that illustrate how to use native code in your
+ Android applications. For more information, see <a href=
+ "{@docRoot}sdk/ndk/overview.html#samples">Sample Applications</a>.</p>
- <li>Select the <strong>Create project from existing source</strong> radio button.</li>
-
- <li>Select any API level above Android 1.5.</li>
-
- <li>In the <strong>Location</strong> field, click <strong>Browse...</strong> and select
- the <code>&lt;ndk-root&gt;/samples/hello-jni</code> directory.</li>
-
- <li>Click <strong>Finish</strong>.</li>
- </ol>
- </li>
-
- <li>On the command line:
-
- <ol type="a">
- <li>Change to the <code>&lt;ndk-root&gt;/samples/hello-jni</code> directory.</li>
-
- <li>Run the following command to generate a build.xml file:
- <pre class="no-pretty-print">
-android update project -p . -s
-</pre>
- </li>
- </ol>
- </li>
- </ul>
- </li>
-
- <li>Compile the native code using the <code>ndk-build</code> command.
- <pre class="no-pretty-print">
-cd &lt;ndk-root&gt;/samples/hello-jni
-&lt;ndk_root&gt;/ndk-build
-</pre>
- </li>
-
- <li>Build and install the application as you would a normal Android application. If you are
- using Eclipse, run the application to build and install it on a device. If you are using Ant,
- run the following commands from the project directory:
- <pre class="no-pretty-print">
-ant debug
-adb install bin/HelloJni-debug.apk
-</pre>
- </li>
- </ol>
-
- <p>When you run the application on the device, the string <code>Hello JNI</code> should appear on
- your device. You can explore the rest of the samples that are located in the
- <code>&lt;ndk-root&gt;/samples</code> directory for more examples on how to use the JNI.</p>
-
- <h3 id="native-activity">Exploring the native-activity Sample Application</h3>
-
- <p>The native-activity sample provided with the Android NDK demonstrates how to use the
- android_native_app_glue static library. This static library makes creating a native activity
- easier by providing you with an implementation that handles your callbacks in another thread, so
- you do not have to worry about them blocking your main UI thread. The main parts of the sample
- are described below:</p>
-
- <ul>
- <li>The familiar basic structure of an Android application (an <code>AndroidManifest.xml</code>
- file, a <code>src/</code> and <code>res</code> directories). The AndroidManifest.xml declares
- that the application is native and specifies the .so file of the native activity. See {@link
- android.app.NativeActivity} for the source or see the
- <code>&lt;ndk_root&gt;/platforms/samples/native-activity/AndroidManifest.xml</code> file.</li>
-
- <li>A <code>jni/</code> directory contains the native activity, main.c, which uses the
- <code>android_native_app_glue.h</code> interface to implement the activity. The Android.mk that
- describes the native module to the build system also exists here.</li>
- </ul>
-
- <p>To build this sample application:</p>
-
- <ol>
- <li>Create a new project in Eclipse from the existing sample source or use the
- <code>android</code> tool to update the project so it generates a build.xml file that you can
- use to build the sample.
-
- <ul>
- <li>In Eclipse:
-
- <ol type="a">
- <li>Click <strong>File &gt; New Android Project...</strong></li>
-
- <li>Select the <strong>Create project from existing source</strong> radio button.</li>
-
- <li>Select any API level above Android 2.3.</li>
-
- <li>In the <strong>Location</strong> field, click <strong>Browse...</strong> and select
- the <code>&lt;ndk-root&gt;/samples/native-activity</code> directory.</li>
-
- <li>Click <strong>Finish</strong>.</li>
- </ol>
- </li>
-
- <li>On the command line:
-
- <ol type="a">
- <li>Change to the <code>&lt;ndk-root&gt;/samples/native-activity</code> directory.</li>
-
- <li>Run the following command to generate a build.xml file:
- <pre class="no-pretty-print">
-android update project -p . -s
-</pre>
- </li>
- </ol>
- </li>
- </ul>
- </li>
-
- <li>Compile the native code using the <code>ndk-build</code> command.
- <pre class="no-pretty-print">
-cd &lt;ndk-root&gt;/platforms/samples/android-9/samples/native-activity
-&lt;ndk_root&gt;/ndk-build
-</pre>
- </li>
-
- <li>Build and install the application as you would a normal Android application. If you are
- using Eclipse, run the application to build and install it on a device. If you are using Ant,
- run the following commands in the project directory, then run the application on the device:
- <pre class="no-pretty-print">
-ant debug
-adb install bin/NativeActivity-debug.apk
-</pre>
- </li>
- </ol>
-
<h2 id="forum">Discussion Forum and Mailing List</h2>
<p>If you have questions about the NDK or would like to read or contribute to discussions about
diff --git a/docs/html/sdk/ndk/overview.jd b/docs/html/sdk/ndk/overview.jd
index a7ec5d4..f6d148a 100644
--- a/docs/html/sdk/ndk/overview.jd
+++ b/docs/html/sdk/ndk/overview.jd
@@ -7,10 +7,8 @@ page.title=What is the NDK?
<ol>
<li><a href="#choosing">When to Develop in Native Code</a></li>
-
<li>
<a href="#contents">Contents of the NDK</a>
-
<ol>
<li><a href="#tools">Development tools</a></li>
@@ -19,9 +17,7 @@ page.title=What is the NDK?
<li><a href="#samples">Sample applications</a></li>
</ol>
</li>
-
<li><a href="#reqs">System and Software Requirements</a></li>
-
</ol>
</div>
</div>
@@ -102,9 +98,8 @@ page.title=What is the NDK?
later.</li>
<li>
- <p>Write a native activity, which allows you to potentially create an application completely in native
- code, because you can implement the lifecycle callbacks natively. The Android SDK provides
- the {@link android.app.NativeActivity} class, which is a convenience class that notifies your
+ <p>Write a native activity, which allows you to implement the lifecycle callbacks in native
+ code. The Android SDK provides the {@link android.app.NativeActivity} class, which is a convenience class that notifies your
native code of any activity lifecycle callbacks (<code>onCreate()</code>, <code>onPause()</code>,
<code>onResume()</code>, etc). You can implement the callbacks in your native code to handle
these events when they occur. Applications that use native activities must be run on Android
@@ -142,6 +137,10 @@ page.title=What is the NDK?
<li>libjnigraphics (Pixel buffer access) header (for Android 2.2 and above).</li>
<li>A Minimal set of headers for C++ support</li>
+
+ <li>OpenSL ES native audio libraries</li>
+
+ <li>Android native application APIS</li>
</ul>
<p>The NDK also provides a build system that lets you work efficiently with your sources, without
@@ -163,25 +162,18 @@ page.title=What is the NDK?
the <code>&lt;ndk&gt;/docs/</code> directory. Included are these files:</p>
<ul>
- <li>INSTALL.HTML &mdash; describes how to install the NDK and configure it for your host
+ <li>
+ INSTALL.HTML &mdash; describes how to install the NDK and configure it for your host
system</li>
<li>OVERVIEW.HTML &mdash; provides an overview of the NDK capabilities and usage</li>
-
+
<li>ANDROID-MK.HTML &mdash; describes the use of the Android.mk file, which defines the native
sources you want to compile</li>
-
+
<li>APPLICATION-MK.HTML &mdash; describes the use of the Application.mk file, which describes
- the native sources required by your Android application</li>
-
- <li>HOWTO.HTML &mdash; information about common tasks associated with NDK development.</li>
-
- <li>SYSTEM-ISSUES.HTML &mdash; known issues in the Android system images that you should be
- aware of, if you are developing using the NDK.</li>
-
- <li>STABLE-APIS.HTML &mdash; a complete list of the stable APIs exposed by headers in the
- NDK.</li>
-
+ the native sources required by your Android application</li>
+ <li>CPLUSPLUS-SUPPORT.HTML &mdash; describes the C++ support provided in the Android NDK</li>
<li>CPU-ARCH-ABIS.HTML &mdash; a description of supported CPU architectures and how to target
them.</li>
@@ -193,6 +185,32 @@ page.title=What is the NDK?
instructions.</li>
<li>CHANGES.HTML &mdash; a complete list of changes to the NDK across all releases.</li>
+
+ <li>DEVELOPMENT.HTML &mdash; describes how to modify the NDK and generate release packages for it</li>
+
+ <li>HOWTO.HTML &mdash; information about common tasks associated with NDK development</li>
+
+ <li>IMPORT-MODULE.HTML &mdash; describes how to share and reuse modules</li>
+
+ <li>LICENSES.HTML &mdash; information about the various open source licenses that govern the Android NDK</li>
+
+ <li>NATIVE-ACTIVITY.HTML &mdash; describes how to implement native activities</li>
+
+ <li>NDK-BUILD.HTML &mdash; describes the usage of the ndk-build script</li>
+
+ <li>NDK-GDB.HTML &mdash; describes how to use the native code debugger</li>
+
+ <li>PREBUILTS.HTML &mdash; information about how shared and static prebuilt libraries work </li>
+
+ <li>STANDALONE-TOOLCHAIN.HTML &mdash; describes how to use Android NDK toolchain as a standalone
+ compiler (still in beta).</li>
+
+ <li>SYSTEM-ISSUES.HTML &mdash; known issues in the Android system images that you should be
+ aware of, if you are developing using the NDK.</li>
+
+ <li>STABLE-APIS.HTML &mdash; a complete list of the stable APIs exposed by headers in the
+ NDK.</li>
+
</ul>
<p>Additionally, the package includes detailed information about the "bionic" C library provided
@@ -206,9 +224,218 @@ page.title=What is the NDK?
<h3 id="samples">Sample applications</h3>
- <p>The NDK includes sample Android applications that illustrate how to use native code in your
- Android applications. For more information, see <a href=
- "{@docRoot}sdk/ndk/installing.html#samples">Sample Applications</a>.</p>
+<p>The NDK includes sample applications that illustrate how to use native code in your Android
+ applications:</p>
+
+ <ul>
+ <li><code>hello-jni</code> &mdash; a simple application that loads a string from a native
+ method implemented in a shared library and then displays it in the application UI.</li>
+
+ <li><code>two-libs</code> &mdash; a simple application that loads a shared library dynamically
+ and calls a native method provided by the library. In this case, the method is implemented in a
+ static library imported by the shared library.</li>
+
+ <li><code>san-angeles</code> &mdash; a simple application that renders 3D graphics through the
+ native OpenGL ES APIs, while managing activity lifecycle with a {@link
+ android.opengl.GLSurfaceView} object.</li>
+
+ <li><code>hello-gl2</code> &mdash; a simple application that renders a triangle using OpenGL ES
+ 2.0 vertex and fragment shaders.</li>
+
+ <li><code>hello-neon</code> &mdash; a simple application that shows how to use the
+ <code>cpufeatures</code> library to check CPU capabilities at runtime, then use NEON intrinsics
+ if supported by the CPU. Specifically, the application implements two versions of a tiny
+ benchmark for a FIR filter loop, a C version and a NEON-optimized version for devices that
+ support it.</li>
+
+ <li><code>bitmap-plasma</code> &mdash; a simple application that demonstrates how to access the
+ pixel buffers of Android {@link android.graphics.Bitmap} objects from native code, and uses
+ this to generate an old-school "plasma" effect.</li>
+
+ <li><code>native-activity</code> &mdash; a simple application that demonstrates how to use the
+ native-app-glue static library to create a native activity</li>
+
+ <li><code>native-plasma</code> &mdash; a version of bitmap-plasma implemented with a native
+ activity.</li>
+ </ul>
+
+ <p>For each sample, the NDK includes the corresponding C source code and the necessary Android.mk
+ and Application.mk files. There are located under <code>&lt;ndk&gt;/samples/&lt;name&gt;/</code>
+ and their source code can be found under <code>&lt;ndk&gt;/samples/&lt;name&gt;/jni/</code>.</p>
+
+ <p>You can build the shared libraries for the sample apps by going into
+ <code>&lt;ndk&gt;/samples/&lt;name&gt;/</code> then calling the <code>ndk-build</code> command.
+ The generated shared libraries will be located under
+ <code>&lt;ndk&gt;/samples/&lt;name&gt;/libs/armeabi/</code> for (ARMv5TE machine code) and/or
+ <code>&lt;ndk&gt;/samples/&lt;name&gt;/libs/armeabi-v7a/</code> for (ARMv7 machine code).</p>
+
+ <p>Next, build the sample Android applications that use the shared libraries:</p>
+
+ <ul>
+ <li>If you are developing in Eclipse with ADT, use the New Project Wizard to create a new
+ Android project for each sample, using the "Import from Existing Source" option and importing
+ the source from <code>&lt;ndk&gt;/apps/&lt;app_name&gt;/project/</code>. Then, set up an AVD,
+ if necessary, and build/run the application in the emulator. For more information about
+ creating a new Android project in Eclipse, see <a href=
+ "{@docRoot}guide/developing/eclipse-adt.html">Developing in Eclipse</a>.</li>
+
+ <li>If you are developing with Ant, use the <code>android</code> tool to create the build file
+ for each of the sample projects at <code>&lt;ndk&gt;/apps/&lt;app_name&gt;/project/</code>.
+ Then set up an AVD, if necessary, build your project in the usual way, and run it in the
+ emulator. For more information, see <a href=
+ "{@docRoot}guide/developing/other-ide.html">Developing in Other IDEs</a>.</li>
+ </ul>
+
+ <h4 id="hello-jni">Exploring the hello-jni Sample</h4>
+
+ <p>The hello-jni sample is a simple demonstration on how to use JNI from an Android application.
+ The HelloJni activity receives a string from a simple C function and displays it in a
+ TextView.</p>
+
+ <p>The main components of the sample include:</p>
+
+ <ul>
+ <li>The familiar basic structure of an Android application (an <code>AndroidManifest.xml</code>
+ file, a <code>src/</code> and <code>res</code> directories, and a main activity)</li>
+
+ <li>A <code>jni/</code> directory that includes the implemented source file for the native code
+ as well as the Android.mk file</li>
+
+ <li>A <code>tests/</code> directory that contains unit test code.</li>
+ </ul>
+
+ <ol>
+ <li>Create a new project in Eclipse from the existing sample source or use the
+ <code>android</code> tool to update the project so it generates a build.xml file that you can
+ use to build the sample.
+
+ <ul>
+ <li>In Eclipse:
+
+ <ol type="a">
+ <li>Click <strong>File &gt; New Android Project...</strong></li>
+
+ <li>Select the <strong>Create project from existing source</strong> radio button.</li>
+
+ <li>Select any API level above Android 1.5.</li>
+
+ <li>In the <strong>Location</strong> field, click <strong>Browse...</strong> and select
+ the <code>&lt;ndk-root&gt;/samples/hello-jni</code> directory.</li>
+
+ <li>Click <strong>Finish</strong>.</li>
+ </ol>
+ </li>
+
+ <li>On the command line:
+
+ <ol type="a">
+ <li>Change to the <code>&lt;ndk-root&gt;/samples/hello-jni</code> directory.</li>
+
+ <li>Run the following command to generate a build.xml file:
+ <pre class="no-pretty-print">android update project -p . -s</pre>
+ </li>
+ </ol>
+ </li>
+ </ul>
+ </li>
+
+ <li>Compile the native code using the <code>ndk-build</code> command.
+ <pre class="no-pretty-print">
+cd &lt;ndk-root&gt;/samples/hello-jni
+&lt;ndk_root&gt;/ndk-build
+</pre>
+ </li>
+
+ <li>Build and install the application as you would a normal Android application. If you are
+ using Eclipse, run the application to build and install it on a device. If you are using Ant,
+ run the following commands from the project directory:
+ <pre class="no-pretty-print">
+ant debug
+adb install bin/HelloJni-debug.apk
+</pre>
+ </li>
+ </ol>
+
+ <p>When you run the application on the device, the string <code>Hello JNI</code> should appear on
+ your device. You can explore the rest of the samples that are located in the
+ <code>&lt;ndk-root&gt;/samples</code> directory for more examples on how to use the JNI.</p>
+
+ <h4 id="native-activity">Exploring the native-activity Sample Application</h4>
+
+ <p>The native-activity sample provided with the Android NDK demonstrates how to use the
+ android_native_app_glue static library. This static library makes creating a native activity
+ easier by providing you with an implementation that handles your callbacks in another thread, so
+ you do not have to worry about them blocking your main UI thread. The main parts of the sample
+ are described below:</p>
+
+ <ul>
+ <li>The familiar basic structure of an Android application (an <code>AndroidManifest.xml</code>
+ file, a <code>src/</code> and <code>res</code> directories). The AndroidManifest.xml declares
+ that the application is native and specifies the .so file of the native activity. See {@link
+ android.app.NativeActivity} for the source or see the
+ <code>&lt;ndk_root&gt;/platforms/samples/native-activity/AndroidManifest.xml</code> file.</li>
+
+ <li>A <code>jni/</code> directory contains the native activity, main.c, which uses the
+ <code>android_native_app_glue.h</code> interface to implement the activity. The Android.mk that
+ describes the native module to the build system also exists here.</li>
+ </ul>
+
+ <p>To build this sample application:</p>
+
+ <ol>
+ <li>Create a new project in Eclipse from the existing sample source or use the
+ <code>android</code> tool to update the project so it generates a build.xml file that you can
+ use to build the sample.
+
+ <ul>
+ <li>In Eclipse:
+
+ <ol type="a">
+ <li>Click <strong>File &gt; New Android Project...</strong></li>
+
+ <li>Select the <strong>Create project from existing source</strong> radio button.</li>
+
+ <li>Select any API level above Android 2.3.</li>
+
+ <li>In the <strong>Location</strong> field, click <strong>Browse...</strong> and select
+ the <code>&lt;ndk-root&gt;/samples/native-activity</code> directory.</li>
+
+ <li>Click <strong>Finish</strong>.</li>
+ </ol>
+ </li>
+
+ <li>On the command line:
+
+ <ol type="a">
+ <li>Change to the <code>&lt;ndk-root&gt;/samples/native-activity</code> directory.</li>
+
+ <li>Run the following command to generate a build.xml file:
+ <pre class="no-pretty-print">
+android update project -p . -s
+</pre>
+ </li>
+ </ol>
+ </li>
+ </ul>
+ </li>
+
+ <li>Compile the native code using the <code>ndk-build</code> command.
+ <pre class="no-pretty-print">
+cd &lt;ndk-root&gt;/platforms/samples/android-9/samples/native-activity
+&lt;ndk_root&gt;/ndk-build
+</pre>
+ </li>
+
+ <li>Build and install the application as you would a normal Android application. If you are
+ using Eclipse, run the application to build and install it on a device. If you are using Ant,
+ run the following commands in the project directory, then run the application on the device:
+ <pre class="no-pretty-print">
+ant debug
+adb install bin/NativeActivity-debug.apk
+</pre>
+ </li>
+ </ol>
+
<h2 id="reqs">System and Software Requirements</h2>
@@ -313,7 +540,7 @@ page.title=What is the NDK?
to users whose devices are capable of supporting your application. For example:
<pre style="margin:1em;">
&lt;manifest&gt;
- ...
+ ...
<!-- Declare that the application uses the OpenGL ES 2.0 API and is designed
to run only on devices that support OpenGL ES 2.0 or higher. -->
&lt;uses-feature android:glEsVersion="0x00020000" /&gt;
@@ -331,4 +558,4 @@ page.title=What is the NDK?
containing the library can be deployed only to devices running Android 2.2 (API level 8) or
higher. To ensure compatibility, make sure that your application declares <code>&lt;uses-sdk
android:minSdkVersion="8" /&gt;</code> attribute value in its manifest.</li>
- </ul> \ No newline at end of file
+ </ul>
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index 6364d58..431aaa47 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -79,6 +79,14 @@ public:
// the camera only has a single output, and does not have
// separate output for video frames and preview frame.
void getSupportedVideoSizes(Vector<Size> &sizes) const;
+ // Retrieve the preferred preview size (width and height) in pixels
+ // for video recording. The given width and height must be one of
+ // supported preview sizes returned from getSupportedPreviewSizes().
+ // Must not be called if getSupportedVideoSizes() returns an empty
+ // Vector of Size. If getSupportedVideoSizes() returns an empty
+ // Vector of Size, the width and height returned from this method
+ // is invalid, and is "-1x-1".
+ void getPreferredPreviewSizeForVideo(int *width, int *height) const;
void setPreviewFrameRate(int fps);
int getPreviewFrameRate() const;
@@ -319,6 +327,21 @@ public:
// frameworks/base/include/camera/Camera.h.
// Example: "176x144,1280x720". Read only.
static const char KEY_SUPPORTED_VIDEO_SIZES[];
+
+ // Preferred preview frame size in pixels for video recording.
+ // The width and height must be one of the supported sizes retrieved
+ // via KEY_SUPPORTED_PREVIEW_SIZES. This key can be used only when
+ // getSupportedVideoSizes() does not return an empty Vector of Size.
+ // Camcorder applications are recommended to set the preview size
+ // to a value that is not larger than the preferred preview size.
+ // In other words, the product of the width and height of the
+ // preview size should not be larger than that of the preferred
+ // preview size. In addition, we recommend to choos a preview size
+ // that has the same aspect ratio as the resolution of video to be
+ // recorded.
+ // Example value: "800x600". Read only.
+ static const char KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO[];
+
// The image format for video frames. See CAMERA_MSG_VIDEO_FRAME in
// frameworks/base/include/camera/Camera.h.
// Example value: "yuv420sp" or PIXEL_FORMAT_XXX constants. Read only.
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/camera/CameraParameters.cpp b/libs/camera/CameraParameters.cpp
index 45b1b9a..e9a5f8c 100644
--- a/libs/camera/CameraParameters.cpp
+++ b/libs/camera/CameraParameters.cpp
@@ -75,6 +75,7 @@ const char CameraParameters::KEY_FOCUS_DISTANCES[] = "focus-distances";
const char CameraParameters::KEY_VIDEO_FRAME_FORMAT[] = "video-frame-format";
const char CameraParameters::KEY_VIDEO_SIZE[] = "video-size";
const char CameraParameters::KEY_SUPPORTED_VIDEO_SIZES[] = "video-size-values";
+const char CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO[] = "preferred-preview-size-for-video";
const char CameraParameters::TRUE[] = "true";
const char CameraParameters::FOCUS_DISTANCE_INFINITY[] = "Infinity";
@@ -333,6 +334,14 @@ void CameraParameters::getPreviewSize(int *width, int *height) const
parse_pair(p, width, height, 'x');
}
+void CameraParameters::getPreferredPreviewSizeForVideo(int *width, int *height) const
+{
+ *width = *height = -1;
+ const char *p = get(KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO);
+ if (p == 0) return;
+ parse_pair(p, width, height, 'x');
+}
+
void CameraParameters::getSupportedPreviewSizes(Vector<Size> &sizes) const
{
const char *previewSizesStr = get(KEY_SUPPORTED_PREVIEW_SIZES);
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/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/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 69b872b..e17a640 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -992,7 +992,12 @@ public class MediaScanner
private boolean inScanDirectory(String path, String[] directories) {
for (int i = 0; i < directories.length; i++) {
- if (path.startsWith(directories[i])) {
+ String directory = directories[i];
+ if (mExternalStoragePath != null && directory.equals(mMediaStoragePath)) {
+ // database paths use external storage prefix
+ directory = mExternalStoragePath;
+ }
+ if (path.startsWith(directory)) {
return true;
}
}
diff --git a/media/java/android/media/MtpDatabase.java b/media/java/android/media/MtpDatabase.java
index 0387989..139a6ea 100644
--- a/media/java/android/media/MtpDatabase.java
+++ b/media/java/android/media/MtpDatabase.java
@@ -33,6 +33,7 @@ import android.provider.MediaStore.MediaColumns;
import android.util.Log;
import java.io.File;
+import java.util.HashMap;
/**
* {@hide}
@@ -48,6 +49,14 @@ public class MtpDatabase {
private final String mMediaStoragePath;
private final String mExternalStoragePath;
+ // cached property groups for single properties
+ private final HashMap<Integer, MtpPropertyGroup> mPropertyGroupsByProperty
+ = new HashMap<Integer, MtpPropertyGroup>();
+
+ // cached property groups for all properties for a given format
+ private final HashMap<Integer, MtpPropertyGroup> mPropertyGroupsByFormat
+ = new HashMap<Integer, MtpPropertyGroup>();
+
// true if the database has been modified in the current MTP session
private boolean mDatabaseModified;
@@ -386,6 +395,43 @@ public class MtpDatabase {
MtpConstants.PROPERTY_DESCRIPTION,
};
+ static final int[] ALL_PROPERTIES = {
+ // NOTE must match FILE_PROPERTIES above
+ MtpConstants.PROPERTY_STORAGE_ID,
+ MtpConstants.PROPERTY_OBJECT_FORMAT,
+ MtpConstants.PROPERTY_PROTECTION_STATUS,
+ MtpConstants.PROPERTY_OBJECT_SIZE,
+ MtpConstants.PROPERTY_OBJECT_FILE_NAME,
+ MtpConstants.PROPERTY_DATE_MODIFIED,
+ MtpConstants.PROPERTY_PARENT_OBJECT,
+ MtpConstants.PROPERTY_PERSISTENT_UID,
+ MtpConstants.PROPERTY_NAME,
+ MtpConstants.PROPERTY_DISPLAY_NAME,
+ MtpConstants.PROPERTY_DATE_ADDED,
+
+ // image specific properties
+ MtpConstants.PROPERTY_DESCRIPTION,
+
+ // audio specific properties
+ MtpConstants.PROPERTY_ARTIST,
+ MtpConstants.PROPERTY_ALBUM_NAME,
+ MtpConstants.PROPERTY_ALBUM_ARTIST,
+ MtpConstants.PROPERTY_TRACK,
+ MtpConstants.PROPERTY_ORIGINAL_RELEASE_DATE,
+ MtpConstants.PROPERTY_DURATION,
+ MtpConstants.PROPERTY_GENRE,
+ MtpConstants.PROPERTY_COMPOSER,
+
+ // video specific properties
+ MtpConstants.PROPERTY_ARTIST,
+ MtpConstants.PROPERTY_ALBUM_NAME,
+ MtpConstants.PROPERTY_DURATION,
+ MtpConstants.PROPERTY_DESCRIPTION,
+
+ // image specific properties
+ MtpConstants.PROPERTY_DESCRIPTION,
+ };
+
private int[] getSupportedObjectProperties(int format) {
switch (format) {
case MtpConstants.FORMAT_MP3:
@@ -403,6 +449,8 @@ public class MtpDatabase {
case MtpConstants.FORMAT_PNG:
case MtpConstants.FORMAT_BMP:
return IMAGE_PROPERTIES;
+ case 0:
+ return ALL_PROPERTIES;
default:
return FILE_PROPERTIES;
}
@@ -415,324 +463,32 @@ public class MtpDatabase {
};
}
- private String queryString(int id, String column) {
- Cursor c = null;
- try {
- // for now we are only reading properties from the "objects" table
- c = mMediaProvider.query(mObjectsUri,
- new String [] { Files.FileColumns._ID, column },
- ID_WHERE, new String[] { Integer.toString(id) }, null);
- if (c != null && c.moveToNext()) {
- return c.getString(1);
- } else {
- return "";
- }
- } catch (Exception e) {
- return null;
- } finally {
- if (c != null) {
- c.close();
- }
- }
- }
-
- private String queryAudio(int id, String column) {
- Cursor c = null;
- try {
- c = mMediaProvider.query(Audio.Media.getContentUri(mVolumeName),
- new String [] { Files.FileColumns._ID, column },
- ID_WHERE, new String[] { Integer.toString(id) }, null);
- if (c != null && c.moveToNext()) {
- return c.getString(1);
- } else {
- return "";
- }
- } catch (Exception e) {
- return null;
- } finally {
- if (c != null) {
- c.close();
- }
- }
- }
- private String queryGenre(int id) {
- Cursor c = null;
- try {
- Uri uri = Audio.Genres.getContentUriForAudioId(mVolumeName, id);
- c = mMediaProvider.query(uri,
- new String [] { Files.FileColumns._ID, Audio.GenresColumns.NAME },
- null, null, null);
- if (c != null && c.moveToNext()) {
- return c.getString(1);
- } else {
- return "";
- }
- } catch (Exception e) {
- Log.e(TAG, "queryGenre exception", e);
- return null;
- } finally {
- if (c != null) {
- c.close();
- }
- }
- }
-
- private Long queryLong(int id, String column) {
- Cursor c = null;
- try {
- // for now we are only reading properties from the "objects" table
- c = mMediaProvider.query(mObjectsUri,
- new String [] { Files.FileColumns._ID, column },
- ID_WHERE, new String[] { Integer.toString(id) }, null);
- if (c != null && c.moveToNext()) {
- return new Long(c.getLong(1));
- }
- } catch (Exception e) {
- } finally {
- if (c != null) {
- c.close();
- }
- }
- return null;
- }
-
- private String nameFromPath(String path) {
- // extract name from full path
- int start = 0;
- int lastSlash = path.lastIndexOf('/');
- if (lastSlash >= 0) {
- start = lastSlash + 1;
- }
- int end = path.length();
- if (end - start > 255) {
- end = start + 255;
- }
- return path.substring(start, end);
- }
-
- private MtpPropertyList getObjectPropertyList(int handle, int format, int property,
+ private MtpPropertyList getObjectPropertyList(long handle, int format, long property,
int groupCode, int depth) {
// FIXME - implement group support
- // For now we only support a single property at a time
if (groupCode != 0) {
return new MtpPropertyList(0, MtpConstants.RESPONSE_SPECIFICATION_BY_GROUP_UNSUPPORTED);
}
- if (depth > 1) {
- return new MtpPropertyList(0, MtpConstants.RESPONSE_SPECIFICATION_BY_DEPTH_UNSUPPORTED);
- }
- String column = null;
- int type = MtpConstants.TYPE_UNDEFINED;
-
- switch (property) {
- case MtpConstants.PROPERTY_STORAGE_ID:
- // no query needed until we support multiple storage units
- // for now it is always mStorageID
- type = MtpConstants.TYPE_UINT32;
- break;
- case MtpConstants.PROPERTY_OBJECT_FORMAT:
- column = Files.FileColumns.FORMAT;
- type = MtpConstants.TYPE_UINT16;
- break;
- case MtpConstants.PROPERTY_PROTECTION_STATUS:
- // protection status is always 0
- type = MtpConstants.TYPE_UINT16;
- break;
- case MtpConstants.PROPERTY_OBJECT_SIZE:
- column = Files.FileColumns.SIZE;
- type = MtpConstants.TYPE_UINT64;
- break;
- case MtpConstants.PROPERTY_OBJECT_FILE_NAME:
- column = Files.FileColumns.DATA;
- type = MtpConstants.TYPE_STR;
- break;
- case MtpConstants.PROPERTY_NAME:
- column = MediaColumns.TITLE;
- type = MtpConstants.TYPE_STR;
- break;
- case MtpConstants.PROPERTY_DATE_MODIFIED:
- column = Files.FileColumns.DATE_MODIFIED;
- type = MtpConstants.TYPE_STR;
- break;
- case MtpConstants.PROPERTY_DATE_ADDED:
- column = Files.FileColumns.DATE_ADDED;
- type = MtpConstants.TYPE_STR;
- break;
- case MtpConstants.PROPERTY_ORIGINAL_RELEASE_DATE:
- column = Audio.AudioColumns.YEAR;
- type = MtpConstants.TYPE_STR;
- break;
- case MtpConstants.PROPERTY_PARENT_OBJECT:
- column = Files.FileColumns.PARENT;
- type = MtpConstants.TYPE_UINT32;
- break;
- case MtpConstants.PROPERTY_PERSISTENT_UID:
- // PUID is concatenation of storageID and object handle
- type = MtpConstants.TYPE_UINT128;
- break;
- case MtpConstants.PROPERTY_DURATION:
- column = Audio.AudioColumns.DURATION;
- type = MtpConstants.TYPE_UINT32;
- break;
- case MtpConstants.PROPERTY_TRACK:
- column = Audio.AudioColumns.TRACK;
- type = MtpConstants.TYPE_UINT16;
- break;
- case MtpConstants.PROPERTY_DISPLAY_NAME:
- column = MediaColumns.DISPLAY_NAME;
- type = MtpConstants.TYPE_STR;
- break;
- case MtpConstants.PROPERTY_ARTIST:
- type = MtpConstants.TYPE_STR;
- break;
- case MtpConstants.PROPERTY_ALBUM_NAME:
- type = MtpConstants.TYPE_STR;
- break;
- case MtpConstants.PROPERTY_ALBUM_ARTIST:
- column = Audio.AudioColumns.ALBUM_ARTIST;
- type = MtpConstants.TYPE_STR;
- break;
- case MtpConstants.PROPERTY_GENRE:
- // genre requires a special query
- type = MtpConstants.TYPE_STR;
- break;
- case MtpConstants.PROPERTY_COMPOSER:
- column = Audio.AudioColumns.COMPOSER;
- type = MtpConstants.TYPE_STR;
- break;
- case MtpConstants.PROPERTY_DESCRIPTION:
- column = Images.ImageColumns.DESCRIPTION;
- type = MtpConstants.TYPE_STR;
- break;
- default:
- return new MtpPropertyList(0, MtpConstants.RESPONSE_OBJECT_PROP_NOT_SUPPORTED);
- }
-
- Cursor c = null;
- try {
- if (column != null) {
- c = mMediaProvider.query(mObjectsUri,
- new String [] { Files.FileColumns._ID, column },
- // depth 0: single record, depth 1: immediate children
- (depth == 0 ? ID_WHERE : PARENT_WHERE),
- new String[] { Integer.toString(handle) }, null);
- if (c == null) {
- return new MtpPropertyList(0, MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE);
- }
- } else if (depth == 1) {
- c = mMediaProvider.query(mObjectsUri,
- new String [] { Files.FileColumns._ID },
- PARENT_WHERE, new String[] { Integer.toString(handle) }, null);
- if (c == null) {
- return new MtpPropertyList(0, MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE);
- }
- }
-
- int count = (c == null ? 1 : c.getCount());
- MtpPropertyList result = new MtpPropertyList(count, MtpConstants.RESPONSE_OK);
-
- for (int index = 0; index < count; index++) {
- if (c != null) {
- c.moveToNext();
- }
- if (depth == 1) {
- handle = (int)c.getLong(0);
- }
-
- switch (property) {
- // handle special cases here
- case MtpConstants.PROPERTY_STORAGE_ID:
- result.setProperty(index, handle, property, MtpConstants.TYPE_UINT32,
- mStorageID);
- break;
- case MtpConstants.PROPERTY_PROTECTION_STATUS:
- // protection status is always 0
- result.setProperty(index, handle, property, MtpConstants.TYPE_UINT16, 0);
- break;
- case MtpConstants.PROPERTY_OBJECT_FILE_NAME:
- // special case - need to extract file name from full path
- String value = c.getString(1);
- if (value != null) {
- result.setProperty(index, handle, property, nameFromPath(value));
- } else {
- result.setResult(MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE);
- }
- break;
- case MtpConstants.PROPERTY_NAME:
- // first try title
- String name = c.getString(1);
- // then try name
- if (name == null) {
- name = queryString(handle, Audio.PlaylistsColumns.NAME);
- }
- // if title and name fail, extract name from full path
- if (name == null) {
- name = queryString(handle, Files.FileColumns.DATA);
- if (name != null) {
- name = nameFromPath(name);
- }
- }
- if (name != null) {
- result.setProperty(index, handle, property, name);
- } else {
- result.setResult(MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE);
- }
- break;
- case MtpConstants.PROPERTY_DATE_MODIFIED:
- case MtpConstants.PROPERTY_DATE_ADDED:
- // convert from seconds to DateTime
- result.setProperty(index, handle, property, format_date_time(c.getInt(1)));
- break;
- case MtpConstants.PROPERTY_ORIGINAL_RELEASE_DATE:
- // release date is stored internally as just the year
- int year = c.getInt(1);
- String dateTime = Integer.toString(year) + "0101T000000";
- result.setProperty(index, handle, property, dateTime);
- break;
- case MtpConstants.PROPERTY_PERSISTENT_UID:
- // PUID is concatenation of storageID and object handle
- long puid = mStorageID;
- puid <<= 32;
- puid += handle;
- result.setProperty(index, handle, property, MtpConstants.TYPE_UINT128, puid);
- break;
- case MtpConstants.PROPERTY_TRACK:
- result.setProperty(index, handle, property, MtpConstants.TYPE_UINT16,
- c.getInt(1) % 1000);
- break;
- case MtpConstants.PROPERTY_ARTIST:
- result.setProperty(index, handle, property, queryAudio(handle, Audio.AudioColumns.ARTIST));
- break;
- case MtpConstants.PROPERTY_ALBUM_NAME:
- result.setProperty(index, handle, property, queryAudio(handle, Audio.AudioColumns.ALBUM));
- break;
- case MtpConstants.PROPERTY_GENRE:
- String genre = queryGenre(handle);
- if (genre != null) {
- result.setProperty(index, handle, property, genre);
- } else {
- result.setResult(MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE);
- }
- break;
- default:
- if (type == MtpConstants.TYPE_STR) {
- result.setProperty(index, handle, property, c.getString(1));
- } else {
- result.setProperty(index, handle, property, type, c.getLong(1));
- }
- }
+ MtpPropertyGroup propertyGroup;
+ if (property == 0xFFFFFFFFL) {
+ propertyGroup = mPropertyGroupsByFormat.get(format);
+ if (propertyGroup == null) {
+ int[] propertyList = getSupportedObjectProperties(format);
+ propertyGroup = new MtpPropertyGroup(this, mMediaProvider, mVolumeName, propertyList);
+ mPropertyGroupsByFormat.put(new Integer(format), propertyGroup);
}
-
- return result;
- } catch (RemoteException e) {
- return new MtpPropertyList(0, MtpConstants.RESPONSE_GENERAL_ERROR);
- } finally {
- if (c != null) {
- c.close();
+ } else {
+ propertyGroup = mPropertyGroupsByProperty.get(property);
+ if (propertyGroup == null) {
+ int[] propertyList = new int[] { (int)property };
+ propertyGroup = new MtpPropertyGroup(this, mMediaProvider, mVolumeName, propertyList);
+ mPropertyGroupsByProperty.put(new Integer((int)property), propertyGroup);
}
}
- // impossible to get here, so no return statement
+
+ return propertyGroup.getPropertyList((int)handle, format, depth, mStorageID);
}
private int renameFile(int handle, String newName) {
@@ -1028,5 +784,4 @@ public class MtpDatabase {
private native final void native_setup();
private native final void native_finalize();
- private native String format_date_time(long seconds);
}
diff --git a/media/java/android/media/MtpPropertyGroup.java b/media/java/android/media/MtpPropertyGroup.java
new file mode 100644
index 0000000..bb733e2
--- /dev/null
+++ b/media/java/android/media/MtpPropertyGroup.java
@@ -0,0 +1,442 @@
+/*
+ * 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.media;
+
+import android.content.IContentProvider;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.RemoteException;
+import android.provider.MediaStore;
+import android.provider.MediaStore.Audio;
+import android.provider.MediaStore.Files;
+import android.provider.MediaStore.Images;
+import android.provider.MediaStore.MediaColumns;
+import android.util.Log;
+
+import java.util.ArrayList;
+
+class MtpPropertyGroup {
+
+ private static final String TAG = "MtpPropertyGroup";
+
+ private class Property {
+ // MTP property code
+ int code;
+ // MTP data type
+ int type;
+ // column index for our query
+ int column;
+
+ Property(int code, int type, int column) {
+ this.code = code;
+ this.type = type;
+ this.column = column;
+ }
+ }
+
+ private final MtpDatabase mDatabase;
+ private final IContentProvider mProvider;
+ private final String mVolumeName;
+ private final Uri mUri;
+
+ // list of all properties in this group
+ private final Property[] mProperties;
+
+ // list of columns for database query
+ private String[] mColumns;
+
+ private static final String ID_WHERE = Files.FileColumns._ID + "=?";
+ private static final String ID_FORMAT_WHERE = ID_WHERE + " AND "
+ + Files.FileColumns.FORMAT + "=?";
+ private static final String PARENT_WHERE = Files.FileColumns.PARENT + "=?";
+ private static final String PARENT_FORMAT_WHERE = PARENT_WHERE + " AND "
+ + Files.FileColumns.FORMAT + "=?";
+ // constructs a property group for a list of properties
+ public MtpPropertyGroup(MtpDatabase database, IContentProvider provider, String volume,
+ int[] properties) {
+ mDatabase = database;
+ mProvider = provider;
+ mVolumeName = volume;
+ mUri = Files.getMtpObjectsUri(volume);
+
+ int count = properties.length;
+ ArrayList<String> columns = new ArrayList<String>(count);
+ columns.add(Files.FileColumns._ID);
+
+ mProperties = new Property[count];
+ for (int i = 0; i < count; i++) {
+ mProperties[i] = createProperty(properties[i], columns);
+ }
+ count = columns.size();
+ mColumns = new String[count];
+ for (int i = 0; i < count; i++) {
+ mColumns[i] = columns.get(i);
+ }
+ }
+
+ private Property createProperty(int code, ArrayList<String> columns) {
+ String column = null;
+ int type;
+
+ switch (code) {
+ case MtpConstants.PROPERTY_STORAGE_ID:
+ // no query needed until we support multiple storage units
+ type = MtpConstants.TYPE_UINT32;
+ break;
+ case MtpConstants.PROPERTY_OBJECT_FORMAT:
+ column = Files.FileColumns.FORMAT;
+ type = MtpConstants.TYPE_UINT16;
+ break;
+ case MtpConstants.PROPERTY_PROTECTION_STATUS:
+ // protection status is always 0
+ type = MtpConstants.TYPE_UINT16;
+ break;
+ case MtpConstants.PROPERTY_OBJECT_SIZE:
+ column = Files.FileColumns.SIZE;
+ type = MtpConstants.TYPE_UINT64;
+ break;
+ case MtpConstants.PROPERTY_OBJECT_FILE_NAME:
+ column = Files.FileColumns.DATA;
+ type = MtpConstants.TYPE_STR;
+ break;
+ case MtpConstants.PROPERTY_NAME:
+ column = MediaColumns.TITLE;
+ type = MtpConstants.TYPE_STR;
+ break;
+ case MtpConstants.PROPERTY_DATE_MODIFIED:
+ column = Files.FileColumns.DATE_MODIFIED;
+ type = MtpConstants.TYPE_STR;
+ break;
+ case MtpConstants.PROPERTY_DATE_ADDED:
+ column = Files.FileColumns.DATE_ADDED;
+ type = MtpConstants.TYPE_STR;
+ break;
+ case MtpConstants.PROPERTY_ORIGINAL_RELEASE_DATE:
+ column = Audio.AudioColumns.YEAR;
+ type = MtpConstants.TYPE_STR;
+ break;
+ case MtpConstants.PROPERTY_PARENT_OBJECT:
+ column = Files.FileColumns.PARENT;
+ type = MtpConstants.TYPE_UINT32;
+ break;
+ case MtpConstants.PROPERTY_PERSISTENT_UID:
+ // PUID is concatenation of storageID and object handle
+ type = MtpConstants.TYPE_UINT128;
+ break;
+ case MtpConstants.PROPERTY_DURATION:
+ column = Audio.AudioColumns.DURATION;
+ type = MtpConstants.TYPE_UINT32;
+ break;
+ case MtpConstants.PROPERTY_TRACK:
+ column = Audio.AudioColumns.TRACK;
+ type = MtpConstants.TYPE_UINT16;
+ break;
+ case MtpConstants.PROPERTY_DISPLAY_NAME:
+ column = MediaColumns.DISPLAY_NAME;
+ type = MtpConstants.TYPE_STR;
+ break;
+ case MtpConstants.PROPERTY_ARTIST:
+ type = MtpConstants.TYPE_STR;
+ break;
+ case MtpConstants.PROPERTY_ALBUM_NAME:
+ type = MtpConstants.TYPE_STR;
+ break;
+ case MtpConstants.PROPERTY_ALBUM_ARTIST:
+ column = Audio.AudioColumns.ALBUM_ARTIST;
+ type = MtpConstants.TYPE_STR;
+ break;
+ case MtpConstants.PROPERTY_GENRE:
+ // genre requires a special query
+ type = MtpConstants.TYPE_STR;
+ break;
+ case MtpConstants.PROPERTY_COMPOSER:
+ column = Audio.AudioColumns.COMPOSER;
+ type = MtpConstants.TYPE_STR;
+ break;
+ case MtpConstants.PROPERTY_DESCRIPTION:
+ column = Images.ImageColumns.DESCRIPTION;
+ type = MtpConstants.TYPE_STR;
+ break;
+ default:
+ type = MtpConstants.TYPE_UNDEFINED;
+ Log.e(TAG, "unsupported property " + code);
+ break;
+ }
+
+ if (column != null) {
+ columns.add(column);
+ return new Property(code, type, columns.size() - 1);
+ } else {
+ return new Property(code, type, -1);
+ }
+ }
+
+ private String queryString(int id, String column) {
+ Cursor c = null;
+ try {
+ // for now we are only reading properties from the "objects" table
+ c = mProvider.query(mUri,
+ new String [] { Files.FileColumns._ID, column },
+ ID_WHERE, new String[] { Integer.toString(id) }, null);
+ if (c != null && c.moveToNext()) {
+ return c.getString(1);
+ } else {
+ return "";
+ }
+ } catch (Exception e) {
+ return null;
+ } finally {
+ if (c != null) {
+ c.close();
+ }
+ }
+ }
+
+ private String queryAudio(int id, String column) {
+ Cursor c = null;
+ try {
+ c = mProvider.query(Audio.Media.getContentUri(mVolumeName),
+ new String [] { Files.FileColumns._ID, column },
+ ID_WHERE, new String[] { Integer.toString(id) }, null);
+ if (c != null && c.moveToNext()) {
+ return c.getString(1);
+ } else {
+ return "";
+ }
+ } catch (Exception e) {
+ return null;
+ } finally {
+ if (c != null) {
+ c.close();
+ }
+ }
+ }
+
+ private String queryGenre(int id) {
+ Cursor c = null;
+ try {
+ Uri uri = Audio.Genres.getContentUriForAudioId(mVolumeName, id);
+ c = mProvider.query(uri,
+ new String [] { Files.FileColumns._ID, Audio.GenresColumns.NAME },
+ null, null, null);
+ if (c != null && c.moveToNext()) {
+ return c.getString(1);
+ } else {
+ return "";
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "queryGenre exception", e);
+ return null;
+ } finally {
+ if (c != null) {
+ c.close();
+ }
+ }
+ }
+
+ private Long queryLong(int id, String column) {
+ Cursor c = null;
+ try {
+ // for now we are only reading properties from the "objects" table
+ c = mProvider.query(mUri,
+ new String [] { Files.FileColumns._ID, column },
+ ID_WHERE, new String[] { Integer.toString(id) }, null);
+ if (c != null && c.moveToNext()) {
+ return new Long(c.getLong(1));
+ }
+ } catch (Exception e) {
+ } finally {
+ if (c != null) {
+ c.close();
+ }
+ }
+ return null;
+ }
+
+ private static String nameFromPath(String path) {
+ // extract name from full path
+ int start = 0;
+ int lastSlash = path.lastIndexOf('/');
+ if (lastSlash >= 0) {
+ start = lastSlash + 1;
+ }
+ int end = path.length();
+ if (end - start > 255) {
+ end = start + 255;
+ }
+ return path.substring(start, end);
+ }
+
+ MtpPropertyList getPropertyList(int handle, int format, int depth, int storageID) {
+ Log.d(TAG, "getPropertyList handle: " + handle + " format: " + format + " depth: " + depth);
+ if (depth > 1) {
+ // we only support depth 0 and 1
+ // depth 0: single object, depth 1: immediate children
+ return new MtpPropertyList(0, MtpConstants.RESPONSE_SPECIFICATION_BY_DEPTH_UNSUPPORTED);
+ }
+
+ String where;
+ String[] whereArgs;
+ if (format == 0) {
+ whereArgs = new String[] { Integer.toString(handle) };
+ if (depth == 1) {
+ where = PARENT_WHERE;
+ } else {
+ where = ID_WHERE;
+ }
+ } else {
+ whereArgs = new String[] { Integer.toString(handle), Integer.toString(format) };
+ if (depth == 1) {
+ where = PARENT_FORMAT_WHERE;
+ } else {
+ where = ID_FORMAT_WHERE;
+ }
+ }
+
+ Cursor c = null;
+ try {
+ // don't query if not necessary
+ if (depth > 0 || mColumns.length > 1) {
+ c = mProvider.query(mUri, mColumns, where, whereArgs, null);
+ if (c == null) {
+ return new MtpPropertyList(0, MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE);
+ }
+ }
+
+ int count = (c == null ? 1 : c.getCount());
+ MtpPropertyList result = new MtpPropertyList(count * mProperties.length,
+ MtpConstants.RESPONSE_OK);
+
+ // iterate over all objects in the query
+ for (int objectIndex = 0; objectIndex < count; objectIndex++) {
+ if (c != null) {
+ c.moveToNext();
+ }
+ if (depth == 1) {
+ handle = (int)c.getLong(0);
+ }
+
+ // iterate over all properties in the query for the given object
+ for (int propertyIndex = 0; propertyIndex < mProperties.length; propertyIndex++) {
+ Property property = mProperties[propertyIndex];
+ int propertyCode = property.code;
+ int column = property.column;
+
+ // handle some special cases
+ switch (propertyCode) {
+ case MtpConstants.PROPERTY_STORAGE_ID:
+ result.append(handle, propertyCode, MtpConstants.TYPE_UINT32,
+ storageID);
+ break;
+ case MtpConstants.PROPERTY_PROTECTION_STATUS:
+ // protection status is always 0
+ result.append(handle, propertyCode, MtpConstants.TYPE_UINT16, 0);
+ break;
+ case MtpConstants.PROPERTY_OBJECT_FILE_NAME:
+ // special case - need to extract file name from full path
+ String value = c.getString(column);
+ if (value != null) {
+ result.append(handle, propertyCode, nameFromPath(value));
+ } else {
+ result.setResult(MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE);
+ }
+ break;
+ case MtpConstants.PROPERTY_NAME:
+ // first try title
+ String name = c.getString(column);
+ // then try name
+ if (name == null) {
+ name = queryString(handle, Audio.PlaylistsColumns.NAME);
+ }
+ // if title and name fail, extract name from full path
+ if (name == null) {
+ name = queryString(handle, Files.FileColumns.DATA);
+ if (name != null) {
+ name = nameFromPath(name);
+ }
+ }
+ if (name != null) {
+ result.append(handle, propertyCode, name);
+ } else {
+ result.setResult(MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE);
+ }
+ break;
+ case MtpConstants.PROPERTY_DATE_MODIFIED:
+ case MtpConstants.PROPERTY_DATE_ADDED:
+ // convert from seconds to DateTime
+ result.append(handle, propertyCode, format_date_time(c.getInt(column)));
+ break;
+ case MtpConstants.PROPERTY_ORIGINAL_RELEASE_DATE:
+ // release date is stored internally as just the year
+ int year = c.getInt(column);
+ String dateTime = Integer.toString(year) + "0101T000000";
+ result.append(handle, propertyCode, dateTime);
+ break;
+ case MtpConstants.PROPERTY_PERSISTENT_UID:
+ // PUID is concatenation of storageID and object handle
+ long puid = storageID;
+ puid <<= 32;
+ puid += handle;
+ result.append(handle, propertyCode, MtpConstants.TYPE_UINT128, puid);
+ break;
+ case MtpConstants.PROPERTY_TRACK:
+ result.append(handle, propertyCode, MtpConstants.TYPE_UINT16,
+ c.getInt(column) % 1000);
+ break;
+ case MtpConstants.PROPERTY_ARTIST:
+ result.append(handle, propertyCode,
+ queryAudio(handle, Audio.AudioColumns.ARTIST));
+ break;
+ case MtpConstants.PROPERTY_ALBUM_NAME:
+ result.append(handle, propertyCode,
+ queryAudio(handle, Audio.AudioColumns.ALBUM));
+ break;
+ case MtpConstants.PROPERTY_GENRE:
+ String genre = queryGenre(handle);
+ if (genre != null) {
+ result.append(handle, propertyCode, genre);
+ } else {
+ result.setResult(MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE);
+ }
+ break;
+ default:
+ if (property.type == MtpConstants.TYPE_STR) {
+ result.append(handle, propertyCode, c.getString(column));
+ } else if (property.type == MtpConstants.TYPE_UNDEFINED) {
+ result.append(handle, propertyCode, property.type, 0);
+ } else {
+ result.append(handle, propertyCode, property.type,
+ c.getLong(column));
+ }
+ break;
+ }
+ }
+ }
+
+ return result;
+ } catch (RemoteException e) {
+ return new MtpPropertyList(0, MtpConstants.RESPONSE_GENERAL_ERROR);
+ } finally {
+ if (c != null) {
+ c.close();
+ }
+ }
+ // impossible to get here, so no return statement
+ }
+
+ private native String format_date_time(long seconds);
+}
diff --git a/media/java/android/media/MtpPropertyList.java b/media/java/android/media/MtpPropertyList.java
index f598981..d3f0b34 100644
--- a/media/java/android/media/MtpPropertyList.java
+++ b/media/java/android/media/MtpPropertyList.java
@@ -19,14 +19,14 @@ package android.media;
/**
* Encapsulates the ObjectPropList dataset used by the GetObjectPropList command.
* The fields of this class are read by JNI code in android_media_MtpDatabase.cpp
- *
- * {@hide}
*/
-public class MtpPropertyList {
+class MtpPropertyList {
// number of results returned
- public final int mCount;
+ private int mCount;
+ // maximum number of results
+ private final int mMaxCount;
// result code for GetObjectPropList
public int mResult;
// list of object handles (first field in quadruplet)
@@ -41,18 +41,19 @@ public class MtpPropertyList {
public String[] mStringValues;
// constructor only called from MtpDatabase
- public MtpPropertyList(int count, int result) {
- mCount = count;
+ public MtpPropertyList(int maxCount, int result) {
+ mMaxCount = maxCount;
mResult = result;
- mObjectHandles = new int[count];
- mPropertyCodes = new int[count];
- mDataTypes = new int[count];
+ mObjectHandles = new int[maxCount];
+ mPropertyCodes = new int[maxCount];
+ mDataTypes = new int[maxCount];
// mLongValues and mStringValues are created lazily since both might not be necessary
}
- public void setProperty(int index, int handle, int property, int type, long value) {
+ public void append(int handle, int property, int type, long value) {
+ int index = mCount++;
if (mLongValues == null) {
- mLongValues = new long[mCount];
+ mLongValues = new long[mMaxCount];
}
mObjectHandles[index] = handle;
mPropertyCodes[index] = property;
@@ -60,9 +61,10 @@ public class MtpPropertyList {
mLongValues[index] = value;
}
- public void setProperty(int index, int handle, int property, String value) {
+ public void append(int handle, int property, String value) {
+ int index = mCount++;
if (mStringValues == null) {
- mStringValues = new String[mCount];
+ mStringValues = new String[mMaxCount];
}
mObjectHandles[index] = handle;
mPropertyCodes[index] = property;
diff --git a/media/java/android/media/audiofx/Visualizer.java b/media/java/android/media/audiofx/Visualizer.java
index 0c48556..41309dc 100755
--- a/media/java/android/media/audiofx/Visualizer.java
+++ b/media/java/android/media/audiofx/Visualizer.java
@@ -43,10 +43,8 @@ import android.os.Message;
* <li>Frequency data: 8-bit magnitude FFT by using the {@link #getFft(byte[])} method</li>
* </ul>
* <p>The length of the capture can be retrieved or specified by calling respectively
- * {@link #getCaptureSize()} and {@link #setCaptureSize(int)} methods. Note that the size of the FFT
- * is half of the specified capture size but both sides of the spectrum are returned yielding in a
- * number of bytes equal to the capture size. The capture size must be a power of 2 in the range
- * returned by {@link #getCaptureSizeRange()}.
+ * {@link #getCaptureSize()} and {@link #setCaptureSize(int)} methods. The capture size must be a
+ * power of 2 in the range returned by {@link #getCaptureSizeRange()}.
* <p>In addition to the polling capture mode described above with {@link #getWaveForm(byte[])} and
* {@link #getFft(byte[])} methods, a callback mode is also available by installing a listener by
* use of the {@link #setDataCaptureListener(OnDataCaptureListener, int, boolean, boolean)} method.
@@ -333,11 +331,43 @@ public class Visualizer {
}
}
/**
- * Returns a frequency capture of currently playing audio content. The capture is a 8-bit
- * magnitude FFT. Note that the size of the FFT is half of the specified capture size but both
- * sides of the spectrum are returned yielding in a number of bytes equal to the capture size.
- * {@see #getCaptureSize()}.
+ * Returns a frequency capture of currently playing audio content.
* <p>This method must be called when the Visualizer is enabled.
+ * <p>The capture is an 8-bit magnitude FFT, the frequency range covered being 0 (DC) to half of
+ * the sampling rate returned by {@link #getSamplingRate()}. The capture returns the real and
+ * imaginary parts of a number of frequency points equal to half of the capture size plus one.
+ * <p>Note: only the real part is returned for the first point (DC) and the last point
+ * (sampling frequency / 2).
+ * <p>The layout in the returned byte array is as follows:
+ * <ul>
+ * <li> n is the capture size returned by getCaptureSize()</li>
+ * <li> Rfk, Ifk are respectively the real and imaginary parts of the kth frequency
+ * component</li>
+ * <li> If Fs is the sampling frequency retuned by getSamplingRate() the kth frequency is:
+ * (k*Fs)/(n/2) </li>
+ * </ul>
+ * <table border="0" cellspacing="0" cellpadding="0">
+ * <tr><td>Index </p></td>
+ * <td>0 </p></td>
+ * <td>1 </p></td>
+ * <td>2 </p></td>
+ * <td>3 </p></td>
+ * <td>4 </p></td>
+ * <td>5 </p></td>
+ * <td>... </p></td>
+ * <td>n - 2 </p></td>
+ * <td>n - 1 </p></td></tr>
+ * <tr><td>Data </p></td>
+ * <td>Rf0 </p></td>
+ * <td>Rf(n/2) </p></td>
+ * <td>Rf1 </p></td>
+ * <td>If1 </p></td>
+ * <td>Rf2 </p></td>
+ * <td>If2 </p></td>
+ * <td>... </p></td>
+ * <td>Rf(n-1)/2 </p></td>
+ * <td>If(n-1)/2 </p></td></tr>
+ * </table>
* @param fft array of bytes where the FFT should be returned
* @return {@link #SUCCESS} in case of success,
* {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION} or {@link #ERROR_DEAD_OBJECT}
diff --git a/media/jni/android_media_MtpDatabase.cpp b/media/jni/android_media_MtpDatabase.cpp
index f04a2ae..1909e6a 100644
--- a/media/jni/android_media_MtpDatabase.cpp
+++ b/media/jni/android_media_MtpDatabase.cpp
@@ -134,8 +134,7 @@ public:
virtual MtpResponseCode resetDeviceProperty(MtpDeviceProperty property);
virtual MtpResponseCode getObjectPropertyList(MtpObjectHandle handle,
- MtpObjectFormat format,
- MtpObjectProperty property,
+ uint32_t format, uint32_t property,
int groupCode, int depth,
MtpDataPacket& packet);
@@ -355,7 +354,7 @@ MtpResponseCode MyMtpDatabase::getObjectPropertyValue(MtpObjectHandle handle,
MtpDataPacket& packet) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
jobject list = env->CallObjectMethod(mDatabase, method_getObjectPropertyList,
- (jint)handle, 0, (jint)property, 0, 0);
+ (jlong)handle, 0, (jlong)property, 0, 0);
MtpResponseCode result = env->GetIntField(list, field_mResult);
int count = env->GetIntField(list, field_mCount);
if (result == MTP_RESPONSE_OK && count != 1)
@@ -646,18 +645,19 @@ MtpResponseCode MyMtpDatabase::resetDeviceProperty(MtpDeviceProperty property) {
}
MtpResponseCode MyMtpDatabase::getObjectPropertyList(MtpObjectHandle handle,
- MtpObjectFormat format,
- MtpObjectProperty property,
+ uint32_t format, uint32_t property,
int groupCode, int depth,
MtpDataPacket& packet) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
jobject list = env->CallObjectMethod(mDatabase, method_getObjectPropertyList,
- (jint)handle, (jint)format, (jint)property, (jint)groupCode, (jint)depth);
+ (jlong)handle, (jint)format, (jlong)property, (jint)groupCode, (jint)depth);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ if (!list)
+ return MTP_RESPONSE_GENERAL_ERROR;
int count = env->GetIntField(list, field_mCount);
MtpResponseCode result = env->GetIntField(list, field_mResult);
packet.putUInt32(count);
-
if (count > 0) {
jintArray objectHandlesArray = (jintArray)env->GetObjectField(list, field_mObjectHandles);
jintArray propertyCodesArray = (jintArray)env->GetObjectField(list, field_mPropertyCodes);
@@ -1042,7 +1042,7 @@ android_media_MtpDatabase_finalize(JNIEnv *env, jobject thiz)
}
static jstring
-android_media_MtpDatabase_format_date_time(JNIEnv *env, jobject thiz, jlong seconds)
+android_media_MtpPropertyGroup_format_date_time(JNIEnv *env, jobject thiz, jlong seconds)
{
#ifdef HAVE_ANDROID_OS
char date[20];
@@ -1055,11 +1055,14 @@ android_media_MtpDatabase_format_date_time(JNIEnv *env, jobject thiz, jlong seco
// ----------------------------------------------------------------------------
-static JNINativeMethod gMethods[] = {
+static JNINativeMethod gMtpDatabaseMethods[] = {
{"native_setup", "()V", (void *)android_media_MtpDatabase_setup},
{"native_finalize", "()V", (void *)android_media_MtpDatabase_finalize},
+};
+
+static JNINativeMethod gMtpPropertyGroupMethods[] = {
{"format_date_time", "(J)Ljava/lang/String;",
- (void *)android_media_MtpDatabase_format_date_time},
+ (void *)android_media_MtpPropertyGroup_format_date_time},
};
static const char* const kClassPathName = "android/media/MtpDatabase";
@@ -1131,7 +1134,7 @@ int register_android_media_MtpDatabase(JNIEnv *env)
return -1;
}
method_getObjectPropertyList = env->GetMethodID(clazz, "getObjectPropertyList",
- "(IIIII)Landroid/media/MtpPropertyList;");
+ "(JIJII)Landroid/media/MtpPropertyList;");
if (method_getObjectPropertyList == NULL) {
LOGE("Can't find getObjectPropertyList");
return -1;
@@ -1220,6 +1223,10 @@ int register_android_media_MtpDatabase(JNIEnv *env)
return -1;
}
+ if (AndroidRuntime::registerNativeMethods(env,
+ "android/media/MtpDatabase", gMtpDatabaseMethods, NELEM(gMtpDatabaseMethods)))
+ return -1;
+
return AndroidRuntime::registerNativeMethods(env,
- "android/media/MtpDatabase", gMethods, NELEM(gMethods));
+ "android/media/MtpPropertyGroup", gMtpPropertyGroupMethods, NELEM(gMtpPropertyGroupMethods));
}
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/MtpDatabase.h b/media/mtp/MtpDatabase.h
index 900b517..9929805 100644
--- a/media/mtp/MtpDatabase.h
+++ b/media/mtp/MtpDatabase.h
@@ -77,8 +77,7 @@ public:
virtual MtpResponseCode resetDeviceProperty(MtpDeviceProperty property) = 0;
virtual MtpResponseCode getObjectPropertyList(MtpObjectHandle handle,
- MtpObjectFormat format,
- MtpObjectProperty property,
+ uint32_t format, uint32_t property,
int groupCode, int depth,
MtpDataPacket& packet) = 0;
diff --git a/media/mtp/MtpProperty.cpp b/media/mtp/MtpProperty.cpp
index 42945f5..4356a6f 100644
--- a/media/mtp/MtpProperty.cpp
+++ b/media/mtp/MtpProperty.cpp
@@ -53,7 +53,7 @@ MtpProperty::MtpProperty(MtpPropertyCode propCode,
mDefaultArrayValues(NULL),
mCurrentArrayLength(0),
mCurrentArrayValues(NULL),
- mGroupCode(-1), // disable multiple properties in GetObjectPropList for now
+ mGroupCode(0),
mFormFlag(kFormNone),
mEnumLength(0),
mEnumValues(NULL)
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index c3755f3..de6cbac 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -536,8 +536,9 @@ MtpResponseCode MtpServer::doResetDevicePropValue() {
MtpResponseCode MtpServer::doGetObjectPropList() {
MtpObjectHandle handle = mRequest.getParameter(1);
- MtpObjectFormat format = mRequest.getParameter(2);
- MtpDeviceProperty property = mRequest.getParameter(3);
+ // use uint32_t so we can support 0xFFFFFFFF
+ uint32_t format = mRequest.getParameter(2);
+ uint32_t property = mRequest.getParameter(3);
int groupCode = mRequest.getParameter(4);
int depth = mRequest.getParameter(5);
LOGD("GetObjectPropList %d format: %s property: %s group: %d depth: %d\n",
diff --git a/packages/DefaultContainerService/AndroidManifest.xml b/packages/DefaultContainerService/AndroidManifest.xml
index 078daa7..b0597c4 100755
--- a/packages/DefaultContainerService/AndroidManifest.xml
+++ b/packages/DefaultContainerService/AndroidManifest.xml
@@ -1,6 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.defcontainer">
<uses-permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER"/>
+ <uses-permission android:name="android.permission.ACCESS_ALL_DOWNLOADS"/>
<uses-permission android:name="android.permission.ASEC_ACCESS"/>
<uses-permission android:name="android.permission.ASEC_CREATE"/>
<uses-permission android:name="android.permission.ASEC_DESTROY"/>
diff --git a/packages/SystemUI/res/drawable-nodpi/panel_notification.png b/packages/SystemUI/res/drawable-nodpi/panel_notification.png
index eca47d7..b0d9c18 100644
--- a/packages/SystemUI/res/drawable-nodpi/panel_notification.png
+++ b/packages/SystemUI/res/drawable-nodpi/panel_notification.png
Binary files differ
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index cfdf0dd..21c0645 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -19,22 +19,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_label (7164937344850004466) -->
- <skip />
+ <string name="app_label" msgid="7164937344850004466">"UI systému"</string>
<string name="status_bar_clear_all_button" msgid="7774721344716731603">"Vymazat"</string>
- <!-- no translation found for status_bar_do_not_disturb_button (5812628897510997853) -->
- <skip />
- <!-- no translation found for status_bar_please_disturb_button (3345398298841572813) -->
- <skip />
+ <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Nerušit"</string>
+ <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Zobrazit upozornění"</string>
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Žádná oznámení"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Probíhající"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Oznámení"</string>
<string name="battery_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>
- <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
- <skip />
- <!-- no translation found for invalid_charger (4549105996740522523) -->
- <skip />
+ <string name="battery_low_subtitle" msgid="1752040062087829196">"Baterie je vybitá."</string>
+ <string name="battery_low_percent_format" msgid="1077244949318261761">"Zbývá <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="invalid_charger" msgid="4549105996740522523">"Nabíjení pomocí rozhraní USB není podporováno."\n"Používejte pouze nabíječku, která byla dodána se zařízením."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Využití baterie"</string>
<!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
<skip />
@@ -45,12 +40,9 @@
<!-- 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) -->
- <skip />
+ <string name="recent_tasks_empty" msgid="1905484479067697884">"Žádné nedávno použité aplikace."</string>
<!-- no translation found for recent_tasks_app_label (3796483981246752469) -->
<skip />
- <!-- no translation found for toast_rotation_free (2700542202836832631) -->
- <skip />
- <!-- no translation found for toast_rotation_locked (7484691306949652450) -->
- <skip />
+ <string name="toast_rotation_free" msgid="2700542202836832631">"Obrazovka se automaticky otočí."</string>
+ <string name="toast_rotation_locked" msgid="7484691306949652450">"Otáčení obrazovky je uzamčeno."</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index e4fc728..a569aa4 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -19,22 +19,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_label (7164937344850004466) -->
- <skip />
+ <string name="app_label" msgid="7164937344850004466">"System-UI"</string>
<string name="status_bar_clear_all_button" msgid="7774721344716731603">"Ryd"</string>
- <!-- no translation found for status_bar_do_not_disturb_button (5812628897510997853) -->
- <skip />
- <!-- no translation found for status_bar_please_disturb_button (3345398298841572813) -->
- <skip />
+ <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Forstyr ikke"</string>
+ <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Vis meddelelser"</string>
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ingen meddelelser"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"I gang"</string>
<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>
- <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
- <skip />
- <!-- no translation found for invalid_charger (4549105996740522523) -->
- <skip />
+ <string name="battery_low_subtitle" msgid="1752040062087829196">"Batteriet er ved at være fladt."</string>
+ <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> tilbage"</string>
+ <string name="invalid_charger" msgid="4549105996740522523">"Opladning via USB understøttes ikke."\n"Brug kun den medfølgende oplader."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Batteriforbrug"</string>
<!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
<skip />
@@ -45,12 +40,9 @@
<!-- 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) -->
- <skip />
+ <string name="recent_tasks_empty" msgid="1905484479067697884">"Der er ingen nye programmer."</string>
<!-- no translation found for recent_tasks_app_label (3796483981246752469) -->
<skip />
- <!-- no translation found for toast_rotation_free (2700542202836832631) -->
- <skip />
- <!-- no translation found for toast_rotation_locked (7484691306949652450) -->
- <skip />
+ <string name="toast_rotation_free" msgid="2700542202836832631">"Skærmen roterer automatisk."</string>
+ <string name="toast_rotation_locked" msgid="7484691306949652450">"Skærmrotationen er nu låst."</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index edb1bef..fce8200 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -19,22 +19,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_label (7164937344850004466) -->
- <skip />
+ <string name="app_label" msgid="7164937344850004466">"System-UI"</string>
<string name="status_bar_clear_all_button" msgid="7774721344716731603">"Löschen"</string>
- <!-- no translation found for status_bar_do_not_disturb_button (5812628897510997853) -->
- <skip />
- <!-- no translation found for status_bar_please_disturb_button (3345398298841572813) -->
- <skip />
+ <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Bitte nicht stören"</string>
+ <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Benachrichtigungen zeigen"</string>
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Keine Benachrichtigungen"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Aktuell"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Benachrichtigungen"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Ladegerät anschließen"</string>
- <!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Akku ist fast leer."</string>
- <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
- <skip />
- <!-- no translation found for invalid_charger (4549105996740522523) -->
- <skip />
+ <string name="battery_low_subtitle" msgid="1752040062087829196">"Akku ist fast leer."</string>
+ <string name="battery_low_percent_format" msgid="1077244949318261761">"Noch <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="invalid_charger" msgid="4549105996740522523">"USB-Aufladung wird nicht unterstützt."\n"Verwenden Sie das mitgelieferte Aufladegerät."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Akkuverbrauch"</string>
<!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
<skip />
@@ -45,12 +40,9 @@
<!-- 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) -->
- <skip />
+ <string name="recent_tasks_empty" msgid="1905484479067697884">"Keine neuen Anwendungen"</string>
<!-- no translation found for recent_tasks_app_label (3796483981246752469) -->
<skip />
- <!-- no translation found for toast_rotation_free (2700542202836832631) -->
- <skip />
- <!-- no translation found for toast_rotation_locked (7484691306949652450) -->
- <skip />
+ <string name="toast_rotation_free" msgid="2700542202836832631">"Bildschirm wird automatisch gedreht."</string>
+ <string name="toast_rotation_locked" msgid="7484691306949652450">"Bildschirmrotation ist jetzt gesperrt."</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 21ea803..01bf5a1 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -19,22 +19,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_label (7164937344850004466) -->
- <skip />
+ <string name="app_label" msgid="7164937344850004466">"UI συστήματ."</string>
<string name="status_bar_clear_all_button" msgid="7774721344716731603">"Εκκαθάριση"</string>
- <!-- no translation found for status_bar_do_not_disturb_button (5812628897510997853) -->
- <skip />
- <!-- no translation found for status_bar_please_disturb_button (3345398298841572813) -->
- <skip />
+ <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Μην ενοχλείτε"</string>
+ <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Εμφάνιση ειδοποιήσεων"</string>
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Δεν υπάρχουν ειδοποιήσεις"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Εν εξελίξει"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Ειδοποιήσεις"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Συνδέστε τον φορτιστή"</string>
- <!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Η στάθμη της μπαταρίας είναι χαμηλή:"</string>
- <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
- <skip />
- <!-- no translation found for invalid_charger (4549105996740522523) -->
- <skip />
+ <string name="battery_low_subtitle" msgid="1752040062087829196">"Η στάθμη της μπαταρίας είναι χαμηλή."</string>
+ <string name="battery_low_percent_format" msgid="1077244949318261761">"Απομένει <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="invalid_charger" msgid="4549105996740522523">"Δεν υποστηρίζεται η φόρτιση USB."\n"Χρησιμοποιείτε μόνο τον φορτιστή που παρέχεται."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Χρήση μπαταρίας"</string>
<!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
<skip />
@@ -45,12 +40,9 @@
<!-- 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) -->
- <skip />
+ <string name="recent_tasks_empty" msgid="1905484479067697884">"Δεν υπάρχουν πρόσφατες εφαρμογές."</string>
<!-- no translation found for recent_tasks_app_label (3796483981246752469) -->
<skip />
- <!-- no translation found for toast_rotation_free (2700542202836832631) -->
- <skip />
- <!-- no translation found for toast_rotation_locked (7484691306949652450) -->
- <skip />
+ <string name="toast_rotation_free" msgid="2700542202836832631">"Θα γίνεται αυτόματη περιστροφή της οθόνης."</string>
+ <string name="toast_rotation_locked" msgid="7484691306949652450">"Η περιστροφή οθόνης είναι κλειδωμένη."</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index b6d3618..e2172c0 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -19,22 +19,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_label (7164937344850004466) -->
- <skip />
+ <string name="app_label" msgid="7164937344850004466">"Sistema UI"</string>
<string name="status_bar_clear_all_button" msgid="7774721344716731603">"Borrar"</string>
- <!-- no translation found for status_bar_do_not_disturb_button (5812628897510997853) -->
- <skip />
- <!-- no translation found for status_bar_please_disturb_button (3345398298841572813) -->
- <skip />
+ <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"No molestar"</string>
+ <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Mostrar notificaciones"</string>
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"No hay notificaciones"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Continuo"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificaciones"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Conecta el cargador"</string>
- <!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Hay poca batería:"</string>
- <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
- <skip />
- <!-- no translation found for invalid_charger (4549105996740522523) -->
- <skip />
+ <string name="battery_low_subtitle" msgid="1752040062087829196">"Hay poca batería."</string>
+ <string name="battery_low_percent_format" msgid="1077244949318261761">"Quedan <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="invalid_charger" msgid="4549105996740522523">"No admite la carga USB."\n"Usa sólo el cargador provisto."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Uso de la batería"</string>
<!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
<skip />
@@ -45,12 +40,9 @@
<!-- 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 />
+ <string name="recent_tasks_empty" msgid="1905484479067697884">"No hay aplicaciones recientes."</string>
<!-- no translation found for recent_tasks_app_label (3796483981246752469) -->
<skip />
- <!-- no translation found for toast_rotation_free (2700542202836832631) -->
- <skip />
- <!-- no translation found for toast_rotation_locked (7484691306949652450) -->
- <skip />
+ <string name="toast_rotation_free" msgid="2700542202836832631">"La pantalla rotará automáticamente."</string>
+ <string name="toast_rotation_locked" msgid="7484691306949652450">"La rotación de la pantalla se encuentra actualmente bloqueada."</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 77773af..b402e15 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -19,22 +19,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_label (7164937344850004466) -->
- <skip />
+ <string name="app_label" msgid="7164937344850004466">"IU sistema"</string>
<string name="status_bar_clear_all_button" msgid="7774721344716731603">"Borrar"</string>
- <!-- no translation found for status_bar_do_not_disturb_button (5812628897510997853) -->
- <skip />
- <!-- no translation found for status_bar_please_disturb_button (3345398298841572813) -->
- <skip />
+ <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"No molestar"</string>
+ <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Mostrar notificaciones"</string>
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"No tienes notificaciones"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Entrante"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificaciones"</string>
<string name="battery_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>
- <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
- <skip />
- <!-- no translation found for invalid_charger (4549105996740522523) -->
- <skip />
+ <string name="battery_low_subtitle" msgid="1752040062087829196">"Se está agotando la batería."</string>
+ <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> restante"</string>
+ <string name="invalid_charger" msgid="4549105996740522523">"No se admite la carga por USB."\n"Utiliza solo el cargador proporcionado."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Uso de la batería"</string>
<!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
<skip />
@@ -45,12 +40,9 @@
<!-- 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 />
+ <string name="recent_tasks_empty" msgid="1905484479067697884">"No hay aplicaciones recientes."</string>
<!-- no translation found for recent_tasks_app_label (3796483981246752469) -->
<skip />
- <!-- no translation found for toast_rotation_free (2700542202836832631) -->
- <skip />
- <!-- no translation found for toast_rotation_locked (7484691306949652450) -->
- <skip />
+ <string name="toast_rotation_free" msgid="2700542202836832631">"La pantalla girará automáticamente."</string>
+ <string name="toast_rotation_locked" msgid="7484691306949652450">"La rotación de la pantalla esta bloqueada."</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 8877329..70d2a51 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -19,22 +19,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_label (7164937344850004466) -->
- <skip />
+ <string name="app_label" msgid="7164937344850004466">"IU système"</string>
<string name="status_bar_clear_all_button" msgid="7774721344716731603">"Effacer"</string>
- <!-- no translation found for status_bar_do_not_disturb_button (5812628897510997853) -->
- <skip />
- <!-- no translation found for status_bar_please_disturb_button (3345398298841572813) -->
- <skip />
+ <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Ne pas déranger"</string>
+ <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Afficher les notifications"</string>
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Aucune notification"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"En cours"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifications"</string>
<string name="battery_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>
- <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
- <skip />
- <!-- no translation found for invalid_charger (4549105996740522523) -->
- <skip />
+ <string name="battery_low_subtitle" msgid="1752040062087829196">"Le niveau de la batterie est faible."</string>
+ <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> restant(s)"</string>
+ <string name="invalid_charger" msgid="4549105996740522523">"Chargement USB non disponible."\n"Vous devez utiliser le chargeur fourni."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Utilisation de la batterie"</string>
<!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
<skip />
@@ -45,12 +40,9 @@
<!-- 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) -->
- <skip />
+ <string name="recent_tasks_empty" msgid="1905484479067697884">"Aucune application récente"</string>
<!-- no translation found for recent_tasks_app_label (3796483981246752469) -->
<skip />
- <!-- no translation found for toast_rotation_free (2700542202836832631) -->
- <skip />
- <!-- no translation found for toast_rotation_locked (7484691306949652450) -->
- <skip />
+ <string name="toast_rotation_free" msgid="2700542202836832631">"L\'écran pivote automatiquement."</string>
+ <string name="toast_rotation_locked" msgid="7484691306949652450">"La rotation de l\'écran est verrouillée."</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 0507cf9..4b16033 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -19,22 +19,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_label (7164937344850004466) -->
- <skip />
+ <string name="app_label" msgid="7164937344850004466">"UI sistema"</string>
<string name="status_bar_clear_all_button" msgid="7774721344716731603">"Cancella"</string>
- <!-- no translation found for status_bar_do_not_disturb_button (5812628897510997853) -->
- <skip />
- <!-- no translation found for status_bar_please_disturb_button (3345398298841572813) -->
- <skip />
+ <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Non disturbare"</string>
+ <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Mostra notifiche"</string>
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Nessuna notifica"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"In corso"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notifiche"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Collegare il caricabatterie"</string>
- <!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Batteria quasi scarica:"</string>
- <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
- <skip />
- <!-- no translation found for invalid_charger (4549105996740522523) -->
- <skip />
+ <string name="battery_low_subtitle" msgid="1752040062087829196">"Batteria quasi scarica."</string>
+ <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> rimanente"</string>
+ <string name="invalid_charger" msgid="4549105996740522523">"Ricarica tramite USB non supportata."\n"Utilizza solo il caricatore in dotazione."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Utilizzo batteria"</string>
<!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
<skip />
@@ -45,12 +40,9 @@
<!-- 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) -->
- <skip />
+ <string name="recent_tasks_empty" msgid="1905484479067697884">"Nessuna applicazione recente."</string>
<!-- no translation found for recent_tasks_app_label (3796483981246752469) -->
<skip />
- <!-- no translation found for toast_rotation_free (2700542202836832631) -->
- <skip />
- <!-- no translation found for toast_rotation_locked (7484691306949652450) -->
- <skip />
+ <string name="toast_rotation_free" msgid="2700542202836832631">"Lo schermo ruoterà automaticamente."</string>
+ <string name="toast_rotation_locked" msgid="7484691306949652450">"La rotazione dello schermo è bloccata."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 782d03b..b2b6c54 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -19,22 +19,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_label (7164937344850004466) -->
- <skip />
+ <string name="app_label" msgid="7164937344850004466">"システムUI"</string>
<string name="status_bar_clear_all_button" msgid="7774721344716731603">"通知を消去"</string>
- <!-- no translation found for status_bar_do_not_disturb_button (5812628897510997853) -->
- <skip />
- <!-- no translation found for status_bar_please_disturb_button (3345398298841572813) -->
- <skip />
+ <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"通知を非表示"</string>
+ <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"通知を表示"</string>
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"通知なし"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"実行中"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
<string name="battery_low_title" msgid="7923774589611311406">"充電してください"</string>
- <!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"電池が残り少なくなっています:"</string>
- <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
- <skip />
- <!-- no translation found for invalid_charger (4549105996740522523) -->
- <skip />
+ <string name="battery_low_subtitle" msgid="1752040062087829196">"電池が残り少なくなっています。"</string>
+ <string name="battery_low_percent_format" msgid="1077244949318261761">"残り<xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="invalid_charger" msgid="4549105996740522523">"USB充電には対応していません。"\n"付属の充電器をお使いください。"</string>
<string name="battery_low_why" msgid="7279169609518386372">"電池使用量"</string>
<!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
<skip />
@@ -45,12 +40,9 @@
<!-- 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) -->
- <skip />
+ <string name="recent_tasks_empty" msgid="1905484479067697884">"新着のアプリケーションはありません。"</string>
<!-- no translation found for recent_tasks_app_label (3796483981246752469) -->
<skip />
- <!-- no translation found for toast_rotation_free (2700542202836832631) -->
- <skip />
- <!-- no translation found for toast_rotation_locked (7484691306949652450) -->
- <skip />
+ <string name="toast_rotation_free" msgid="2700542202836832631">"画面は自動的に回転します。"</string>
+ <string name="toast_rotation_locked" msgid="7484691306949652450">"画面の回転をロックしました。"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 5e9b9d5..d550253 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -19,22 +19,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_label (7164937344850004466) -->
- <skip />
+ <string name="app_label" msgid="7164937344850004466">"시스템 UI"</string>
<string name="status_bar_clear_all_button" msgid="7774721344716731603">"지우기"</string>
- <!-- no translation found for status_bar_do_not_disturb_button (5812628897510997853) -->
- <skip />
- <!-- no translation found for status_bar_please_disturb_button (3345398298841572813) -->
- <skip />
+ <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"응답 거부"</string>
+ <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"알림 표시"</string>
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"알림 없음"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"진행 중"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"알림"</string>
<string name="battery_low_title" msgid="7923774589611311406">"충전기를 연결하세요."</string>
- <!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"배터리 전원이 부족합니다."</string>
- <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
- <skip />
- <!-- no translation found for invalid_charger (4549105996740522523) -->
- <skip />
+ <string name="battery_low_subtitle" msgid="1752040062087829196">"배터리 전원이 부족합니다."</string>
+ <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g>개 남음"</string>
+ <string name="invalid_charger" msgid="4549105996740522523">"USB 충전이 지원되지 않습니다."\n"제공된 충전기만 사용하세요."</string>
<string name="battery_low_why" msgid="7279169609518386372">"배터리 사용량"</string>
<!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
<skip />
@@ -45,12 +40,9 @@
<!-- 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) -->
- <skip />
+ <string name="recent_tasks_empty" msgid="1905484479067697884">"최근에 사용한 애플리케이션이 없습니다."</string>
<!-- no translation found for recent_tasks_app_label (3796483981246752469) -->
<skip />
- <!-- no translation found for toast_rotation_free (2700542202836832631) -->
- <skip />
- <!-- no translation found for toast_rotation_locked (7484691306949652450) -->
- <skip />
+ <string name="toast_rotation_free" msgid="2700542202836832631">"화면은 자동으로 회전합니다."</string>
+ <string name="toast_rotation_locked" msgid="7484691306949652450">"현재 화면 회전이 잠겨 있습니다."</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 147242f..1eb7851 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -19,22 +19,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_label (7164937344850004466) -->
- <skip />
+ <string name="app_label" msgid="7164937344850004466">"Sys.gr.snitt"</string>
<string name="status_bar_clear_all_button" msgid="7774721344716731603">"Fjern"</string>
- <!-- no translation found for status_bar_do_not_disturb_button (5812628897510997853) -->
- <skip />
- <!-- no translation found for status_bar_please_disturb_button (3345398298841572813) -->
- <skip />
+ <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Ikke forstyrr"</string>
+ <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Vis varslinger"</string>
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Ingen varslinger"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Aktiviteter"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Varslinger"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Koble til en lader"</string>
- <!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Batteriet er nesten tomt:"</string>
- <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
- <skip />
- <!-- no translation found for invalid_charger (4549105996740522523) -->
- <skip />
+ <string name="battery_low_subtitle" msgid="1752040062087829196">"Lavt batterinivå."</string>
+ <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> gjenværende"</string>
+ <string name="invalid_charger" msgid="4549105996740522523">"USB-lading støttes ikke."\n"Bruk kun den medfølgende laderen."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Batteribruk"</string>
<!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
<skip />
@@ -45,12 +40,9 @@
<!-- 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) -->
- <skip />
+ <string name="recent_tasks_empty" msgid="1905484479067697884">"Ingen nylig brukte programmer."</string>
<!-- no translation found for recent_tasks_app_label (3796483981246752469) -->
<skip />
- <!-- no translation found for toast_rotation_free (2700542202836832631) -->
- <skip />
- <!-- no translation found for toast_rotation_locked (7484691306949652450) -->
- <skip />
+ <string name="toast_rotation_free" msgid="2700542202836832631">"Skjermen vil rotere automatisk."</string>
+ <string name="toast_rotation_locked" msgid="7484691306949652450">"Skjermrotering er låst."</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 6067cca..c642240 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -19,22 +19,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_label (7164937344850004466) -->
- <skip />
+ <string name="app_label" msgid="7164937344850004466">"Systeem-UI"</string>
<string name="status_bar_clear_all_button" msgid="7774721344716731603">"Wissen"</string>
- <!-- no translation found for status_bar_do_not_disturb_button (5812628897510997853) -->
- <skip />
- <!-- no translation found for status_bar_please_disturb_button (3345398298841572813) -->
- <skip />
+ <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Niet storen"</string>
+ <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Meldingen weergeven"</string>
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Geen meldingen"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Actief"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Meldingen"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Sluit de oplader aan"</string>
- <!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"De accu raakt op:"</string>
- <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
- <skip />
- <!-- no translation found for invalid_charger (4549105996740522523) -->
- <skip />
+ <string name="battery_low_subtitle" msgid="1752040062087829196">"De accu raakt leeg."</string>
+ <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> resterend"</string>
+ <string name="invalid_charger" msgid="4549105996740522523">"Opladen via USB niet ondersteund."\n"Gebruik alleen de bijgeleverde oplader."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Accugebruik"</string>
<!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
<skip />
@@ -45,12 +40,9 @@
<!-- 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) -->
- <skip />
+ <string name="recent_tasks_empty" msgid="1905484479067697884">"Geen recente toepassingen."</string>
<!-- no translation found for recent_tasks_app_label (3796483981246752469) -->
<skip />
- <!-- no translation found for toast_rotation_free (2700542202836832631) -->
- <skip />
- <!-- no translation found for toast_rotation_locked (7484691306949652450) -->
- <skip />
+ <string name="toast_rotation_free" msgid="2700542202836832631">"Scherm wordt automatisch geroteerd."</string>
+ <string name="toast_rotation_locked" msgid="7484691306949652450">"Schermrotatie is nu vergrendeld."</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 6b19a34..4f5f328 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -19,22 +19,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_label (7164937344850004466) -->
- <skip />
+ <string name="app_label" msgid="7164937344850004466">"Interfejs"</string>
<string name="status_bar_clear_all_button" msgid="7774721344716731603">"Wyczyść"</string>
- <!-- no translation found for status_bar_do_not_disturb_button (5812628897510997853) -->
- <skip />
- <!-- no translation found for status_bar_please_disturb_button (3345398298841572813) -->
- <skip />
+ <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Nie przeszkadzać"</string>
+ <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Pokaż powiadomienia"</string>
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Brak powiadomień"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Bieżące"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Powiadomienia"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Podłącz ładowarkę"</string>
- <!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Bateria się rozładowuje:"</string>
- <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
- <skip />
- <!-- no translation found for invalid_charger (4549105996740522523) -->
- <skip />
+ <string name="battery_low_subtitle" msgid="1752040062087829196">"Bateria wkrótce zostanie rozładowana."</string>
+ <string name="battery_low_percent_format" msgid="1077244949318261761">"Pozostało: <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="invalid_charger" msgid="4549105996740522523">"Ładowanie przy użyciu złącza USB nie jest obsługiwane."\n"Należy używać tylko dołączonej ładowarki."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Użycie baterii"</string>
<!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
<skip />
@@ -45,12 +40,9 @@
<!-- 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) -->
- <skip />
+ <string name="recent_tasks_empty" msgid="1905484479067697884">"Brak ostatnio używanych aplikacji."</string>
<!-- no translation found for recent_tasks_app_label (3796483981246752469) -->
<skip />
- <!-- no translation found for toast_rotation_free (2700542202836832631) -->
- <skip />
- <!-- no translation found for toast_rotation_locked (7484691306949652450) -->
- <skip />
+ <string name="toast_rotation_free" msgid="2700542202836832631">"Ekran zostanie obrócony automatycznie."</string>
+ <string name="toast_rotation_locked" msgid="7484691306949652450">"Obracanie ekranu zostało zablokowane."</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 7bf6eb4..8ec603a 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -19,22 +19,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_label (7164937344850004466) -->
- <skip />
+ <string name="app_label" msgid="7164937344850004466">"IU do sist."</string>
<string name="status_bar_clear_all_button" msgid="7774721344716731603">"Limpar"</string>
- <!-- no translation found for status_bar_do_not_disturb_button (5812628897510997853) -->
- <skip />
- <!-- no translation found for status_bar_please_disturb_button (3345398298841572813) -->
- <skip />
+ <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Não incomodar"</string>
+ <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Mostrar notificações"</string>
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Sem notificações"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Em curso"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificações"</string>
<string name="battery_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>
- <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
- <skip />
- <!-- no translation found for invalid_charger (4549105996740522523) -->
- <skip />
+ <string name="battery_low_subtitle" msgid="1752040062087829196">"A bateria está a ficar fraca."</string>
+ <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> restante"</string>
+ <string name="invalid_charger" msgid="4549105996740522523">"Carregamento USB não suportado. "\n"Utilize apenas o carregador fornecido."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Utilização da bateria"</string>
<!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
<skip />
@@ -45,12 +40,9 @@
<!-- 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) -->
- <skip />
+ <string name="recent_tasks_empty" msgid="1905484479067697884">"Nenhuma aplicação recente."</string>
<!-- no translation found for recent_tasks_app_label (3796483981246752469) -->
<skip />
- <!-- no translation found for toast_rotation_free (2700542202836832631) -->
- <skip />
- <!-- no translation found for toast_rotation_locked (7484691306949652450) -->
- <skip />
+ <string name="toast_rotation_free" msgid="2700542202836832631">"O ecrã será rodado automaticamente."</string>
+ <string name="toast_rotation_locked" msgid="7484691306949652450">"A rotação do ecrã está agora bloqueada."</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 14b4b1f..6f98ed6 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -19,22 +19,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_label (7164937344850004466) -->
- <skip />
+ <string name="app_label" msgid="7164937344850004466">"Interf sist"</string>
<string name="status_bar_clear_all_button" msgid="7774721344716731603">"Limpar"</string>
- <!-- no translation found for status_bar_do_not_disturb_button (5812628897510997853) -->
- <skip />
- <!-- no translation found for status_bar_please_disturb_button (3345398298841572813) -->
- <skip />
+ <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Não perturbe"</string>
+ <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Mostrar notificações"</string>
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Sem notificações"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Em andamento"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Notificações"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Conecte o carregador"</string>
- <!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"A bateria está ficando baixa:"</string>
- <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
- <skip />
- <!-- no translation found for invalid_charger (4549105996740522523) -->
- <skip />
+ <string name="battery_low_subtitle" msgid="1752040062087829196">"A bateria está ficando baixa."</string>
+ <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> restante"</string>
+ <string name="invalid_charger" msgid="4549105996740522523">"O carregamento via USB não é suportado."\n"Use apenas o carregador fornecido."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Uso da bateria"</string>
<!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
<skip />
@@ -45,12 +40,9 @@
<!-- 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) -->
- <skip />
+ <string name="recent_tasks_empty" msgid="1905484479067697884">"Nenhum aplicativo recente."</string>
<!-- no translation found for recent_tasks_app_label (3796483981246752469) -->
<skip />
- <!-- no translation found for toast_rotation_free (2700542202836832631) -->
- <skip />
- <!-- no translation found for toast_rotation_locked (7484691306949652450) -->
- <skip />
+ <string name="toast_rotation_free" msgid="2700542202836832631">"A tela girará automaticamente."</string>
+ <string name="toast_rotation_locked" msgid="7484691306949652450">"A rotação da tela está bloqueada."</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 0a15bcd..471525f 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -19,22 +19,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_label (7164937344850004466) -->
- <skip />
+ <string name="app_label" msgid="7164937344850004466">"Графический интерфейс системы"</string>
<string name="status_bar_clear_all_button" msgid="7774721344716731603">"Очистить"</string>
- <!-- no translation found for status_bar_do_not_disturb_button (5812628897510997853) -->
- <skip />
- <!-- no translation found for status_bar_please_disturb_button (3345398298841572813) -->
- <skip />
+ <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Не беспокоить"</string>
+ <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Показать уведомления"</string>
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Нет уведомлений"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Текущие"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Уведомления"</string>
<string name="battery_low_title" msgid="7923774589611311406">"Подключите зарядное устройство"</string>
- <!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"Батарея разряжена:"</string>
- <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
- <skip />
- <!-- no translation found for invalid_charger (4549105996740522523) -->
- <skip />
+ <string name="battery_low_subtitle" msgid="1752040062087829196">"Батарея разряжена."</string>
+ <string name="battery_low_percent_format" msgid="1077244949318261761">"Осталось: <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="invalid_charger" msgid="4549105996740522523">"Зарядка через порт USB не поддерживается."\n"Используйте только зарядное устройство из комплекта поставки."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Расход заряда батареи"</string>
<!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
<skip />
@@ -45,12 +40,9 @@
<!-- 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) -->
- <skip />
+ <string name="recent_tasks_empty" msgid="1905484479067697884">"Новых приложений нет"</string>
<!-- no translation found for recent_tasks_app_label (3796483981246752469) -->
<skip />
- <!-- no translation found for toast_rotation_free (2700542202836832631) -->
- <skip />
- <!-- no translation found for toast_rotation_locked (7484691306949652450) -->
- <skip />
+ <string name="toast_rotation_free" msgid="2700542202836832631">"Экран будет поворачиваться автоматически."</string>
+ <string name="toast_rotation_locked" msgid="7484691306949652450">"Поворот экрана заблокирован."</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 06188ab..7b7f29f 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -19,22 +19,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_label (7164937344850004466) -->
- <skip />
+ <string name="app_label" msgid="7164937344850004466">"Gränssnitt"</string>
<string name="status_bar_clear_all_button" msgid="7774721344716731603">"Ta bort"</string>
- <!-- no translation found for status_bar_do_not_disturb_button (5812628897510997853) -->
- <skip />
- <!-- no translation found for status_bar_please_disturb_button (3345398298841572813) -->
- <skip />
+ <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Stör ej"</string>
+ <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Visa aviseringar"</string>
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Inga aviseringar"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Pågående"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Meddelanden"</string>
<string name="battery_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>
- <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
- <skip />
- <!-- no translation found for invalid_charger (4549105996740522523) -->
- <skip />
+ <string name="battery_low_subtitle" msgid="1752040062087829196">"Batteriet håller på att ta slut."</string>
+ <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> återstår"</string>
+ <string name="invalid_charger" msgid="4549105996740522523">"Det går inte att ladda via USB."\n"Använd endast den laddare som levererades med telefonen."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Batteriförbrukning"</string>
<!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
<skip />
@@ -45,12 +40,9 @@
<!-- 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) -->
- <skip />
+ <string name="recent_tasks_empty" msgid="1905484479067697884">"Inga nya program."</string>
<!-- no translation found for recent_tasks_app_label (3796483981246752469) -->
<skip />
- <!-- no translation found for toast_rotation_free (2700542202836832631) -->
- <skip />
- <!-- no translation found for toast_rotation_locked (7484691306949652450) -->
- <skip />
+ <string name="toast_rotation_free" msgid="2700542202836832631">"Skärmen roteras automatiskt."</string>
+ <string name="toast_rotation_locked" msgid="7484691306949652450">"Skärmrotationen är nu låst."</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 253fbe0..7c31960 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -19,22 +19,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_label (7164937344850004466) -->
- <skip />
+ <string name="app_label" msgid="7164937344850004466">"Sist Arayüzü"</string>
<string name="status_bar_clear_all_button" msgid="7774721344716731603">"Temizle"</string>
- <!-- no translation found for status_bar_do_not_disturb_button (5812628897510997853) -->
- <skip />
- <!-- no translation found for status_bar_please_disturb_button (3345398298841572813) -->
- <skip />
+ <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"Rahatsız etmeyin"</string>
+ <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"Bildirimleri göster"</string>
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"Bildirim yok"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"Sürüyor"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"Bildirimler"</string>
<string name="battery_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>
- <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
- <skip />
- <!-- no translation found for invalid_charger (4549105996740522523) -->
- <skip />
+ <string name="battery_low_subtitle" msgid="1752040062087829196">"Pil azalıyor."</string>
+ <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> kaldı"</string>
+ <string name="invalid_charger" msgid="4549105996740522523">"USB üzerinden şarj desteklenmiyor."\n"Yalnızca ürünle birlikte verilen şarj cihazını kullanın."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Pil kullanımı"</string>
<!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
<skip />
@@ -45,12 +40,9 @@
<!-- 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) -->
- <skip />
+ <string name="recent_tasks_empty" msgid="1905484479067697884">"Hiçbir yeni uygulama yok."</string>
<!-- no translation found for recent_tasks_app_label (3796483981246752469) -->
<skip />
- <!-- no translation found for toast_rotation_free (2700542202836832631) -->
- <skip />
- <!-- no translation found for toast_rotation_locked (7484691306949652450) -->
- <skip />
+ <string name="toast_rotation_free" msgid="2700542202836832631">"Ekran otomatik olarak dönecektir."</string>
+ <string name="toast_rotation_locked" msgid="7484691306949652450">"Ekran dönüşü şimdi kilitlendi."</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 161a085..4705013 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -19,22 +19,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_label (7164937344850004466) -->
- <skip />
+ <string name="app_label" msgid="7164937344850004466">"系统用户界面"</string>
<string name="status_bar_clear_all_button" msgid="7774721344716731603">"清除"</string>
- <!-- no translation found for status_bar_do_not_disturb_button (5812628897510997853) -->
- <skip />
- <!-- no translation found for status_bar_please_disturb_button (3345398298841572813) -->
- <skip />
+ <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"请勿打扰"</string>
+ <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"显示通知"</string>
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"无通知"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"正在进行的"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
<string name="battery_low_title" msgid="7923774589611311406">"请连接充电器"</string>
- <!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"电量所剩不多:"</string>
- <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
- <skip />
- <!-- no translation found for invalid_charger (4549105996740522523) -->
- <skip />
+ <string name="battery_low_subtitle" msgid="1752040062087829196">"电池电量低。"</string>
+ <string name="battery_low_percent_format" msgid="1077244949318261761">"还剩 <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="invalid_charger" msgid="4549105996740522523">"不支持 USB 充电功能。"\n"只能使用随附的充电器充电。"</string>
<string name="battery_low_why" msgid="7279169609518386372">"电量使用情况"</string>
<!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
<skip />
@@ -45,12 +40,9 @@
<!-- 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) -->
- <skip />
+ <string name="recent_tasks_empty" msgid="1905484479067697884">"没有最近使用的应用程序。"</string>
<!-- no translation found for recent_tasks_app_label (3796483981246752469) -->
<skip />
- <!-- no translation found for toast_rotation_free (2700542202836832631) -->
- <skip />
- <!-- no translation found for toast_rotation_locked (7484691306949652450) -->
- <skip />
+ <string name="toast_rotation_free" msgid="2700542202836832631">"屏幕会自动旋转。"</string>
+ <string name="toast_rotation_locked" msgid="7484691306949652450">"屏幕旋转现已锁定。"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index eb9108d..ec9c298 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -19,22 +19,17 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- no translation found for app_label (7164937344850004466) -->
- <skip />
+ <string name="app_label" msgid="7164937344850004466">"系統 UI"</string>
<string name="status_bar_clear_all_button" msgid="7774721344716731603">"清除"</string>
- <!-- no translation found for status_bar_do_not_disturb_button (5812628897510997853) -->
- <skip />
- <!-- no translation found for status_bar_please_disturb_button (3345398298841572813) -->
- <skip />
+ <string name="status_bar_do_not_disturb_button" msgid="5812628897510997853">"勿干擾"</string>
+ <string name="status_bar_please_disturb_button" msgid="3345398298841572813">"顯示通知"</string>
<string name="status_bar_no_notifications_title" msgid="4755261167193833213">"沒有通知"</string>
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"進行中"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"通知"</string>
<string name="battery_low_title" msgid="7923774589611311406">"請連接充電器"</string>
- <!-- outdated translation 7388781709819722764 --> <string name="battery_low_subtitle" msgid="1752040062087829196">"電池電量即將不足:"</string>
- <!-- no translation found for battery_low_percent_format (1077244949318261761) -->
- <skip />
- <!-- no translation found for invalid_charger (4549105996740522523) -->
- <skip />
+ <string name="battery_low_subtitle" msgid="1752040062087829196">"電池電量即將不足。"</string>
+ <string name="battery_low_percent_format" msgid="1077244949318261761">"還剩 <xliff:g id="NUMBER">%d%%</xliff:g>"</string>
+ <string name="invalid_charger" msgid="4549105996740522523">"不支援 USB 充電。"\n"僅能使用隨附的充電器。"</string>
<string name="battery_low_why" msgid="7279169609518386372">"電池使用狀況"</string>
<!-- no translation found for status_bar_settings_settings_button (3023889916699270224) -->
<skip />
@@ -45,12 +40,9 @@
<!-- 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) -->
- <skip />
+ <string name="recent_tasks_empty" msgid="1905484479067697884">"沒有最近用過的應用程式。"</string>
<!-- no translation found for recent_tasks_app_label (3796483981246752469) -->
<skip />
- <!-- no translation found for toast_rotation_free (2700542202836832631) -->
- <skip />
- <!-- no translation found for toast_rotation_locked (7484691306949652450) -->
- <skip />
+ <string name="toast_rotation_free" msgid="2700542202836832631">"螢幕會自動旋轉。"</string>
+ <string name="toast_rotation_locked" msgid="7484691306949652450">"螢幕旋轉功能現已鎖定。"</string>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
index d1e61a9..4d0835f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/ShirtPocket.java
@@ -169,7 +169,7 @@ public class ShirtPocket extends FrameLayout {
thumb = new DragThumbnailBuilder(mWindow.findViewById(R.id.preview));
}
- v.startDrag(clip, thumb, false);
+ v.startDrag(clip, thumb, false, null);
// TODO: only discard the clipping if it was accepted
stash(null);
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 c55c87e..563b8ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -114,6 +114,7 @@ public class TabletStatusBar extends StatusBar {
NotificationPeekPanel mNotificationPeekWindow;
ViewGroup mNotificationPeekRow;
int mNotificationPeekIndex;
+ IBinder mNotificationPeekKey;
LayoutTransition mNotificationPeekScrubLeft, mNotificationPeekScrubRight;
int mNotificationPeekTapDuration;
@@ -344,9 +345,11 @@ public class TabletStatusBar extends StatusBar {
if (DEBUG) Slog.d(TAG, "opening notification peek window; arg=" + m.arg1);
if (m.arg1 >= 0) {
final int N = mNotns.size();
- if (mNotificationPeekIndex < N) {
+ if (mNotificationPeekIndex >= 0 && mNotificationPeekIndex < N) {
NotificationData.Entry entry = mNotns.get(N-1-mNotificationPeekIndex);
entry.icon.setBackgroundColor(0);
+ mNotificationPeekIndex = -1;
+ mNotificationPeekKey = null;
}
final int peekIndex = m.arg1;
@@ -373,6 +376,7 @@ public class TabletStatusBar extends StatusBar {
mNotificationPanel.setVisibility(View.GONE);
mNotificationPeekIndex = peekIndex;
+ mNotificationPeekKey = entry.key;
}
}
break;
@@ -381,10 +385,13 @@ public class TabletStatusBar extends StatusBar {
mNotificationPeekWindow.setVisibility(View.GONE);
mNotificationPeekRow.removeAllViews();
final int N = mNotns.size();
- if (mNotificationPeekIndex < N) {
+ if (mNotificationPeekIndex >= 0 && mNotificationPeekIndex < N) {
NotificationData.Entry entry = mNotns.get(N-1-mNotificationPeekIndex);
entry.icon.setBackgroundColor(0);
}
+
+ mNotificationPeekIndex = -1;
+ mNotificationPeekKey = null;
break;
case MSG_OPEN_NOTIFICATION_PANEL:
if (DEBUG) Slog.d(TAG, "opening notifications panel");
@@ -496,7 +503,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
@@ -508,7 +515,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
@@ -516,7 +523,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 {
@@ -644,6 +654,12 @@ public class TabletStatusBar extends StatusBar {
// called by StatusBar
@Override
public void setLightsOn(boolean on) {
+ // Policy note: if the frontmost activity needs the menu key, we assume it is a legacy app
+ // that can't handle lights-out mode.
+ if (mMenuButton.getVisibility() == View.VISIBLE
+ || mMenuShadow.getVisibility() == View.VISIBLE) {
+ on = true;
+ }
mHandler.removeMessages(MSG_SHOW_SHADOWS);
mHandler.removeMessages(MSG_HIDE_SHADOWS);
mHandler.sendEmptyMessage(on ? MSG_HIDE_SHADOWS : MSG_SHOW_SHADOWS);
@@ -654,6 +670,9 @@ public class TabletStatusBar extends StatusBar {
Slog.d(TAG, (visible?"showing":"hiding") + " the MENU button");
}
mMenuButton.setVisibility(visible ? View.VISIBLE : View.GONE);
+
+ // See above re: lights-out policy for legacy apps.
+ if (visible) setLightsOn(true);
}
public void setIMEButtonVisible(IBinder token, boolean visible) {
@@ -811,6 +830,11 @@ public class TabletStatusBar extends StatusBar {
// Remove the expanded view.
ViewGroup rowParent = (ViewGroup)entry.row.getParent();
if (rowParent != null) rowParent.removeView(entry.row);
+
+ if (key == mNotificationPeekKey) {
+ // must close the peek as well, since it's gone
+ mHandler.sendEmptyMessage(MSG_CLOSE_NOTIFICATION_PEEK);
+ }
// Remove the icon.
// ViewGroup iconParent = (ViewGroup)entry.icon.getParent();
// if (iconParent != null) iconParent.removeView(entry.icon);
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/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index cd8a065..138dff7 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -160,6 +160,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
private ContextMenuBuilder mContextMenu;
private MenuDialogHelper mContextMenuHelper;
+ private ActionButtonSubmenu mActionButtonPopup;
+ private boolean mClosingActionMenu;
private int mVolumeControlStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE;
@@ -542,6 +544,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (doCallback) {
callOnPanelClosed(st.featureId, st, null);
}
+ } else if (st.featureId == FEATURE_OPTIONS_PANEL && doCallback &&
+ mActionBar != null) {
+ checkCloseActionMenu(st.menu);
}
st.isPrepared = false;
st.isHandled = false;
@@ -563,6 +568,27 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
}
+ private void checkCloseActionMenu(Menu menu) {
+ if (mClosingActionMenu) {
+ return;
+ }
+
+ boolean closed = false;
+ mClosingActionMenu = true;
+ if (mActionBar.isOverflowMenuOpen() && mActionBar.hideOverflowMenu()) {
+ closed = true;
+ }
+ if (mActionButtonPopup != null) {
+ mActionButtonPopup.dismiss();
+ closed = true;
+ }
+ Callback cb = getCallback();
+ if (cb != null && closed) {
+ cb.onPanelClosed(FEATURE_ACTION_BAR, menu);
+ }
+ mClosingActionMenu = false;
+ }
+
@Override
public final void togglePanel(int featureId, KeyEvent event) {
PanelFeatureState st = getPanelState(featureId, true);
@@ -842,7 +868,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
// The window manager will give us a valid window token
new MenuDialogHelper(subMenu).show(null);
} else {
- new MenuPopupHelper(getContext(), subMenu).show();
+ mActionButtonPopup = new ActionButtonSubmenu(getContext(), subMenu);
+ mActionButtonPopup.show();
+ Callback cb = getCallback();
+ if (cb != null) {
+ cb.onMenuOpened(FEATURE_ACTION_BAR, subMenu);
+ }
}
return true;
@@ -854,16 +885,21 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
private void reopenMenu(boolean toggleMenuMode) {
if (mActionBar != null) {
+ final Callback cb = getCallback();
if (!mActionBar.isOverflowMenuShowing() || !toggleMenuMode) {
- final Callback cb = getCallback();
if (cb != null) {
final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true);
if (cb.onPreparePanel(FEATURE_OPTIONS_PANEL, st.createdPanelView, st.menu)) {
- mActionBar.showOverflowMenu();
+ cb.onMenuOpened(FEATURE_ACTION_BAR, st.menu);
+ mActionBar.openOverflowMenu();
}
}
} else {
mActionBar.hideOverflowMenu();
+ if (cb != null) {
+ final PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, true);
+ cb.onPanelClosed(FEATURE_ACTION_BAR, st.menu);
+ }
}
return;
}
@@ -2042,8 +2078,23 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
if (cb != null && mFeatureId < 0) {
cb.onDetachedFromWindow();
}
+
+ if (mActionButtonPopup != null) {
+ if (mActionButtonPopup.isShowing()) {
+ mActionButtonPopup.dismiss();
+ }
+ mActionButtonPopup = null;
+ }
}
-
+
+ @Override
+ protected void onConfigurationChanged(Configuration newConfig) {
+ if (mActionButtonPopup != null) {
+ mActionButtonPopup.dismiss();
+ post(mActionButtonPopup);
+ }
+ }
+
@Override
public void onCloseSystemDialogs(String reason) {
if (mFeatureId >= 0) {
@@ -2921,4 +2972,29 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
void sendCloseSystemWindows(String reason) {
PhoneWindowManager.sendCloseSystemWindows(getContext(), reason);
}
+
+ private class ActionButtonSubmenu extends MenuPopupHelper implements Runnable {
+ private SubMenuBuilder mSubMenu;
+
+ public ActionButtonSubmenu(Context context, SubMenuBuilder subMenu) {
+ super(context, subMenu);
+ mSubMenu = subMenu;
+ }
+
+ @Override
+ public void onDismiss() {
+ super.onDismiss();
+ mSubMenu.getCallback().onCloseSubMenu(mSubMenu);
+ mActionButtonPopup = null;
+ }
+
+ @Override
+ public void run() {
+ show();
+ Callback cb = getCallback();
+ if (cb != null) {
+ cb.onMenuOpened(FEATURE_ACTION_BAR, mSubMenu);
+ }
+ }
+ }
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 1373627..c3112d8 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;
}
@@ -1816,12 +1820,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
final IStatusBarService sbs = mStatusBarService;
if (mStatusBarService != null) {
try {
- if (changedFullscreen) {
- sbs.setActiveWindowIsFullscreen(topIsFullscreenF);
- }
if (changedMenu) {
sbs.setMenuKeyVisible(topNeedsMenuF);
}
+ if (changedFullscreen) {
+ sbs.setActiveWindowIsFullscreen(topIsFullscreenF);
+ }
} catch (RemoteException e) {
// This should be impossible because we're in the same process.
mStatusBarService = null;
@@ -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/audioflinger/AudioPolicyManagerBase.cpp b/services/audioflinger/AudioPolicyManagerBase.cpp
index e3b5db1..175f613 100644
--- a/services/audioflinger/AudioPolicyManagerBase.cpp
+++ b/services/audioflinger/AudioPolicyManagerBase.cpp
@@ -81,12 +81,6 @@ status_t AudioPolicyManagerBase::setDeviceConnectionState(AudioSystem::audio_dev
LOGV("setDeviceConnectionState() BT SCO device, address %s", device_address);
// keep track of SCO device address
mScoDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
-#ifdef WITH_A2DP
- if (mA2dpOutput != 0 &&
- mPhoneState != AudioSystem::MODE_NORMAL) {
- mpClientInterface->suspendOutput(mA2dpOutput);
- }
-#endif
}
}
break;
@@ -115,12 +109,6 @@ status_t AudioPolicyManagerBase::setDeviceConnectionState(AudioSystem::audio_dev
{
if (AudioSystem::isBluetoothScoDevice(device)) {
mScoDeviceAddress = "";
-#ifdef WITH_A2DP
- if (mA2dpOutput != 0 &&
- mPhoneState != AudioSystem::MODE_NORMAL) {
- mpClientInterface->restoreOutput(mA2dpOutput);
- }
-#endif
}
}
} break;
@@ -138,6 +126,7 @@ status_t AudioPolicyManagerBase::setDeviceConnectionState(AudioSystem::audio_dev
if (state == AudioSystem::DEVICE_STATE_UNAVAILABLE && AudioSystem::isA2dpDevice(device)) {
closeA2dpOutputs();
}
+ checkA2dpSuspend();
#endif
updateDeviceForStrategy();
setOutputDevice(mHardwareOutput, newDevice);
@@ -280,14 +269,7 @@ void AudioPolicyManagerBase::setPhoneState(int state)
newDevice = getNewDevice(mHardwareOutput, false);
#ifdef WITH_A2DP
checkOutputForAllStrategies();
- // suspend A2DP output if a SCO device is present.
- if (mA2dpOutput != 0 && mScoDeviceAddress != "") {
- if (oldState == AudioSystem::MODE_NORMAL) {
- mpClientInterface->suspendOutput(mA2dpOutput);
- } else if (state == AudioSystem::MODE_NORMAL) {
- mpClientInterface->restoreOutput(mA2dpOutput);
- }
- }
+ checkA2dpSuspend();
#endif
updateDeviceForStrategy();
@@ -397,6 +379,7 @@ void AudioPolicyManagerBase::setForceUse(AudioSystem::force_use usage, AudioSyst
uint32_t newDevice = getNewDevice(mHardwareOutput, false);
#ifdef WITH_A2DP
checkOutputForAllStrategies();
+ checkA2dpSuspend();
#endif
updateDeviceForStrategy();
setOutputDevice(mHardwareOutput, newDevice);
@@ -1025,8 +1008,10 @@ AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clien
#ifdef AUDIO_POLICY_TEST
Thread(false),
#endif //AUDIO_POLICY_TEST
- mPhoneState(AudioSystem::MODE_NORMAL), mRingerMode(0), mMusicStopTime(0), mLimitRingtoneVolume(false),
- mLastVoiceVolume(-1.0f), mTotalEffectsCpuLoad(0), mTotalEffectsMemory(0)
+ mPhoneState(AudioSystem::MODE_NORMAL), mRingerMode(0),
+ mMusicStopTime(0), mLimitRingtoneVolume(false), mLastVoiceVolume(-1.0f),
+ mTotalEffectsCpuLoad(0), mTotalEffectsMemory(0),
+ mA2dpSuspended(false)
{
mpClientInterface = clientInterface;
@@ -1322,17 +1307,6 @@ status_t AudioPolicyManagerBase::handleA2dpConnection(AudioSystem::audio_devices
}
AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mHardwareOutput);
- if (mScoDeviceAddress != "") {
- // It is normal to suspend twice if we are both in call,
- // and have the hardware audio output routed to BT SCO
- if (mPhoneState != AudioSystem::MODE_NORMAL) {
- mpClientInterface->suspendOutput(mA2dpOutput);
- }
- if (AudioSystem::isBluetoothScoDevice((AudioSystem::audio_devices)hwOutputDesc->device())) {
- mpClientInterface->suspendOutput(mA2dpOutput);
- }
- }
-
if (!a2dpUsedForSonification()) {
// mute music on A2DP output if a notification or ringtone is playing
uint32_t refCount = hwOutputDesc->strategyRefCount(STRATEGY_SONIFICATION);
@@ -1340,6 +1314,9 @@ status_t AudioPolicyManagerBase::handleA2dpConnection(AudioSystem::audio_devices
setStrategyMute(STRATEGY_MEDIA, true, mA2dpOutput);
}
}
+
+ mA2dpSuspended = false;
+
return NO_ERROR;
}
@@ -1369,6 +1346,7 @@ status_t AudioPolicyManagerBase::handleA2dpDisconnection(AudioSystem::audio_devi
}
}
mA2dpDeviceAddress = "";
+ mA2dpSuspended = false;
return NO_ERROR;
}
@@ -1467,6 +1445,48 @@ void AudioPolicyManagerBase::checkOutputForAllStrategies()
checkOutputForStrategy(STRATEGY_DTMF);
}
+void AudioPolicyManagerBase::checkA2dpSuspend()
+{
+ // suspend A2DP output if:
+ // (NOT already suspended) &&
+ // ((SCO device is connected &&
+ // (forced usage for communication || for record is SCO))) ||
+ // (phone state is ringing || in call)
+ //
+ // restore A2DP output if:
+ // (Already suspended) &&
+ // ((SCO device is NOT connected ||
+ // (forced usage NOT for communication && NOT for record is SCO))) &&
+ // (phone state is NOT ringing && NOT in call)
+ //
+ if (mA2dpOutput == 0) {
+ return;
+ }
+
+ if (mA2dpSuspended) {
+ if (((mScoDeviceAddress == "") ||
+ ((mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO) &&
+ (mForceUse[AudioSystem::FOR_RECORD] != AudioSystem::FORCE_BT_SCO))) &&
+ ((mPhoneState != AudioSystem::MODE_IN_CALL) &&
+ (mPhoneState != AudioSystem::MODE_RINGTONE))) {
+
+ mpClientInterface->restoreOutput(mA2dpOutput);
+ mA2dpSuspended = false;
+ }
+ } else {
+ if (((mScoDeviceAddress != "") &&
+ ((mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) ||
+ (mForceUse[AudioSystem::FOR_RECORD] == AudioSystem::FORCE_BT_SCO))) ||
+ ((mPhoneState == AudioSystem::MODE_IN_CALL) ||
+ (mPhoneState == AudioSystem::MODE_RINGTONE))) {
+
+ mpClientInterface->suspendOutput(mA2dpOutput);
+ mA2dpSuspended = true;
+ }
+ }
+}
+
+
#endif
uint32_t AudioPolicyManagerBase::getNewDevice(audio_io_handle_t output, bool fromCache)
@@ -1714,14 +1734,7 @@ void AudioPolicyManagerBase::setOutputDevice(audio_io_handle_t output, uint32_t
// wait for the PCM output buffers to empty before proceeding with the rest of the command
usleep(outputDesc->mLatency*2*1000);
}
-#ifdef WITH_A2DP
- // suspend A2DP output if SCO device is selected
- if (AudioSystem::isBluetoothScoDevice((AudioSystem::audio_devices)device)) {
- if (mA2dpOutput != 0) {
- mpClientInterface->suspendOutput(mA2dpOutput);
- }
- }
-#endif
+
// do the routing
AudioParameter param = AudioParameter();
param.addInt(String8(AudioParameter::keyRouting), (int)device);
@@ -1729,15 +1742,6 @@ void AudioPolicyManagerBase::setOutputDevice(audio_io_handle_t output, uint32_t
// update stream volumes according to new device
applyStreamVolumes(output, device, delayMs);
-#ifdef WITH_A2DP
- // if disconnecting SCO device, restore A2DP output
- if (AudioSystem::isBluetoothScoDevice((AudioSystem::audio_devices)prevDevice)) {
- if (mA2dpOutput != 0) {
- LOGV("restore A2DP output");
- mpClientInterface->restoreOutput(mA2dpOutput);
- }
- }
-#endif
// if changing from a combined headset + speaker route, unmute media streams
if (output == mHardwareOutput && AudioSystem::popCount(prevDevice) == 2) {
setStrategyMute(STRATEGY_MEDIA, false, output, delayMs);
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/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/ScreenRotationAnimation.java b/services/java/com/android/server/ScreenRotationAnimation.java
index 1cc6a2a..a95a6c7 100644
--- a/services/java/com/android/server/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/ScreenRotationAnimation.java
@@ -122,7 +122,9 @@ class ScreenRotationAnimation {
mSurface.unlockCanvasAndPost(c);
Surface.closeTransaction();
- screenshot.recycle();
+ if (screenshot != null) {
+ screenshot.recycle();
+ }
}
static int deltaRotation(int oldRotation, int newRotation) {
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index cbb35c6..d7a6a0e 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -619,7 +619,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (mDragInProgress && newWin.isPotentialDragTarget()) {
DragEvent event = DragEvent.obtain(DragEvent.ACTION_DRAG_STARTED,
touchX - newWin.mFrame.left, touchY - newWin.mFrame.top,
- desc, null, false);
+ null, desc, null, false);
try {
newWin.mClient.dispatchDragEvent(event);
// track each window that we've notified that the drag is starting
@@ -659,7 +659,7 @@ public class WindowManagerService extends IWindowManager.Stub
Slog.d(TAG, "broadcasting DRAG_ENDED");
}
DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_ENDED,
- 0, 0, null, null, mDragResult);
+ 0, 0, null, null, null, mDragResult);
for (WindowState ws: mNotifiedWindows) {
try {
ws.mClient.dispatchDragEvent(evt);
@@ -711,7 +711,7 @@ public class WindowManagerService extends IWindowManager.Stub
// force DRAG_EXITED_EVENT if appropriate
DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_EXITED,
x - mTargetWindow.mFrame.left, y - mTargetWindow.mFrame.top,
- null, null, false);
+ null, null, null, false);
mTargetWindow.mClient.dispatchDragEvent(evt);
if (myPid != mTargetWindow.mSession.mPid) {
evt.recycle();
@@ -723,7 +723,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_LOCATION,
x - touchedWin.mFrame.left, y - touchedWin.mFrame.top,
- null, null, false);
+ null, null, null, false);
touchedWin.mClient.dispatchDragEvent(evt);
if (myPid != touchedWin.mSession.mPid) {
evt.recycle();
@@ -754,7 +754,7 @@ public class WindowManagerService extends IWindowManager.Stub
final IBinder token = touchedWin.mClient.asBinder();
DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DROP,
x - touchedWin.mFrame.left, y - touchedWin.mFrame.top,
- null, mData, false);
+ null, null, mData, false);
try {
touchedWin.mClient.dispatchDragEvent(evt);
@@ -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.
@@ -6853,6 +6848,8 @@ public class WindowManagerService extends IWindowManager.Stub
}
if (!mParentFrame.equals(pf)) {
+ //Slog.i(TAG, "Window " + this + " content frame from " + mParentFrame
+ // + " to " + pf);
mParentFrame.set(pf);
mContentChanged = true;
}
@@ -7739,12 +7736,10 @@ public class WindowManagerService extends IWindowManager.Stub
* sense to call from performLayoutAndPlaceSurfacesLockedInner().)
*/
boolean shouldAnimateMove() {
- return mContentChanged && !mAnimating && !mLastHidden && !mDisplayFrozen
+ return mContentChanged && !mExiting && !mLastHidden && !mDisplayFrozen
&& (mFrame.top != mLastFrame.top
|| mFrame.left != mLastFrame.left)
- && (mAttachedWindow == null
- || (mAttachedWindow.mAnimation == null
- && !mAttachedWindow.shouldAnimateMove()))
+ && (mAttachedWindow == null || !mAttachedWindow.shouldAnimateMove())
&& mPolicy.isScreenOn();
}
@@ -9228,6 +9223,7 @@ public class WindowManagerService extends IWindowManager.Stub
if (!gone || !win.mHaveFrame) {
if (!win.mLayoutAttached) {
if (initial) {
+ //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
win.mContentChanged = false;
}
mPolicy.layoutWindowLw(win, win.mAttrs, null);
@@ -9262,6 +9258,7 @@ public class WindowManagerService extends IWindowManager.Stub
if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
|| !win.mHaveFrame) {
if (initial) {
+ //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
win.mContentChanged = false;
}
mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
@@ -9460,7 +9457,6 @@ public class WindowManagerService extends IWindowManager.Stub
w.setAnimation(a);
animDw = w.mLastFrame.left - w.mFrame.left;
animDh = w.mLastFrame.top - w.mFrame.top;
- w.mContentChanged = false;
}
// Execute animation.
@@ -10247,6 +10243,11 @@ public class WindowManagerService extends IWindowManager.Stub
w.mOrientationChanging = false;
}
+ if (w.mContentChanged) {
+ //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
+ w.mContentChanged = false;
+ }
+
final boolean canBeSeen = w.isDisplayedLw();
if (someoneLosingFocus && w == mCurrentFocus && canBeSeen) {
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/services/sensorservice/GravitySensor.cpp b/services/sensorservice/GravitySensor.cpp
index 18bd359..5c6aa99 100644
--- a/services/sensorservice/GravitySensor.cpp
+++ b/services/sensorservice/GravitySensor.cpp
@@ -29,8 +29,8 @@ namespace android {
GravitySensor::GravitySensor(sensor_t const* list, size_t count)
: mSensorDevice(SensorDevice::getInstance()),
- mEnabled(false), mAccTime(0),
- mLowPass(M_SQRT1_2, 1),
+ mAccTime(0),
+ mLowPass(M_SQRT1_2, 1.5f),
mX(mLowPass), mY(mLowPass), mZ(mLowPass)
{
@@ -71,15 +71,9 @@ bool GravitySensor::process(sensors_event_t* outEvent,
}
return false;
}
-
-bool GravitySensor::isEnabled() const {
- return mEnabled;
-}
-
status_t GravitySensor::activate(void* ident, bool enabled) {
status_t err = mSensorDevice.activate(this, mAccelerometer.getHandle(), enabled);
if (err == NO_ERROR) {
- mEnabled = enabled;
if (enabled) {
mAccTime = 0;
}
diff --git a/services/sensorservice/GravitySensor.h b/services/sensorservice/GravitySensor.h
index f9850b7..decfbb8 100644
--- a/services/sensorservice/GravitySensor.h
+++ b/services/sensorservice/GravitySensor.h
@@ -33,17 +33,15 @@ namespace android {
class GravitySensor : public SensorInterface {
SensorDevice& mSensorDevice;
Sensor mAccelerometer;
- bool mEnabled;
double mAccTime;
SecondOrderLowPassFilter mLowPass;
- BiquadFilter mX, mY, mZ;
+ CascadedBiquadFilter mX, mY, mZ;
public:
GravitySensor(sensor_t const* list, size_t count);
virtual bool process(sensors_event_t* outEvent,
const sensors_event_t& event);
- virtual bool isEnabled() const;
virtual status_t activate(void* ident, bool enabled);
virtual status_t setDelay(void* ident, int handle, int64_t ns);
virtual Sensor getSensor() const;
diff --git a/services/sensorservice/LinearAccelerationSensor.cpp b/services/sensorservice/LinearAccelerationSensor.cpp
index 2dc12dc..9425a92 100644
--- a/services/sensorservice/LinearAccelerationSensor.cpp
+++ b/services/sensorservice/LinearAccelerationSensor.cpp
@@ -53,10 +53,6 @@ bool LinearAccelerationSensor::process(sensors_event_t* outEvent,
return result;
}
-bool LinearAccelerationSensor::isEnabled() const {
- return mGravitySensor.isEnabled();
-}
-
status_t LinearAccelerationSensor::activate(void* ident, bool enabled) {
return mGravitySensor.activate(ident, enabled);
}
diff --git a/services/sensorservice/LinearAccelerationSensor.h b/services/sensorservice/LinearAccelerationSensor.h
index ee918ce..c577086 100644
--- a/services/sensorservice/LinearAccelerationSensor.h
+++ b/services/sensorservice/LinearAccelerationSensor.h
@@ -40,7 +40,6 @@ class LinearAccelerationSensor : public SensorInterface {
const sensors_event_t& event);
public:
LinearAccelerationSensor(sensor_t const* list, size_t count);
- virtual bool isEnabled() const;
virtual status_t activate(void* ident, bool enabled);
virtual status_t setDelay(void* ident, int handle, int64_t ns);
virtual Sensor getSensor() const;
diff --git a/services/sensorservice/RotationVectorSensor.cpp b/services/sensorservice/RotationVectorSensor.cpp
index 6f4b8be..418e7f8 100644
--- a/services/sensorservice/RotationVectorSensor.cpp
+++ b/services/sensorservice/RotationVectorSensor.cpp
@@ -34,7 +34,6 @@ static inline T clamp(T v) {
RotationVectorSensor::RotationVectorSensor(sensor_t const* list, size_t count)
: mSensorDevice(SensorDevice::getInstance()),
- mEnabled(false),
mALowPass(M_SQRT1_2, 5.0f),
mAX(mALowPass), mAY(mALowPass), mAZ(mALowPass),
mMLowPass(M_SQRT1_2, 2.5f),
@@ -114,15 +113,18 @@ bool RotationVectorSensor::process(sensors_event_t* outEvent,
float qx = sqrtf( clamp( Hx - My - Az + 1) * 0.25f );
float qy = sqrtf( clamp(-Hx + My - Az + 1) * 0.25f );
float qz = sqrtf( clamp(-Hx - My + Az + 1) * 0.25f );
- const float n = 1.0f / (qw*qw + qx*qx + qy*qy + qz*qz);
- qx = copysignf(qx, Ay - Mz) * n;
- qy = copysignf(qy, Hz - Ax) * n;
- qz = copysignf(qz, Mx - Hy) * n;
+ qx = copysignf(qx, Ay - Mz);
+ qy = copysignf(qy, Hz - Ax);
+ qz = copysignf(qz, Mx - Hy);
+
+ // this quaternion is guaranteed to be normalized, by construction
+ // of the rotation matrix.
*outEvent = event;
outEvent->data[0] = qx;
outEvent->data[1] = qy;
outEvent->data[2] = qz;
+ outEvent->data[3] = qw;
outEvent->sensor = '_rov';
outEvent->type = SENSOR_TYPE_ROTATION_VECTOR;
return true;
@@ -130,19 +132,12 @@ bool RotationVectorSensor::process(sensors_event_t* outEvent,
return false;
}
-bool RotationVectorSensor::isEnabled() const {
- return mEnabled;
-}
-
status_t RotationVectorSensor::activate(void* ident, bool enabled) {
- if (mEnabled != enabled) {
- mSensorDevice.activate(this, mAcc.getHandle(), enabled);
- mSensorDevice.activate(this, mMag.getHandle(), enabled);
- mEnabled = enabled;
- if (enabled) {
- mMagTime = 0;
- mAccTime = 0;
- }
+ mSensorDevice.activate(this, mAcc.getHandle(), enabled);
+ mSensorDevice.activate(this, mMag.getHandle(), enabled);
+ if (enabled) {
+ mMagTime = 0;
+ mAccTime = 0;
}
return NO_ERROR;
}
diff --git a/services/sensorservice/RotationVectorSensor.h b/services/sensorservice/RotationVectorSensor.h
index e7f28c9..b7c9512 100644
--- a/services/sensorservice/RotationVectorSensor.h
+++ b/services/sensorservice/RotationVectorSensor.h
@@ -34,7 +34,6 @@ class RotationVectorSensor : public SensorInterface {
SensorDevice& mSensorDevice;
Sensor mAcc;
Sensor mMag;
- bool mEnabled;
float mMagData[3];
double mAccTime;
double mMagTime;
@@ -47,7 +46,6 @@ public:
RotationVectorSensor(sensor_t const* list, size_t count);
virtual bool process(sensors_event_t* outEvent,
const sensors_event_t& event);
- virtual bool isEnabled() const;
virtual status_t activate(void* ident, bool enabled);
virtual status_t setDelay(void* ident, int handle, int64_t ns);
virtual Sensor getSensor() const;
diff --git a/services/sensorservice/SecondOrderLowPassFilter.cpp b/services/sensorservice/SecondOrderLowPassFilter.cpp
index e13e136..eeb6d1e 100644
--- a/services/sensorservice/SecondOrderLowPassFilter.cpp
+++ b/services/sensorservice/SecondOrderLowPassFilter.cpp
@@ -67,4 +67,23 @@ float BiquadFilter::operator()(float x)
}
// ---------------------------------------------------------------------------
+
+CascadedBiquadFilter::CascadedBiquadFilter(const SecondOrderLowPassFilter& s)
+ : mA(s), mB(s)
+{
+}
+
+float CascadedBiquadFilter::init(float x)
+{
+ mA.init(x);
+ mB.init(x);
+ return x;
+}
+
+float CascadedBiquadFilter::operator()(float x)
+{
+ return mB(mA(x));
+}
+
+// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/sensorservice/SecondOrderLowPassFilter.h b/services/sensorservice/SecondOrderLowPassFilter.h
index 998ca35..85698ca 100644
--- a/services/sensorservice/SecondOrderLowPassFilter.h
+++ b/services/sensorservice/SecondOrderLowPassFilter.h
@@ -54,6 +54,18 @@ public:
float operator()(float in);
};
+/*
+ * Two cascaded biquad IIR filters
+ * (4-poles IIR)
+ */
+class CascadedBiquadFilter {
+ BiquadFilter mA;
+ BiquadFilter mB;
+public:
+ CascadedBiquadFilter(const SecondOrderLowPassFilter& s);
+ float init(float in);
+ float operator()(float in);
+};
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 73f85ba..f192913 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -137,9 +137,8 @@ void SensorDevice::dump(String8& result, char* buffer, size_t SIZE)
Mutex::Autolock _l(mLock);
for (size_t i=0 ; i<size_t(count) ; i++) {
- snprintf(buffer, SIZE, "handle=0x%08x, active-count=%d / %d\n",
+ snprintf(buffer, SIZE, "handle=0x%08x, active-count=%d\n",
list[i].handle,
- mActivationCount.valueFor(list[i].handle).count,
mActivationCount.valueFor(list[i].handle).rates.size());
result.append(buffer);
}
@@ -167,22 +166,25 @@ status_t SensorDevice::activate(void* ident, int handle, int enabled)
bool actuateHardware = false;
Info& info( mActivationCount.editValueFor(handle) );
- int32_t& count(info.count);
if (enabled) {
- if (android_atomic_inc(&count) == 0) {
- actuateHardware = true;
- }
Mutex::Autolock _l(mLock);
if (info.rates.indexOfKey(ident) < 0) {
info.rates.add(ident, DEFAULT_EVENTS_PERIOD);
- }
- } else {
- if (android_atomic_dec(&count) == 1) {
actuateHardware = true;
+ } else {
+ // sensor was already activated for this ident
}
+ } else {
Mutex::Autolock _l(mLock);
- info.rates.removeItem(ident);
+ if (info.rates.removeItem(ident) >= 0) {
+ if (info.rates.size() == 0) {
+ actuateHardware = true;
+ }
+ } else {
+ // sensor wasn't enabled for this ident
+ }
}
+
if (actuateHardware) {
err = mSensorDevice->activate(mSensorDevice, handle, enabled);
if (enabled) {
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 63ecbcd..c19b2ce 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -40,8 +40,7 @@ class SensorDevice : public Singleton<SensorDevice> {
Mutex mLock; // protect mActivationCount[].rates
// fixed-size array after construction
struct Info {
- Info() : count(0) { }
- int32_t count;
+ Info() { }
KeyedVector<void*, nsecs_t> rates;
};
DefaultKeyedVector<int, Info> mActivationCount;
diff --git a/services/sensorservice/SensorInterface.cpp b/services/sensorservice/SensorInterface.cpp
index 93d23d9..be8eaff 100644
--- a/services/sensorservice/SensorInterface.cpp
+++ b/services/sensorservice/SensorInterface.cpp
@@ -32,7 +32,7 @@ SensorInterface::~SensorInterface()
HardwareSensor::HardwareSensor(const sensor_t& sensor)
: mSensorDevice(SensorDevice::getInstance()),
- mSensor(&sensor), mEnabled(false)
+ mSensor(&sensor)
{
LOGI("%s", sensor.name);
}
@@ -46,15 +46,8 @@ bool HardwareSensor::process(sensors_event_t* outEvent,
return true;
}
-bool HardwareSensor::isEnabled() const {
- return mEnabled;
-}
-
-status_t HardwareSensor::activate(void* ident,bool enabled) {
- status_t err = mSensorDevice.activate(ident, mSensor.getHandle(), enabled);
- if (err == NO_ERROR)
- mEnabled = enabled;
- return err;
+status_t HardwareSensor::activate(void* ident, bool enabled) {
+ return mSensorDevice.activate(ident, mSensor.getHandle(), enabled);
}
status_t HardwareSensor::setDelay(void* ident, int handle, int64_t ns) {
diff --git a/services/sensorservice/SensorInterface.h b/services/sensorservice/SensorInterface.h
index eebd563..084f2f5 100644
--- a/services/sensorservice/SensorInterface.h
+++ b/services/sensorservice/SensorInterface.h
@@ -38,7 +38,6 @@ public:
virtual bool process(sensors_event_t* outEvent,
const sensors_event_t& event) = 0;
- virtual bool isEnabled() const = 0;
virtual status_t activate(void* ident, bool enabled) = 0;
virtual status_t setDelay(void* ident, int handle, int64_t ns) = 0;
virtual Sensor getSensor() const = 0;
@@ -51,7 +50,6 @@ class HardwareSensor : public SensorInterface
{
SensorDevice& mSensorDevice;
Sensor mSensor;
- bool mEnabled;
public:
HardwareSensor(const sensor_t& sensor);
@@ -61,7 +59,6 @@ public:
virtual bool process(sensors_event_t* outEvent,
const sensors_event_t& event);
- virtual bool isEnabled() const;
virtual status_t activate(void* ident, bool enabled);
virtual status_t setDelay(void* ident, int handle, int64_t ns);
virtual Sensor getSensor() const;
diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java
index 5b49305..719e5b4 100644
--- a/telephony/java/com/android/internal/telephony/CallManager.java
+++ b/telephony/java/com/android/internal/telephony/CallManager.java
@@ -700,6 +700,10 @@ public final class CallManager {
Log.d(LOG_TAG, this.toString());
}
+ if (!canDial(phone)) {
+ throw new CallStateException("cannot dial in current state");
+ }
+
if ( hasActiveFgCall() ) {
Phone activePhone = getActiveFgCall().getPhone();
boolean hasBgCall = !(activePhone.getBackgroundCall().isIdle());
@@ -753,6 +757,32 @@ public final class CallManager {
}
/**
+ * Phone can make a call only if ALL of the following are true:
+ * - Phone is not powered off
+ * - There's no incoming or waiting call
+ * - There's available call slot in either foreground or background
+ * - The foreground call is ACTIVE or IDLE or DISCONNECTED.
+ * (We mainly need to make sure it *isn't* DIALING or ALERTING.)
+ * @param phone
+ * @return true if the phone can make a new call
+ */
+ private boolean canDial(Phone phone) {
+ int serviceState = phone.getServiceState().getState();
+ boolean hasRingingCall = hasActiveRingingCall();
+ boolean hasActiveCall = hasActiveFgCall();
+ boolean hasHoldingCall = hasActiveBgCall();
+ boolean allLinesTaken = hasActiveCall && hasHoldingCall;
+ Call.State fgCallState = getActiveFgCallState();
+
+ return (serviceState != ServiceState.STATE_POWER_OFF
+ && !hasRingingCall
+ && !allLinesTaken
+ && ((fgCallState == Call.State.ACTIVE)
+ || (fgCallState == Call.State.IDLE)
+ || (fgCallState == Call.State.DISCONNECTED)));
+ }
+
+ /**
* Whether or not the phone can do explicit call transfer in the current
* phone state--that is, one call holding and one call active.
* @return true if the phone can do explicit call transfer; false otherwise.
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index 82fcb6a..014901d 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -20,12 +20,13 @@ import android.content.Context;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.net.Uri;
-import android.provider.ContactsContract.PhoneLookup;
import android.provider.ContactsContract.CommonDataKinds.Phone;
-import static android.provider.ContactsContract.RawContacts;
-import android.text.TextUtils;
-import android.telephony.TelephonyManager;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.PhoneLookup;
+import android.provider.ContactsContract.RawContacts;
import android.telephony.PhoneNumberUtils;
+import android.telephony.TelephonyManager;
+import android.text.TextUtils;
import android.util.Log;
@@ -171,33 +172,17 @@ public class CallerInfo {
}
}
- // Look for the person ID.
-
- // TODO: This is pretty ugly now, see bug 2269240 for
- // more details. The column to use depends upon the type of URL,
- // for content://com.android.contacts/data/phones the "contact_id"
- // column is used. For content/com.andriod.contacts/phone_lookup"
- // the "_ID" column is used. If it is neither we leave columnIndex
- // at -1 and no person ID will be available.
-
- columnIndex = -1;
- String url = contactRef.toString();
- if (url.startsWith("content://com.android.contacts/data/phones")) {
- if (VDBG) Log.v(TAG,
- "URL path starts with 'data/phones' using RawContacts.CONTACT_ID");
- columnIndex = cursor.getColumnIndex(RawContacts.CONTACT_ID);
- } else if (url.startsWith("content://com.android.contacts/phone_lookup")) {
- if (VDBG) Log.v(TAG,
- "URL path starts with 'phone_lookup' using PhoneLookup._ID");
- columnIndex = cursor.getColumnIndex(PhoneLookup._ID);
- } else {
- Log.e(TAG, "Bad contact URL '" + url + "'");
- }
-
+ // Look for the person_id.
+ columnIndex = getColumnIndexForPersonId(contactRef, cursor);
if (columnIndex != -1) {
info.person_id = cursor.getLong(columnIndex);
+ if (VDBG) Log.v(TAG, "==> got info.person_id: " + info.person_id);
} else {
- Log.e(TAG, "person_id column missing for " + contactRef);
+ // No valid columnIndex, so we can't look up person_id.
+ Log.w(TAG, "Couldn't find person_id column for " + contactRef);
+ // Watch out: this means that anything that depends on
+ // person_id will be broken (like contact photo lookups in
+ // the in-call UI, for example.)
}
// look for the custom ringtone, create from the string stored
@@ -411,30 +396,120 @@ public class CallerInfo {
}
/**
+ * Returns the column index to use to find the "person_id" field in
+ * the specified cursor, based on the contact URI that was originally
+ * queried.
+ *
+ * This is a helper function for the getCallerInfo() method that takes
+ * a Cursor. Looking up the person_id is nontrivial (compared to all
+ * the other CallerInfo fields) since the column we need to use
+ * depends on what query we originally ran.
+ *
+ * Watch out: be sure to not do any database access in this method, since
+ * it's run from the UI thread (see comments below for more info.)
+ *
+ * @return the columnIndex to use (with cursor.getLong()) to get the
+ * person_id, or -1 if we couldn't figure out what colum to use.
+ *
+ * TODO: Add a unittest for this method. (This is a little tricky to
+ * test, since we'll need a live contacts database to test against,
+ * preloaded with at least some phone numbers and SIP addresses. And
+ * we'll probably have to hardcode the column indexes we expect, so
+ * the test might break whenever the contacts schema changes. But we
+ * can at least make sure we handle all the URI patterns we claim to,
+ * and that the mime types match what we expect...)
+ */
+ private static int getColumnIndexForPersonId(Uri contactRef, Cursor cursor) {
+ // TODO: This is pretty ugly now, see bug 2269240 for
+ // more details. The column to use depends upon the type of URL:
+ // - content://com.android.contacts/data/phones ==> use the "contact_id" column
+ // - content://com.android.contacts/phone_lookup ==> use the "_ID" column
+ // - content://com.android.contacts/data ==> use the "contact_id" column
+ // If it's none of the above, we leave columnIndex=-1 which means
+ // that the person_id field will be left unset.
+ //
+ // The logic here *used* to be based on the mime type of contactRef
+ // (for example Phone.CONTENT_ITEM_TYPE would tell us to use the
+ // RawContacts.CONTACT_ID column). But looking up the mime type requires
+ // a call to context.getContentResolver().getType(contactRef), which
+ // isn't safe to do from the UI thread since it can cause an ANR if
+ // the contacts provider is slow or blocked (like during a sync.)
+ //
+ // So instead, figure out the column to use for person_id by just
+ // looking at the URI itself.
+
+ if (VDBG) Log.v(TAG, "- getColumnIndexForPersonId: contactRef URI = '"
+ + contactRef + "'...");
+ // Warning: Do not enable the following logging (due to ANR risk.)
+ // if (VDBG) Log.v(TAG, "- MIME type: "
+ // + context.getContentResolver().getType(contactRef));
+
+ String url = contactRef.toString();
+ String columnName = null;
+ if (url.startsWith("content://com.android.contacts/data/phones")) {
+ // Direct lookup in the Phone table.
+ // MIME type: Phone.CONTENT_ITEM_TYPE (= "vnd.android.cursor.item/phone_v2")
+ if (VDBG) Log.v(TAG, "'data/phones' URI; using RawContacts.CONTACT_ID");
+ columnName = RawContacts.CONTACT_ID;
+ } else if (url.startsWith("content://com.android.contacts/data")) {
+ // Direct lookup in the Data table.
+ // MIME type: Data.CONTENT_TYPE (= "vnd.android.cursor.dir/data")
+ if (VDBG) Log.v(TAG, "'data' URI; using Data.CONTACT_ID");
+ // (Note Data.CONTACT_ID and RawContacts.CONTACT_ID are equivalent.)
+ columnName = Data.CONTACT_ID;
+ } else if (url.startsWith("content://com.android.contacts/phone_lookup")) {
+ // Lookup in the PhoneLookup table, which provides "fuzzy matching"
+ // for phone numbers.
+ // MIME type: PhoneLookup.CONTENT_TYPE (= "vnd.android.cursor.dir/phone_lookup")
+ if (VDBG) Log.v(TAG, "'phone_lookup' URI; using PhoneLookup._ID");
+ columnName = PhoneLookup._ID;
+ } else {
+ Log.w(TAG, "Unexpected prefix for contactRef '" + url + "'");
+ }
+ int columnIndex = (columnName != null) ? cursor.getColumnIndex(columnName) : -1;
+ if (VDBG) Log.v(TAG, "==> Using column '" + columnName
+ + "' (columnIndex = " + columnIndex + ") for person_id lookup...");
+ return columnIndex;
+ }
+
+ /**
* @return a string debug representation of this instance.
*/
public String toString() {
- return new StringBuilder(384)
- .append("\nname: " + /*name*/ "nnnnnn")
- .append("\nphoneNumber: " + /*phoneNumber*/ "xxxxxxx")
- .append("\ncnapName: " + cnapName)
- .append("\nnumberPresentation: " + numberPresentation)
- .append("\nnamePresentation: " + namePresentation)
- .append("\ncontactExits: " + contactExists)
- .append("\nphoneLabel: " + phoneLabel)
- .append("\nnumberType: " + numberType)
- .append("\nnumberLabel: " + numberLabel)
- .append("\nphotoResource: " + photoResource)
- .append("\nperson_id: " + person_id)
- .append("\nneedUpdate: " + needUpdate)
- .append("\ncontactRefUri: " + /*contactRefUri*/ "xxxxxxx")
- .append("\ncontactRingtoneUri: " + /*contactRefUri*/ "xxxxxxx")
- .append("\nshouldSendToVoicemail: " + shouldSendToVoicemail)
- .append("\ncachedPhoto: " + cachedPhoto)
- .append("\nisCachedPhotoCurrent: " + isCachedPhotoCurrent)
- .append("\nemergency: " + mIsEmergency)
- .append("\nvoicemail " + mIsVoiceMail)
- .append("\ncontactExists " + contactExists)
- .toString();
+ // Warning: never check in this file with VERBOSE_DEBUG = true
+ // because that will result in PII in the system log.
+ final boolean VERBOSE_DEBUG = false;
+
+ if (VERBOSE_DEBUG) {
+ return new StringBuilder(384)
+ .append("\nname: " + name)
+ .append("\nphoneNumber: " + phoneNumber)
+ .append("\ncnapName: " + cnapName)
+ .append("\nnumberPresentation: " + numberPresentation)
+ .append("\nnamePresentation: " + namePresentation)
+ .append("\ncontactExits: " + contactExists)
+ .append("\nphoneLabel: " + phoneLabel)
+ .append("\nnumberType: " + numberType)
+ .append("\nnumberLabel: " + numberLabel)
+ .append("\nphotoResource: " + photoResource)
+ .append("\nperson_id: " + person_id)
+ .append("\nneedUpdate: " + needUpdate)
+ .append("\ncontactRefUri: " + contactRefUri)
+ .append("\ncontactRingtoneUri: " + contactRefUri)
+ .append("\nshouldSendToVoicemail: " + shouldSendToVoicemail)
+ .append("\ncachedPhoto: " + cachedPhoto)
+ .append("\nisCachedPhotoCurrent: " + isCachedPhotoCurrent)
+ .append("\nemergency: " + mIsEmergency)
+ .append("\nvoicemail " + mIsVoiceMail)
+ .append("\ncontactExists " + contactExists)
+ .toString();
+ } else {
+ return new StringBuilder(128)
+ .append("CallerInfo { ")
+ .append("name " + ((name == null) ? "null" : "non-null"))
+ .append(", phoneNumber " + ((phoneNumber == null) ? "null" : "non-null"))
+ .append(" }")
+ .toString();
+ }
}
}
diff --git a/telephony/java/com/android/internal/telephony/sip/SipPhone.java b/telephony/java/com/android/internal/telephony/sip/SipPhone.java
index ef31ddd..58a4cba 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);
}
}
@@ -660,12 +659,6 @@ public class SipPhone extends SipPhoneBase {
@Override
protected void onError(DisconnectCause cause) {
if (DEBUG) Log.d(LOG_TAG, "SIP error: " + cause);
- if (mSipAudioCall.isInCall()
- && (cause != DisconnectCause.LOST_SIGNAL)) {
- // Don't end the call when in a call.
- return;
- }
-
onCallEnded(cause);
}
};
diff --git a/tests/DumpRenderTree/AndroidManifest.xml b/tests/DumpRenderTree/AndroidManifest.xml
index c151251..dc44b25 100644
--- a/tests/DumpRenderTree/AndroidManifest.xml
+++ b/tests/DumpRenderTree/AndroidManifest.xml
@@ -25,7 +25,9 @@
<category android:name="android.intent.category.TEST" />
</intent-filter>
</activity>
- <activity android:name="TestShellActivity" android:launchMode="singleTop"
+ <activity android:name="TestShellActivity"
+ android:launchMode="singleTop"
+ android:hardwareAccelerated="true"
android:screenOrientation="portrait"
android:theme="@android:style/Theme.Light"/>
<activity android:name="ReliabilityTestActivity" android:screenOrientation="portrait"
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/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 2de1cbb..ca87b4e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -23,6 +23,7 @@ import com.android.layoutlib.api.IXmlPullParser;
import com.android.layoutlib.api.LayoutBridge;
import com.android.layoutlib.api.SceneParams;
import com.android.layoutlib.api.SceneResult;
+import com.android.layoutlib.api.SceneResult.SceneStatus;
import com.android.layoutlib.bridge.android.BridgeAssetManager;
import com.android.layoutlib.bridge.impl.FontLoader;
import com.android.layoutlib.bridge.impl.LayoutSceneImpl;
@@ -308,8 +309,13 @@ public final class Bridge extends LayoutBridge {
return new BridgeLayoutScene(scene, lastResult);
} catch (Throwable t) {
- t.printStackTrace();
- return new BridgeLayoutScene(null, new SceneResult("error!", t));
+ // get the real cause of the exception.
+ Throwable t2 = t;
+ while (t2.getCause() != null) {
+ t2 = t.getCause();
+ }
+ return new BridgeLayoutScene(null,
+ new SceneResult(SceneStatus.ERROR_UNKNOWN, t2.getMessage(), t2));
}
}
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 97bf857..f807214 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeLayoutScene.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeLayoutScene.java
@@ -16,12 +16,16 @@
package com.android.layoutlib.bridge;
+import com.android.layoutlib.api.IXmlPullParser;
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;
+import android.view.View;
+import android.view.ViewGroup;
+
import java.awt.image.BufferedImage;
import java.util.Map;
@@ -92,13 +96,86 @@ public class BridgeLayoutScene extends LayoutScene {
}
@Override
- public void dispose() {
- // TODO Auto-generated method stub
+ public SceneResult insertChild(Object parentView, IXmlPullParser childXml, Object beforeSibling,
+ IAnimationListener listener) {
+ if (parentView instanceof ViewGroup == false) {
+ throw new IllegalArgumentException("parentView is not a ViewGroup");
+ }
+ if (beforeSibling != null && beforeSibling instanceof View == false) {
+ throw new IllegalArgumentException("beforeSibling is not a View");
+ }
+
+ try {
+ mScene.prepareThread();
+ mLastResult = mScene.acquire(SceneParams.DEFAULT_TIMEOUT);
+ if (mLastResult == SceneResult.SUCCESS) {
+ mLastResult = mScene.insertChild((ViewGroup) parentView, childXml,
+ (View) beforeSibling, listener);
+ }
+ } finally {
+ mScene.release();
+ mScene.cleanupThread();
+ }
+
+ return mLastResult;
+ }
+
+
+ @Override
+ public SceneResult moveChild(Object parentView, Object childView, Object beforeSibling,
+ IAnimationListener listener) {
+ if (parentView instanceof ViewGroup == false) {
+ throw new IllegalArgumentException("parentView is not a ViewGroup");
+ }
+ if (childView instanceof View == false) {
+ throw new IllegalArgumentException("childView is not a View");
+ }
+ if (beforeSibling != null && beforeSibling instanceof View == false) {
+ throw new IllegalArgumentException("beforeSibling is not a View");
+ }
+
+ try {
+ mScene.prepareThread();
+ mLastResult = mScene.acquire(SceneParams.DEFAULT_TIMEOUT);
+ if (mLastResult == SceneResult.SUCCESS) {
+ mLastResult = mScene.moveChild((ViewGroup) parentView, (View) childView,
+ (View) beforeSibling, listener);
+ }
+ } finally {
+ mScene.release();
+ mScene.cleanupThread();
+ }
+
+ return mLastResult;
+ }
+ @Override
+ public SceneResult removeChild(Object childView, IAnimationListener listener) {
+ if (childView instanceof View == false) {
+ throw new IllegalArgumentException("childView is not a View");
+ }
+
+ try {
+ mScene.prepareThread();
+ mLastResult = mScene.acquire(SceneParams.DEFAULT_TIMEOUT);
+ if (mLastResult == SceneResult.SUCCESS) {
+ mLastResult = mScene.removeChild((View) childView, listener);
+ }
+ } finally {
+ mScene.release();
+ mScene.cleanupThread();
+ }
+
+ return mLastResult;
+ }
+
+ @Override
+ public void dispose() {
}
/*package*/ BridgeLayoutScene(LayoutSceneImpl scene, SceneResult lastResult) {
mScene = scene;
+ mScene.setScene(this);
mLastResult = lastResult;
}
}
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
index c20bdfd..d5766ab 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/AnimationThread.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/AnimationThread.java
@@ -105,7 +105,7 @@ public class AnimationThread extends Thread {
try {
bundle.mTarget.handleMessage(bundle.mMessage);
if (mScene.render() == SceneResult.SUCCESS) {
- mListener.onNewFrame(mScene.getImage());
+ mListener.onNewFrame(mScene.getScene());
}
} finally {
mScene.release();
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 0859976..05d207c 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
@@ -24,13 +24,16 @@ import com.android.internal.util.XmlUtils;
import com.android.layoutlib.api.IProjectCallback;
import com.android.layoutlib.api.IResourceValue;
import com.android.layoutlib.api.IStyleResourceValue;
+import com.android.layoutlib.api.IXmlPullParser;
import com.android.layoutlib.api.LayoutBridge;
+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.api.IDensityBasedResourceValue.Density;
import com.android.layoutlib.api.LayoutScene.IAnimationListener;
import com.android.layoutlib.api.SceneParams.RenderingMode;
+import com.android.layoutlib.api.SceneResult.SceneStatus;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.BridgeConstants;
import com.android.layoutlib.bridge.android.BridgeContext;
@@ -53,6 +56,7 @@ import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewParent;
import android.view.View.AttachInfo;
import android.view.View.MeasureSpec;
import android.widget.FrameLayout;
@@ -92,6 +96,7 @@ public class LayoutSceneImpl {
private final SceneParams mParams;
// scene state
+ private LayoutScene mScene;
private BridgeContext mContext;
private BridgeXmlBlockParser mBlockParser;
private BridgeInflater mInflater;
@@ -362,7 +367,7 @@ public class LayoutSceneImpl {
return SceneResult.SUCCESS;
} catch (PostInflateException e) {
- return new SceneResult("Error during post inflation process:\n" + e.getMessage());
+ return new SceneResult(SceneStatus.ERROR_INFLATION, e.getMessage(), e);
} catch (Throwable e) {
// get the real cause of the exception.
Throwable t = e;
@@ -373,7 +378,7 @@ public class LayoutSceneImpl {
// log it
mParams.getLogger().error(t);
- return new SceneResult("Unknown error during inflation.", t);
+ return new SceneResult(SceneStatus.ERROR_INFLATION, t.getMessage(), t);
}
}
@@ -391,7 +396,7 @@ public class LayoutSceneImpl {
try {
long current = System.currentTimeMillis();
if (mViewRoot == null) {
- return new SceneResult("Layout has not been inflated!");
+ return new SceneResult(SceneStatus.ERROR_NOT_INFLATED);
}
// measure the views
int w_spec, h_spec;
@@ -440,8 +445,13 @@ public class LayoutSceneImpl {
// draw the views
// create the BufferedImage into which the layout will be rendered.
- mImage = new BufferedImage(renderScreenWidth, renderScreenHeight - mScreenOffset,
- BufferedImage.TYPE_INT_ARGB);
+ if (mParams.getImageFactory() != null) {
+ mImage = mParams.getImageFactory().getImage(renderScreenWidth,
+ renderScreenHeight - mScreenOffset);
+ } else {
+ mImage = new BufferedImage(renderScreenWidth, renderScreenHeight - mScreenOffset,
+ BufferedImage.TYPE_INT_ARGB);
+ }
if (mParams.isCustomBackgroundEnabled()) {
Graphics2D gc = mImage.createGraphics();
@@ -482,7 +492,7 @@ public class LayoutSceneImpl {
// log it
mParams.getLogger().error(t);
- return new SceneResult("Unknown error during inflation.", t);
+ return new SceneResult(SceneStatus.ERROR_UNKNOWN, t.getMessage(), t);
}
}
@@ -525,12 +535,74 @@ public class LayoutSceneImpl {
return SceneResult.SUCCESS;
}
} catch (Exception e) {
- e.printStackTrace();
- return new SceneResult("", e);
+ // get the real cause of the exception.
+ Throwable t = e;
+ while (t.getCause() != null) {
+ t = t.getCause();
+ }
+
+ return new SceneResult(SceneStatus.ERROR_UNKNOWN, t.getMessage(), t);
}
}
- return new SceneResult("Failed to find animation");
+ return new SceneResult(SceneStatus.ERROR_ANIM_NOT_FOUND);
+ }
+
+ public SceneResult insertChild(ViewGroup parentView, IXmlPullParser childXml,
+ View beforeSibling, IAnimationListener listener) {
+ checkLock();
+
+ int index = parentView.indexOfChild(beforeSibling);
+ if (beforeSibling != null && index == -1) {
+ throw new IllegalArgumentException("beforeSibling not in parentView");
+ }
+
+ // create a block parser for the XML
+ BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(childXml, mContext,
+ false /* platformResourceFlag */);
+
+ // inflate the child without adding it to the root since we want to control where it'll
+ // get added. We do pass the parentView however to ensure that the layoutParams will
+ // be created correctly.
+ View child = mInflater.inflate(blockParser, parentView, false /*attachToRoot*/);
+
+ // add it to the parentView in the correct location
+ parentView.addView(child, index);
+
+ return render();
+ }
+
+ public SceneResult moveChild(ViewGroup parentView, View childView, View beforeSibling,
+ IAnimationListener listener) {
+ checkLock();
+
+ int index = parentView.indexOfChild(beforeSibling);
+ if (beforeSibling != null && index == -1) {
+ throw new IllegalArgumentException("beforeSibling not in parentView");
+ }
+
+ ViewParent parent = childView.getParent();
+ if (parent instanceof ViewGroup) {
+ ViewGroup parentGroup = (ViewGroup) parent;
+ parentGroup.removeView(childView);
+ }
+
+ // add it to the parentView in the correct location
+ parentView.addView(childView, index);
+
+ return render();
+ }
+
+ public SceneResult removeChild(View childView, IAnimationListener listener) {
+ checkLock();
+
+ ViewParent parent = childView.getParent();
+ if (parent instanceof ViewGroup) {
+ ViewGroup parentGroup = (ViewGroup) parent;
+ parentGroup.removeView(childView);
+ }
+
+ return render();
}
/**
@@ -910,4 +982,12 @@ public class LayoutSceneImpl {
public Map<String, String> getDefaultViewPropertyValues(Object viewObject) {
return mContext.getDefaultPropMap(viewObject);
}
+
+ public void setScene(LayoutScene scene) {
+ mScene = scene;
+ }
+
+ public LayoutScene getScene() {
+ return mScene;
+ }
}
diff --git a/voip/java/android/net/rtp/AudioGroup.java b/voip/java/android/net/rtp/AudioGroup.java
index 43a3827..a6b54d8 100644
--- a/voip/java/android/net/rtp/AudioGroup.java
+++ b/voip/java/android/net/rtp/AudioGroup.java
@@ -21,14 +21,14 @@ import java.util.Map;
/**
* An AudioGroup acts as a router connected to the speaker, the microphone, and
- * {@link AudioStream}s. Its pipeline has four steps. First, for each
- * AudioStream not in {@link RtpStream#MODE_SEND_ONLY}, decodes its incoming
- * packets and stores in its buffer. Then, if the microphone is enabled,
- * processes the recorded audio and stores in its buffer. Third, if the speaker
- * is enabled, mixes and playbacks buffers of all AudioStreams. Finally, for
- * each AudioStream not in {@link RtpStream#MODE_RECEIVE_ONLY}, mixes all other
- * buffers and sends back the encoded packets. An AudioGroup does nothing if
- * there is no AudioStream in it.
+ * {@link AudioStream}s. Its execution loop consists of four steps. First, for
+ * each AudioStream not in {@link RtpStream#MODE_SEND_ONLY}, decodes its
+ * incoming packets and stores in its buffer. Then, if the microphone is
+ * enabled, processes the recorded audio and stores in its buffer. Third, if the
+ * speaker is enabled, mixes and playbacks buffers of all AudioStreams. Finally,
+ * for each AudioStream not in {@link RtpStream#MODE_RECEIVE_ONLY}, mixes all
+ * other buffers and sends back the encoded packets. An AudioGroup does nothing
+ * if there is no AudioStream in it.
*
* <p>Few things must be noticed before using these classes. The performance is
* highly related to the system load and the network bandwidth. Usually a
@@ -47,7 +47,12 @@ import java.util.Map;
* modes other than {@link #MODE_ON_HOLD}. In addition, before adding an
* AudioStream into an AudioGroup, one should always put all other AudioGroups
* into {@link #MODE_ON_HOLD}. That will make sure the audio driver correctly
- * initialized.
+ * initialized.</p>
+ *
+ * <p class="note">Using this class requires
+ * {@link android.Manifest.permission#RECORD_AUDIO} permission.</p>
+ *
+ * @see AudioStream
* @hide
*/
public class AudioGroup {
@@ -78,6 +83,8 @@ public class AudioGroup {
*/
public static final int MODE_ECHO_SUPPRESSION = 3;
+ private static final int MODE_LAST = 3;
+
private final Map<AudioStream, Integer> mStreams;
private int mMode = MODE_ON_HOLD;
@@ -94,6 +101,15 @@ public class AudioGroup {
}
/**
+ * Returns the {@link AudioStream}s in this group.
+ */
+ public AudioStream[] getStreams() {
+ synchronized (this) {
+ return mStreams.keySet().toArray(new AudioStream[mStreams.size()]);
+ }
+ }
+
+ /**
* Returns the current mode.
*/
public int getMode() {
@@ -108,49 +124,77 @@ public class AudioGroup {
* @param mode The mode to change to.
* @throws IllegalArgumentException if the mode is invalid.
*/
- public synchronized native void setMode(int mode);
-
- private native void add(int mode, int socket, String remoteAddress,
- int remotePort, String codecSpec, int dtmfType);
+ public void setMode(int mode) {
+ if (mode < 0 || mode > MODE_LAST) {
+ throw new IllegalArgumentException("Invalid mode");
+ }
+ synchronized (this) {
+ nativeSetMode(mode);
+ mMode = mode;
+ }
+ }
- synchronized void add(AudioStream stream, AudioCodec codec, int dtmfType) {
- if (!mStreams.containsKey(stream)) {
- try {
- int socket = stream.dup();
- String codecSpec = String.format("%d %s %s", codec.type,
- codec.rtpmap, codec.fmtp);
- add(stream.getMode(), socket,
- stream.getRemoteAddress().getHostAddress(),
- stream.getRemotePort(), codecSpec, dtmfType);
- mStreams.put(stream, socket);
- } catch (NullPointerException e) {
- throw new IllegalStateException(e);
+ private native void nativeSetMode(int mode);
+
+ // Package-private method used by AudioStream.join().
+ void add(AudioStream stream, AudioCodec codec, int dtmfType) {
+ synchronized (this) {
+ if (!mStreams.containsKey(stream)) {
+ try {
+ int socket = stream.dup();
+ String codecSpec = String.format("%d %s %s", codec.type,
+ codec.rtpmap, codec.fmtp);
+ nativeAdd(stream.getMode(), socket,
+ stream.getRemoteAddress().getHostAddress(),
+ stream.getRemotePort(), codecSpec, dtmfType);
+ mStreams.put(stream, socket);
+ } catch (NullPointerException e) {
+ throw new IllegalStateException(e);
+ }
}
}
}
- private native void remove(int socket);
+ private native void nativeAdd(int mode, int socket, String remoteAddress,
+ int remotePort, String codecSpec, int dtmfType);
- synchronized void remove(AudioStream stream) {
- Integer socket = mStreams.remove(stream);
- if (socket != null) {
- remove(socket);
+ // Package-private method used by AudioStream.join().
+ void remove(AudioStream stream) {
+ synchronized (this) {
+ Integer socket = mStreams.remove(stream);
+ if (socket != null) {
+ nativeRemove(socket);
+ }
}
}
+ private native void nativeRemove(int socket);
+
/**
* Sends a DTMF digit to every {@link AudioStream} in this group. Currently
* only event {@code 0} to {@code 15} are supported.
*
* @throws IllegalArgumentException if the event is invalid.
*/
- public native synchronized void sendDtmf(int event);
+ public void sendDtmf(int event) {
+ if (event < 0 || event > 15) {
+ throw new IllegalArgumentException("Invalid event");
+ }
+ synchronized (this) {
+ nativeSendDtmf(event);
+ }
+ }
+
+ private native void nativeSendDtmf(int event);
/**
* Removes every {@link AudioStream} in this group.
*/
- public synchronized void clear() {
- remove(-1);
+ public void clear() {
+ synchronized (this) {
+ mStreams.clear();
+ nativeRemove(-1);
+ }
}
@Override
diff --git a/voip/java/android/net/rtp/AudioStream.java b/voip/java/android/net/rtp/AudioStream.java
index e5197ce..0edae6b 100644
--- a/voip/java/android/net/rtp/AudioStream.java
+++ b/voip/java/android/net/rtp/AudioStream.java
@@ -34,8 +34,12 @@ import java.net.SocketException;
* of the setter methods are disabled. This is designed to ease the task of
* managing native resources. One can always make an AudioStream leave its
* AudioGroup by calling {@link #join(AudioGroup)} with {@code null} and put it
- * back after the modification is done.
+ * back after the modification is done.</p>
*
+ * <p class="note">Using this class requires
+ * {@link android.Manifest.permission#INTERNET} permission.</p>
+ *
+ * @see RtpStream
* @see AudioGroup
* @hide
*/
@@ -82,16 +86,18 @@ public class AudioStream extends RtpStream {
* @see AudioGroup
*/
public void join(AudioGroup group) {
- if (mGroup == group) {
- return;
- }
- if (mGroup != null) {
- mGroup.remove(this);
- mGroup = null;
- }
- if (group != null) {
- group.add(this, mCodec, mDtmfType);
- mGroup = group;
+ synchronized (this) {
+ if (mGroup == group) {
+ return;
+ }
+ if (mGroup != null) {
+ mGroup.remove(this);
+ mGroup = null;
+ }
+ if (group != null) {
+ group.add(this, mCodec, mDtmfType);
+ mGroup = group;
+ }
}
}
diff --git a/voip/java/android/net/rtp/RtpStream.java b/voip/java/android/net/rtp/RtpStream.java
index 23fb258..87d8bc6 100644
--- a/voip/java/android/net/rtp/RtpStream.java
+++ b/voip/java/android/net/rtp/RtpStream.java
@@ -24,6 +24,9 @@ import java.net.SocketException;
/**
* RtpStream represents the base class of streams which send and receive network
* packets with media payloads over Real-time Transport Protocol (RTP).
+ *
+ * <p class="note">Using this class requires
+ * {@link android.Manifest.permission#INTERNET} permission.</p>
* @hide
*/
public class RtpStream {
@@ -43,6 +46,8 @@ public class RtpStream {
*/
public static final int MODE_RECEIVE_ONLY = 2;
+ private static final int MODE_LAST = 2;
+
private final InetAddress mLocalAddress;
private final int mLocalPort;
@@ -129,7 +134,7 @@ public class RtpStream {
if (isBusy()) {
throw new IllegalStateException("Busy");
}
- if (mode != MODE_NORMAL && mode != MODE_SEND_ONLY && mode != MODE_RECEIVE_ONLY) {
+ if (mode < 0 || mode > MODE_LAST) {
throw new IllegalArgumentException("Invalid mode");
}
mMode = mode;
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..30ddfb5 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) {
@@ -526,11 +527,14 @@ class SipSessionGroup implements SipListener {
}
public void answerCall(String sessionDescription, int timeout) {
- try {
- processCommand(new MakeCallCommand(mPeerProfile,
- sessionDescription, timeout));
- } catch (SipException e) {
- onError(e);
+ synchronized (SipSessionGroup.this) {
+ if (mPeerProfile == null) return;
+ try {
+ processCommand(new MakeCallCommand(mPeerProfile,
+ sessionDescription, timeout));
+ } catch (SipException e) {
+ onError(e);
+ }
}
}
@@ -539,14 +543,11 @@ class SipSessionGroup implements SipListener {
}
public void changeCall(String sessionDescription, int timeout) {
- doCommandAsync(new MakeCallCommand(mPeerProfile, sessionDescription,
- timeout));
- }
-
- public void changeCallWithTimeout(
- String sessionDescription, int timeout) {
- doCommandAsync(new MakeCallCommand(mPeerProfile, sessionDescription,
- timeout));
+ synchronized (SipSessionGroup.this) {
+ if (mPeerProfile == null) return;
+ doCommandAsync(new MakeCallCommand(mPeerProfile,
+ sessionDescription, timeout));
+ }
}
public void register(int duration) {
@@ -1162,11 +1163,6 @@ class SipSessionGroup implements SipListener {
mProxy.onCallEstablished(this, mPeerSessionDescription);
}
- private void fallbackToPreviousInCall(int errorCode, String message) {
- mState = SipSession.State.IN_CALL;
- mProxy.onCallChangeFailed(this, errorCode, message);
- }
-
private void endCallNormally() {
reset();
mProxy.onCallEnded(this);
@@ -1190,12 +1186,7 @@ class SipSessionGroup implements SipListener {
onRegistrationFailed(errorCode, message);
break;
default:
- if ((errorCode != SipErrorCode.DATA_CONNECTION_LOST)
- && mInCall) {
- fallbackToPreviousInCall(errorCode, message);
- } else {
- endCallOnError(errorCode, message);
- }
+ endCallOnError(errorCode, message);
}
}
diff --git a/voip/jni/rtp/AmrCodec.cpp b/voip/jni/rtp/AmrCodec.cpp
index 72ee44e..84c7166 100644
--- a/voip/jni/rtp/AmrCodec.cpp
+++ b/voip/jni/rtp/AmrCodec.cpp
@@ -73,7 +73,7 @@ int AmrCodec::set(int sampleRate, const char *fmtp)
}
// Handle mode-set and octet-align.
- char *modes = (char*)strcasestr(fmtp, "mode-set=");
+ const char *modes = strcasestr(fmtp, "mode-set=");
if (modes) {
mMode = 0;
mModeSet = 0;
diff --git a/voip/jni/rtp/AudioGroup.cpp b/voip/jni/rtp/AudioGroup.cpp
index 0c8a725..cba1123 100644
--- a/voip/jni/rtp/AudioGroup.cpp
+++ b/voip/jni/rtp/AudioGroup.cpp
@@ -90,6 +90,7 @@ public:
void encode(int tick, AudioStream *chain);
void decode(int tick);
+private:
enum {
NORMAL = 0,
SEND_ONLY = 1,
@@ -97,7 +98,6 @@ public:
LAST_MODE = 2,
};
-private:
int mMode;
int mSocket;
sockaddr_storage mRemote;
@@ -463,6 +463,7 @@ public:
bool add(AudioStream *stream);
bool remove(int socket);
+private:
enum {
ON_HOLD = 0,
MUTED = 1,
@@ -471,7 +472,6 @@ public:
LAST_MODE = 3,
};
-private:
AudioStream *mChain;
int mEventQueue;
volatile int mDtmfEvent;
@@ -948,16 +948,10 @@ void remove(JNIEnv *env, jobject thiz, jint socket)
void setMode(JNIEnv *env, jobject thiz, jint mode)
{
- if (mode < 0 || mode > AudioGroup::LAST_MODE) {
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
- return;
- }
AudioGroup *group = (AudioGroup *)env->GetIntField(thiz, gNative);
if (group && !group->setMode(mode)) {
jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
- return;
}
- env->SetIntField(thiz, gMode, mode);
}
void sendDtmf(JNIEnv *env, jobject thiz, jint event)
@@ -969,10 +963,10 @@ void sendDtmf(JNIEnv *env, jobject thiz, jint event)
}
JNINativeMethod gMethods[] = {
- {"add", "(IILjava/lang/String;ILjava/lang/String;I)V", (void *)add},
- {"remove", "(I)V", (void *)remove},
- {"setMode", "(I)V", (void *)setMode},
- {"sendDtmf", "(I)V", (void *)sendDtmf},
+ {"nativeAdd", "(IILjava/lang/String;ILjava/lang/String;I)V", (void *)add},
+ {"nativeRemove", "(I)V", (void *)remove},
+ {"nativeSetMode", "(I)V", (void *)setMode},
+ {"nativeSendDtmf", "(I)V", (void *)sendDtmf},
};
} // namespace
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;