summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt30
-rw-r--r--cmds/bootanimation/BootAnimation.cpp5
-rw-r--r--cmds/installd/commands.c15
-rw-r--r--cmds/installd/installd.c8
-rw-r--r--cmds/installd/installd.h3
-rw-r--r--cmds/keystore/keystore.cpp1
-rw-r--r--cmds/stagefright/sf2.cpp4
-rw-r--r--cmds/stagefright/stagefright.cpp4
-rw-r--r--cmds/stagefright/stream.cpp180
-rw-r--r--core/java/android/accessibilityservice/AccessibilityService.java265
-rw-r--r--core/java/android/accessibilityservice/AccessibilityServiceInfo.java29
-rw-r--r--core/java/android/accessibilityservice/package.html22
-rw-r--r--core/java/android/app/ActivityManagerNative.java29
-rw-r--r--core/java/android/app/ContextImpl.java14
-rw-r--r--core/java/android/app/IActivityManager.java5
-rw-r--r--core/java/android/app/PendingIntent.java70
-rw-r--r--core/java/android/app/SearchDialog.java5
-rw-r--r--core/java/android/app/SearchManager.java9
-rw-r--r--core/java/android/content/Context.java12
-rw-r--r--core/java/android/content/IIntentSender.aidl2
-rw-r--r--core/java/android/content/IntentSender.java37
-rwxr-xr-xcore/java/android/content/pm/PackageStats.java11
-rw-r--r--core/java/android/inputmethodservice/IInputMethodSessionWrapper.java11
-rw-r--r--core/java/android/inputmethodservice/InputMethodService.java20
-rw-r--r--core/java/android/net/INetworkStatsService.aidl3
-rw-r--r--core/java/android/net/NetworkPolicyManager.java36
-rw-r--r--core/java/android/net/NetworkStatsHistory.java13
-rw-r--r--core/java/android/net/TrafficStats.java15
-rw-r--r--core/java/android/nfc/NdefRecord.java10
-rw-r--r--core/java/android/nfc/Tag.java16
-rw-r--r--core/java/android/os/INetworkManagementService.aidl17
-rw-r--r--core/java/android/os/Process.java6
-rw-r--r--core/java/android/os/storage/IMountService.java33
-rw-r--r--core/java/android/provider/CalendarContract.java231
-rw-r--r--core/java/android/provider/CallLog.java23
-rw-r--r--core/java/android/provider/VoicemailContract.java131
-rw-r--r--core/java/android/server/BluetoothA2dpService.java2
-rw-r--r--[-rwxr-xr-x]core/java/android/server/BluetoothService.java0
-rw-r--r--core/java/android/text/Layout.java44
-rw-r--r--core/java/android/view/InputEventConsistencyVerifier.java27
-rw-r--r--core/java/android/view/MotionEvent.java2
-rw-r--r--core/java/android/view/View.java10
-rw-r--r--core/java/android/view/ViewAncestor.java19
-rw-r--r--core/java/android/view/ViewConfiguration.java39
-rw-r--r--core/java/android/view/ViewGroup.java7
-rw-r--r--core/java/android/view/accessibility/AccessibilityEvent.java188
-rw-r--r--core/java/android/view/accessibility/AccessibilityEventSource.java14
-rw-r--r--core/java/android/view/accessibility/AccessibilityManager.java55
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfo.java158
-rw-r--r--core/java/android/view/accessibility/AccessibilityRecord.java89
-rw-r--r--core/java/android/view/accessibility/package.html39
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java23
-rw-r--r--core/java/android/view/inputmethod/InputMethodSession.java9
-rw-r--r--core/java/android/webkit/CertTool.java16
-rw-r--r--core/java/android/webkit/HTML5VideoFullScreen.java14
-rw-r--r--core/java/android/webkit/HTML5VideoView.java16
-rw-r--r--core/java/android/webkit/L10nUtils.java6
-rw-r--r--core/java/android/webkit/WebViewCore.java13
-rw-r--r--core/java/android/webkit/ZoomManager.java8
-rw-r--r--core/java/android/widget/GridLayout.java725
-rw-r--r--core/java/android/widget/NumberPicker.java13
-rw-r--r--core/java/android/widget/TextView.java107
-rw-r--r--core/java/com/android/internal/app/ActionBarImpl.java6
-rw-r--r--core/java/com/android/internal/content/PackageHelper.java10
-rw-r--r--core/java/com/android/internal/net/VpnConfig.java23
-rw-r--r--core/java/com/android/internal/os/RuntimeInit.java12
-rw-r--r--core/java/com/android/internal/view/IInputMethodSession.aidl4
-rw-r--r--core/java/com/android/internal/view/menu/ActionMenuPresenter.java5
-rw-r--r--core/java/com/android/internal/widget/ActionBarContainer.java23
-rw-r--r--core/java/com/android/internal/widget/ActionBarContextView.java2
-rw-r--r--core/java/com/android/internal/widget/ActionBarView.java7
-rw-r--r--core/java/com/android/internal/widget/ScrollingTabContainerView.java69
-rw-r--r--core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java281
-rw-r--r--core/java/com/android/server/NetworkManagementSocketTagger.java165
-rw-r--r--core/res/AndroidManifest.xml10
-rw-r--r--core/res/res/drawable-hdpi/spinner_black_16.pngbin630 -> 1175 bytes
-rw-r--r--core/res/res/drawable-hdpi/spinner_black_20.pngbin847 -> 1750 bytes
-rw-r--r--core/res/res/drawable-hdpi/spinner_black_48.pngbin1812 -> 4939 bytes
-rw-r--r--core/res/res/drawable-hdpi/spinner_black_76.pngbin2663 -> 8835 bytes
-rw-r--r--core/res/res/drawable-hdpi/spinner_white_16.pngbin606 -> 1219 bytes
-rw-r--r--core/res/res/drawable-hdpi/spinner_white_48.pngbin1736 -> 5570 bytes
-rw-r--r--core/res/res/drawable-hdpi/spinner_white_76.pngbin2603 -> 7405 bytes
-rwxr-xr-x[-rw-r--r--]core/res/res/drawable-hdpi/textfield_default.9.pngbin3731 -> 529 bytes
-rwxr-xr-x[-rw-r--r--]core/res/res/drawable-hdpi/textfield_disabled.9.pngbin3422 -> 613 bytes
-rwxr-xr-x[-rw-r--r--]core/res/res/drawable-hdpi/textfield_disabled_selected.9.pngbin3623 -> 738 bytes
-rwxr-xr-x[-rw-r--r--]core/res/res/drawable-hdpi/textfield_selected.9.pngbin3754 -> 616 bytes
-rw-r--r--core/res/res/drawable-mdpi/spinner_black_16.pngbin291 -> 1008 bytes
-rwxr-xr-xcore/res/res/drawable-mdpi/spinner_black_20.pngbin523 -> 1217 bytes
-rw-r--r--core/res/res/drawable-mdpi/spinner_black_48.pngbin1022 -> 3307 bytes
-rw-r--r--core/res/res/drawable-mdpi/spinner_black_76.pngbin1086 -> 5469 bytes
-rw-r--r--core/res/res/drawable-mdpi/spinner_white_16.pngbin2968 -> 962 bytes
-rw-r--r--core/res/res/drawable-mdpi/spinner_white_48.pngbin782 -> 3062 bytes
-rw-r--r--core/res/res/drawable-mdpi/spinner_white_76.pngbin3745 -> 4714 bytes
-rw-r--r--core/res/res/drawable-mdpi/textfield_default.9.pngbin758 -> 417 bytes
-rw-r--r--core/res/res/drawable-mdpi/textfield_disabled.9.pngbin545 -> 483 bytes
-rw-r--r--core/res/res/drawable-mdpi/textfield_disabled_selected.9.pngbin570 -> 685 bytes
-rw-r--r--core/res/res/drawable-mdpi/textfield_selected.9.pngbin790 -> 600 bytes
-rw-r--r--core/res/res/drawable-xhdpi/popup_bottom_bright.9.pngbin0 -> 1331 bytes
-rw-r--r--core/res/res/drawable-xhdpi/popup_bottom_dark.9.pngbin0 -> 1325 bytes
-rw-r--r--core/res/res/drawable-xhdpi/popup_bottom_medium.9.pngbin0 -> 1331 bytes
-rw-r--r--core/res/res/drawable-xhdpi/popup_center_bright.9.pngbin0 -> 253 bytes
-rw-r--r--core/res/res/drawable-xhdpi/popup_center_dark.9.pngbin0 -> 296 bytes
-rw-r--r--core/res/res/drawable-xhdpi/popup_center_medium.9.pngbin0 -> 265 bytes
-rw-r--r--core/res/res/drawable-xhdpi/popup_full_bright.9.pngbin0 -> 2199 bytes
-rw-r--r--core/res/res/drawable-xhdpi/popup_full_dark.9.pngbin0 -> 2205 bytes
-rw-r--r--core/res/res/drawable-xhdpi/popup_top_bright.9.pngbin0 -> 1279 bytes
-rw-r--r--core/res/res/drawable-xhdpi/popup_top_dark.9.pngbin0 -> 1299 bytes
-rw-r--r--core/res/res/drawable-xhdpi/spinner_black_16.pngbin0 -> 2634 bytes
-rw-r--r--core/res/res/drawable-xhdpi/spinner_black_20.pngbin0 -> 3463 bytes
-rw-r--r--core/res/res/drawable-xhdpi/spinner_black_48.pngbin0 -> 9839 bytes
-rw-r--r--core/res/res/drawable-xhdpi/spinner_black_76.pngbin0 -> 17111 bytes
-rw-r--r--core/res/res/drawable-xhdpi/spinner_white_16.pngbin0 -> 2385 bytes
-rw-r--r--core/res/res/drawable-xhdpi/spinner_white_48.pngbin0 -> 8986 bytes
-rw-r--r--core/res/res/drawable-xhdpi/spinner_white_76.pngbin0 -> 13759 bytes
-rw-r--r--core/res/res/layout-land/ssl_certificate.xml1
-rw-r--r--core/res/res/layout-sw600dp/date_picker_dialog.xml25
-rw-r--r--core/res/res/layout-sw600dp/number_picker.xml39
-rw-r--r--core/res/res/layout/date_picker_dialog.xml2
-rw-r--r--core/res/res/layout/date_picker_holo.xml3
-rw-r--r--core/res/res/layout/keyguard_screen_password_landscape.xml2
-rw-r--r--core/res/res/layout/keyguard_screen_tab_unlock_land.xml5
-rw-r--r--core/res/res/layout/keyguard_screen_unlock_landscape.xml8
-rw-r--r--core/res/res/layout/keyguard_screen_unlock_portrait.xml2
-rw-r--r--core/res/res/layout/number_picker.xml4
-rw-r--r--core/res/res/layout/search_view.xml5
-rw-r--r--core/res/res/layout/ssl_certificate.xml1
-rwxr-xr-xcore/res/res/values/attrs.xml66
-rwxr-xr-xcore/res/res/values/config.xml4
-rw-r--r--core/res/res/values/public.xml6
-rwxr-xr-xcore/res/res/values/strings.xml33
-rw-r--r--data/etc/platform.xml10
-rw-r--r--data/fonts/DroidSansHebrew-Bold.ttfbin0 -> 30280 bytes
-rw-r--r--data/fonts/DroidSansHebrew-Regular.ttfbin0 -> 30024 bytes
-rw-r--r--data/fonts/DroidSansHebrew.ttfbin23076 -> 0 bytes
-rw-r--r--data/fonts/fonts.mk3
-rw-r--r--docs/html/sdk/android-3.1-highlights.jd4
-rw-r--r--graphics/java/android/graphics/SurfaceTexture.java5
-rw-r--r--include/gui/SurfaceTexture.h4
-rw-r--r--include/media/MediaPlayerInterface.h4
-rw-r--r--include/media/stagefright/MediaSource.h10
-rw-r--r--include/media/stagefright/MetaData.h2
-rw-r--r--include/media/stagefright/MetadataBufferType.h77
-rw-r--r--include/media/stagefright/OMXCodec.h20
-rw-r--r--include/private/surfaceflinger/LayerState.h8
-rw-r--r--include/surfaceflinger/ISurfaceComposer.h7
-rw-r--r--include/surfaceflinger/ISurfaceComposerClient.h7
-rw-r--r--include/surfaceflinger/SurfaceComposerClient.h26
-rw-r--r--include/utils/LinearTransform.h64
-rw-r--r--include/utils/SortedVector.h2
-rw-r--r--include/utils/Vector.h26
-rw-r--r--keystore/java/android/security/Credentials.java27
-rw-r--r--keystore/java/android/security/KeyChain.java108
-rw-r--r--libs/gui/ISurfaceComposer.cpp35
-rw-r--r--libs/gui/ISurfaceComposerClient.cpp25
-rw-r--r--libs/gui/LayerState.cpp11
-rw-r--r--libs/gui/SurfaceComposerClient.cpp593
-rw-r--r--libs/gui/SurfaceTexture.cpp11
-rw-r--r--libs/gui/tests/SurfaceTexture_test.cpp4
-rw-r--r--libs/gui/tests/Surface_test.cpp4
-rw-r--r--libs/ui/InputTransport.cpp3
-rw-r--r--libs/utils/Android.mk1
-rw-r--r--libs/utils/LinearTransform.cpp262
-rwxr-xr-xlocation/java/android/location/Country.java4
-rwxr-xr-xlocation/java/com/android/internal/location/GpsNetInitiatedHandler.java2
-rw-r--r--media/java/android/media/MediaPlayer.java11
-rw-r--r--media/java/android/media/MediaRecorder.java5
-rw-r--r--media/java/android/media/videoeditor/MediaArtistNativeHelper.java4
-rwxr-xr-xmedia/jni/mediaeditor/VideoEditorClasses.cpp2
-rwxr-xr-xmedia/jni/mediaeditor/VideoEditorOsal.cpp1
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.cpp27
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.h4
-rw-r--r--media/libmediaplayerservice/StagefrightPlayer.cpp6
-rw-r--r--media/libmediaplayerservice/StagefrightPlayer.h2
-rw-r--r--media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp8
-rw-r--r--media/libmediaplayerservice/nuplayer/HTTPLiveSource.h6
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.cpp10
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.h4
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp6
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDriver.h2
-rw-r--r--media/libstagefright/ACodec.cpp17
-rw-r--r--media/libstagefright/AwesomePlayer.cpp19
-rw-r--r--media/libstagefright/CameraSource.cpp29
-rw-r--r--media/libstagefright/HTTPBase.cpp18
-rw-r--r--media/libstagefright/HTTPStream.cpp23
-rw-r--r--media/libstagefright/NuHTTPDataSource.cpp5
-rw-r--r--media/libstagefright/OMXCodec.cpp190
-rw-r--r--media/libstagefright/WVMExtractor.cpp36
-rw-r--r--media/libstagefright/chromium_http/support.cpp37
-rw-r--r--media/libstagefright/codecs/avc/enc/AVCEncoder.cpp4
-rw-r--r--media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp9
-rw-r--r--media/libstagefright/httplive/LiveSession.cpp56
-rw-r--r--media/libstagefright/httplive/M3UParser.cpp13
-rw-r--r--media/libstagefright/include/ARTSPController.h5
-rw-r--r--media/libstagefright/include/AwesomePlayer.h3
-rw-r--r--media/libstagefright/include/HTTPBase.h6
-rw-r--r--media/libstagefright/include/HTTPStream.h8
-rw-r--r--media/libstagefright/include/LiveSession.h4
-rw-r--r--media/libstagefright/include/WVMExtractor.h5
-rw-r--r--media/libstagefright/rtsp/ARTSPConnection.cpp12
-rw-r--r--media/libstagefright/rtsp/ARTSPConnection.h4
-rw-r--r--media/libstagefright/rtsp/ARTSPController.cpp8
-rw-r--r--media/libstagefright/rtsp/ASessionDescription.cpp3
-rw-r--r--media/libstagefright/rtsp/MyHandler.h25
-rw-r--r--packages/SystemUI/AndroidManifest.xml5
-rw-r--r--packages/SystemUI/res/drawable-hdpi/global_screenshot_background.9.pngbin0 -> 358 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/global_screenshot_background.9.pngbin0 -> 358 bytes
-rw-r--r--packages/SystemUI/res/layout/global_screenshot.xml40
-rw-r--r--packages/SystemUI/res/layout/navigation_bar.xml67
-rw-r--r--packages/SystemUI/res/values/config.xml4
-rw-r--r--packages/SystemUI/res/values/dimens.xml6
-rw-r--r--packages/SystemUI/res/values/strings.xml5
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java384
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java50
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java2
-rw-r--r--packages/VpnDialogs/Android.mk2
-rw-r--r--packages/VpnDialogs/AndroidManifest.xml3
-rw-r--r--packages/VpnDialogs/res/values/strings.xml1
-rw-r--r--packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java37
-rw-r--r--policy/src/com/android/internal/policy/impl/LockScreen.java167
-rwxr-xr-xpolicy/src/com/android/internal/policy/impl/PhoneWindowManager.java56
-rw-r--r--services/input/EventHub.cpp31
-rw-r--r--services/input/EventHub.h4
-rw-r--r--services/input/InputDispatcher.cpp459
-rw-r--r--services/input/InputDispatcher.h24
-rw-r--r--services/input/InputReader.cpp58
-rw-r--r--services/input/SpriteController.cpp11
-rw-r--r--services/input/tests/InputReader_test.cpp20
-rw-r--r--services/java/com/android/server/ConnectivityService.java2
-rw-r--r--services/java/com/android/server/DnsPinger.java115
-rw-r--r--services/java/com/android/server/InputMethodManagerService.java51
-rw-r--r--services/java/com/android/server/IntentResolver.java23
-rw-r--r--services/java/com/android/server/LocationManagerService.java77
-rw-r--r--services/java/com/android/server/MountService.java24
-rw-r--r--services/java/com/android/server/NetworkManagementService.java142
-rw-r--r--services/java/com/android/server/SystemServer.java5
-rw-r--r--services/java/com/android/server/WifiWatchdogService.java6
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java43
-rw-r--r--services/java/com/android/server/am/ActivityStack.java1
-rw-r--r--services/java/com/android/server/am/BroadcastFilter.java4
-rw-r--r--services/java/com/android/server/am/PendingIntentRecord.java10
-rw-r--r--services/java/com/android/server/connectivity/Vpn.java338
-rwxr-xr-xservices/java/com/android/server/location/GpsLocationProvider.java28
-rw-r--r--services/java/com/android/server/net/NetworkPolicyManagerService.java150
-rw-r--r--services/java/com/android/server/net/NetworkStatsService.java39
-rw-r--r--services/java/com/android/server/pm/Installer.java7
-rw-r--r--services/java/com/android/server/pm/PackageManagerService.java34
-rw-r--r--services/java/com/android/server/usb/UsbDeviceManager.java254
-rw-r--r--services/java/com/android/server/usb/UsbHostManager.java5
-rw-r--r--services/java/com/android/server/usb/UsbSettingsManager.java33
-rw-r--r--services/jni/com_android_server_connectivity_Vpn.cpp261
-rwxr-xr-xservices/jni/com_android_server_location_GpsLocationProvider.cpp10
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp166
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h9
-rw-r--r--services/surfaceflinger/tests/resize/resize.cpp8
-rw-r--r--services/surfaceflinger/tests/surface/surface.cpp4
-rw-r--r--services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java57
-rw-r--r--services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java4
-rw-r--r--telephony/java/android/telephony/PhoneNumberFormattingTextWatcher.java3
-rw-r--r--telephony/java/android/telephony/ServiceState.java25
-rw-r--r--telephony/java/android/telephony/TelephonyManager.java4
-rw-r--r--telephony/java/com/android/internal/telephony/CallerInfo.java10
-rw-r--r--telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java8
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java31
-rw-r--r--telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java13
-rw-r--r--tests/GridLayoutTest/res/layout/grid3.xml4
-rw-r--r--tests/GridLayoutTest/src/com/android/test/layout/Activity2.java4
-rw-r--r--tests/HwAccelerationTest/AndroidManifest.xml12
-rw-r--r--tests/HwAccelerationTest/src/com/android/test/hwui/TimeDialogActivity.java48
-rw-r--r--tests/RenderScriptTests/PerfTest/AndroidManifest.xml3
-rw-r--r--tests/RenderScriptTests/PerfTest/res/menu/loader_menu.xml25
-rw-r--r--tests/RenderScriptTests/PerfTest/res/values/strings.xml24
-rw-r--r--tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBench.java37
-rw-r--r--tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java110
-rw-r--r--tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchView.java12
-rw-r--r--tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs341
-rw-r--r--tests/RenderScriptTests/PerfTest/src/com/android/perftest/subtest_def.rsh28
-rw-r--r--tests/RenderScriptTests/PerfTest/src/com/android/perftest/text_test.rs82
-rw-r--r--tests/RenderScriptTests/PerfTest/src/com/android/perftest/torus_test.rs283
-rw-r--r--voip/java/com/android/server/sip/SipService.java122
-rw-r--r--voip/java/com/android/server/sip/SipWakeupTimer.java6
282 files changed, 7375 insertions, 3020 deletions
diff --git a/api/current.txt b/api/current.txt
index c23b28b27c5d..aa08bb4b54b2 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -596,10 +596,10 @@ package android {
field public static final int layout_centerInParent = 16843151; // 0x101018f
field public static final int layout_centerVertical = 16843153; // 0x1010191
field public static final int layout_column = 16843084; // 0x101014c
- field public static final int layout_columnSpan = 16843646; // 0x101037e
- field public static final int layout_columnWeight = 16843647; // 0x101037f
+ field public static final int layout_columnSpan = 16843645; // 0x101037d
field public static final int layout_gravity = 16842931; // 0x10100b3
field public static final int layout_height = 16842997; // 0x10100f5
+ field public static final int layout_heightSpec = 16843647; // 0x101037f
field public static final int layout_margin = 16842998; // 0x10100f6
field public static final int layout_marginBottom = 16843002; // 0x10100fa
field public static final int layout_marginEnd = 16843675; // 0x101039b
@@ -609,13 +609,13 @@ package android {
field public static final int layout_marginTop = 16843000; // 0x10100f8
field public static final int layout_row = 16843643; // 0x101037b
field public static final int layout_rowSpan = 16843644; // 0x101037c
- field public static final int layout_rowWeight = 16843645; // 0x101037d
field public static final int layout_scale = 16843155; // 0x1010193
field public static final int layout_span = 16843085; // 0x101014d
field public static final int layout_toLeftOf = 16843138; // 0x1010182
field public static final int layout_toRightOf = 16843139; // 0x1010183
field public static final int layout_weight = 16843137; // 0x1010181
field public static final int layout_width = 16842996; // 0x10100f4
+ field public static final int layout_widthSpec = 16843646; // 0x101037e
field public static final int layout_x = 16843135; // 0x101017f
field public static final int layout_y = 16843136; // 0x1010180
field public static final int left = 16843181; // 0x10101ad
@@ -3371,6 +3371,7 @@ package android.app {
method public void send(android.content.Context, int, android.content.Intent) throws android.app.PendingIntent.CanceledException;
method public void send(int, android.app.PendingIntent.OnFinished, android.os.Handler) throws android.app.PendingIntent.CanceledException;
method public void send(android.content.Context, int, android.content.Intent, android.app.PendingIntent.OnFinished, android.os.Handler) throws android.app.PendingIntent.CanceledException;
+ method public void send(android.content.Context, int, android.content.Intent, android.app.PendingIntent.OnFinished, android.os.Handler, java.lang.String) throws android.app.PendingIntent.CanceledException;
method public static void writePendingIntentOrNullToParcel(android.app.PendingIntent, android.os.Parcel);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
@@ -3452,6 +3453,7 @@ package android.app {
field public static final java.lang.String SUGGEST_COLUMN_INTENT_DATA = "suggest_intent_data";
field public static final java.lang.String SUGGEST_COLUMN_INTENT_DATA_ID = "suggest_intent_data_id";
field public static final java.lang.String SUGGEST_COLUMN_INTENT_EXTRA_DATA = "suggest_intent_extra_data";
+ field public static final java.lang.String SUGGEST_COLUMN_LAST_ACCESS_HINT = "suggest_last_access_hint";
field public static final java.lang.String SUGGEST_COLUMN_QUERY = "suggest_intent_query";
field public static final java.lang.String SUGGEST_COLUMN_SHORTCUT_ID = "suggest_shortcut_id";
field public static final java.lang.String SUGGEST_COLUMN_SPINNER_WHILE_REFRESHING = "suggest_spinner_while_refreshing";
@@ -5297,6 +5299,7 @@ package android.content {
method public java.lang.String getTargetPackage();
method public static android.content.IntentSender readIntentSenderOrNullFromParcel(android.os.Parcel);
method public void sendIntent(android.content.Context, int, android.content.Intent, android.content.IntentSender.OnFinished, android.os.Handler) throws android.content.IntentSender.SendIntentException;
+ method public void sendIntent(android.content.Context, int, android.content.Intent, android.content.IntentSender.OnFinished, android.os.Handler, java.lang.String) throws android.content.IntentSender.SendIntentException;
method public static void writeIntentSenderOrNullToParcel(android.content.IntentSender, android.os.Parcel);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator CREATOR;
@@ -5897,6 +5900,7 @@ package android.content.pm {
field public long codeSize;
field public long dataSize;
field public long externalCacheSize;
+ field public long externalCodeSize;
field public long externalDataSize;
field public long externalMediaSize;
field public long externalObbSize;
@@ -9398,6 +9402,7 @@ package android.inputmethodservice {
method public void onUpdateExtractingViews(android.view.inputmethod.EditorInfo);
method public void onUpdateExtractingVisibility(android.view.inputmethod.EditorInfo);
method public void onUpdateSelection(int, int, int, int, int, int);
+ method public void onViewClicked(boolean);
method public void onWindowHidden();
method public void onWindowShown();
method public void requestHideSelf(int);
@@ -9441,6 +9446,7 @@ package android.inputmethodservice {
method public void updateCursor(android.graphics.Rect);
method public void updateExtractedText(int, android.view.inputmethod.ExtractedText);
method public void updateSelection(int, int, int, int, int, int);
+ method public void viewClicked(boolean);
}
public static final class InputMethodService.Insets {
@@ -22259,6 +22265,7 @@ package android.view {
method public static deprecated int getTouchSlop();
method public static deprecated int getWindowTouchSlop();
method public static long getZoomControlsTimeout();
+ method public boolean hasPermanentMenuKey();
}
public class ViewDebug {
@@ -22393,6 +22400,7 @@ package android.view {
method public void requestDisallowInterceptTouchEvent(boolean);
method public boolean requestSendAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
method public void requestTransparentRegion(android.view.View);
+ method protected void resetLayoutDirectionResolution();
method public void scheduleLayoutAnimation();
method public void setAddStatesFromChildren(boolean);
method public void setAlwaysDrawnWithCacheEnabled(boolean);
@@ -23517,6 +23525,7 @@ package android.view.inputmethod {
method public void updateCursor(android.view.View, int, int, int, int);
method public void updateExtractedText(android.view.View, int, android.view.inputmethod.ExtractedText);
method public void updateSelection(android.view.View, int, int, int, int);
+ method public void viewClicked(android.view.View);
field public static final int HIDE_IMPLICIT_ONLY = 1; // 0x1
field public static final int HIDE_NOT_ALWAYS = 2; // 0x2
field public static final int RESULT_HIDDEN = 3; // 0x3
@@ -23537,6 +23546,7 @@ package android.view.inputmethod {
method public abstract void updateCursor(android.graphics.Rect);
method public abstract void updateExtractedText(int, android.view.inputmethod.ExtractedText);
method public abstract void updateSelection(int, int, int, int, int, int);
+ method public abstract void viewClicked(boolean);
}
public static abstract interface InputMethodSession.EventCallback {
@@ -24883,9 +24893,9 @@ package android.widget {
}
public class GridLayout extends android.view.ViewGroup {
- ctor public GridLayout(android.content.Context);
ctor public GridLayout(android.content.Context, android.util.AttributeSet, int);
ctor public GridLayout(android.content.Context, android.util.AttributeSet);
+ ctor public GridLayout(android.content.Context);
method public int getAlignmentMode();
method public int getColumnCount();
method public int getOrientation();
@@ -24905,8 +24915,11 @@ package android.widget {
field public static final int ALIGN_MARGINS = 1; // 0x1
field public static final android.widget.GridLayout.Alignment BASELINE;
field public static final android.widget.GridLayout.Alignment BOTTOM;
+ field public static final android.widget.GridLayout.Spec CAN_SHRINK;
+ field public static final android.widget.GridLayout.Spec CAN_STRETCH;
field public static final android.widget.GridLayout.Alignment CENTER;
field public static final android.widget.GridLayout.Alignment FILL;
+ field public static final android.widget.GridLayout.Spec FIXED;
field public static final int HORIZONTAL = 0; // 0x0
field public static final android.widget.GridLayout.Alignment LEFT;
field public static final android.widget.GridLayout.Alignment RIGHT;
@@ -24933,9 +24946,13 @@ package android.widget {
ctor public GridLayout.LayoutParams(android.content.Context, android.util.AttributeSet);
method public void setGravity(int);
field public android.widget.GridLayout.Group columnGroup;
- field public float columnWeight;
+ field public android.widget.GridLayout.Spec heightSpec;
field public android.widget.GridLayout.Group rowGroup;
- field public float rowWeight;
+ field public android.widget.GridLayout.Spec widthSpec;
+ }
+
+ public static abstract class GridLayout.Spec {
+ ctor public GridLayout.Spec();
}
public class GridView extends android.widget.AbsListView {
@@ -26059,6 +26076,7 @@ package android.widget {
method protected void onTextChanged(java.lang.CharSequence, int, int, int);
method public boolean onTextContextMenuItem(int);
method public void removeTextChangedListener(android.text.TextWatcher);
+ method protected void resetLayoutDirectionResolution();
method public final void setAutoLinkMask(int);
method public void setCompoundDrawablePadding(int);
method public void setCompoundDrawables(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 0acba8bc516b..ccd668d08192 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -213,9 +213,10 @@ status_t BootAnimation::readyToRun() {
// create the native surface
sp<SurfaceControl> control = session()->createSurface(
0, dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
- session()->openTransaction();
+
+ SurfaceComposerClient::openGlobalTransaction();
control->setLayer(0x40000000);
- session()->closeTransaction();
+ SurfaceComposerClient::closeGlobalTransaction();
sp<Surface> s = control->getSurface();
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index d45ac1925a24..26b911356699 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -288,8 +288,9 @@ int protect(char *pkgname, gid_t gid)
}
int get_size(const char *pkgname, const char *apkpath,
- const char *fwdlock_apkpath,
- int64_t *_codesize, int64_t *_datasize, int64_t *_cachesize)
+ const char *fwdlock_apkpath, const char *asecpath,
+ int64_t *_codesize, int64_t *_datasize, int64_t *_cachesize,
+ int64_t* _asecsize)
{
DIR *d;
int dfd;
@@ -300,6 +301,7 @@ int get_size(const char *pkgname, const char *apkpath,
int64_t codesize = 0;
int64_t datasize = 0;
int64_t cachesize = 0;
+ int64_t asecsize = 0;
/* count the source apk as code -- but only if it's not
* on the /system partition and its not on the sdcard.
@@ -324,6 +326,14 @@ int get_size(const char *pkgname, const char *apkpath,
}
}
+ /* compute asec size if it is given
+ */
+ if (asecpath != NULL && asecpath[0] != '!') {
+ if (stat(asecpath, &s) == 0) {
+ asecsize += stat_size(&s);
+ }
+ }
+
if (create_pkg_path(path, pkgname, PKG_DIR_POSTFIX, 0)) {
goto done;
}
@@ -370,6 +380,7 @@ done:
*_codesize = codesize;
*_datasize = datasize;
*_cachesize = cachesize;
+ *_asecsize = asecsize;
return 0;
}
diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c
index c062d36ec93b..feb6b927dd9b 100644
--- a/cmds/installd/installd.c
+++ b/cmds/installd/installd.c
@@ -77,16 +77,18 @@ static int do_get_size(char **arg, char reply[REPLY_MAX])
int64_t codesize = 0;
int64_t datasize = 0;
int64_t cachesize = 0;
+ int64_t asecsize = 0;
int res = 0;
/* pkgdir, apkpath */
- res = get_size(arg[0], arg[1], arg[2], &codesize, &datasize, &cachesize);
+ res = get_size(arg[0], arg[1], arg[2], arg[3], &codesize, &datasize, &cachesize, &asecsize);
/*
* Each int64_t can take up 22 characters printed out. Make sure it
* doesn't go over REPLY_MAX in the future.
*/
- snprintf(reply, REPLY_MAX, "%" PRId64 " %" PRId64 " %" PRId64, codesize, datasize, cachesize);
+ snprintf(reply, REPLY_MAX, "%" PRId64 " %" PRId64 " %" PRId64 " %" PRId64,
+ codesize, datasize, cachesize, asecsize);
return res;
}
@@ -137,7 +139,7 @@ struct cmdinfo cmds[] = {
{ "freecache", 1, do_free_cache },
{ "rmcache", 1, do_rm_cache },
{ "protect", 2, do_protect },
- { "getsize", 3, do_get_size },
+ { "getsize", 4, do_get_size },
{ "rmuserdata", 2, do_rm_user_data },
{ "movefiles", 0, do_movefiles },
{ "linklib", 2, do_linklib },
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index e5f6739d9081..c5872b8efa09 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -143,7 +143,8 @@ int move_dex(const char *src, const char *dst);
int rm_dex(const char *path);
int protect(char *pkgname, gid_t gid);
int get_size(const char *pkgname, const char *apkpath, const char *fwdlock_apkpath,
- int64_t *codesize, int64_t *datasize, int64_t *cachesize);
+ const char *asecpath, int64_t *codesize, int64_t *datasize, int64_t *cachesize,
+ int64_t *asecsize);
int free_cache(int64_t free_size);
int dexopt(const char *apk_path, uid_t uid, int is_public);
int movefiles();
diff --git a/cmds/keystore/keystore.cpp b/cmds/keystore/keystore.cpp
index 1c1f37a34c7b..4b4b9b9d4adb 100644
--- a/cmds/keystore/keystore.cpp
+++ b/cmds/keystore/keystore.cpp
@@ -712,7 +712,6 @@ static struct user {
{AID_VPN, AID_SYSTEM, GET},
{AID_WIFI, AID_SYSTEM, GET},
{AID_ROOT, AID_SYSTEM, GET},
- {AID_KEYCHAIN, AID_SYSTEM, TEST | GET | SAW},
{~0, ~0, TEST | GET | INSERT | DELETE | EXIST | SAW},
};
diff --git a/cmds/stagefright/sf2.cpp b/cmds/stagefright/sf2.cpp
index ddd64ecf0445..6fa66cf3524e 100644
--- a/cmds/stagefright/sf2.cpp
+++ b/cmds/stagefright/sf2.cpp
@@ -568,10 +568,10 @@ int main(int argc, char **argv) {
CHECK(control != NULL);
CHECK(control->isValid());
- CHECK_EQ(composerClient->openTransaction(), (status_t)OK);
+ SurfaceComposerClient::openGlobalTransaction();
CHECK_EQ(control->setLayer(30000), (status_t)OK);
CHECK_EQ(control->show(), (status_t)OK);
- CHECK_EQ(composerClient->closeTransaction(), (status_t)OK);
+ SurfaceComposerClient::closeGlobalTransaction();
surface = control->getSurface();
CHECK(surface != NULL);
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 656f5fdb4805..1a5b7f3ab8b1 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -865,10 +865,10 @@ int main(int argc, char **argv) {
CHECK(control != NULL);
CHECK(control->isValid());
- CHECK_EQ(composerClient->openTransaction(), (status_t)OK);
+ SurfaceComposerClient::openGlobalTransaction();
CHECK_EQ(control->setLayer(30000), (status_t)OK);
CHECK_EQ(control->show(), (status_t)OK);
- CHECK_EQ(composerClient->closeTransaction(), (status_t)OK);
+ SurfaceComposerClient::closeGlobalTransaction();
gSurface = control->getSurface();
CHECK(gSurface != NULL);
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
index f780afb80a0a..ee91c291c08d 100644
--- a/cmds/stagefright/stream.cpp
+++ b/cmds/stagefright/stream.cpp
@@ -20,6 +20,11 @@
#include <media/mediaplayer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MPEG2TSWriter.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
#include <binder/IServiceManager.h>
#include <media/IMediaPlayerService.h>
@@ -31,7 +36,7 @@
using namespace android;
struct MyStreamSource : public BnStreamSource {
- // Caller retains ownership of fd.
+ // Object assumes ownership of fd.
MyStreamSource(int fd);
virtual void setListener(const sp<IStreamListener> &listener);
@@ -64,6 +69,8 @@ MyStreamSource::MyStreamSource(int fd)
}
MyStreamSource::~MyStreamSource() {
+ close(mFd);
+ mFd = -1;
}
void MyStreamSource::setListener(const sp<IStreamListener> &listener) {
@@ -99,6 +106,143 @@ void MyStreamSource::onBufferAvailable(size_t index) {
mListener->queueBuffer(index, n);
}
}
+////////////////////////////////////////////////////////////////////////////////
+
+struct MyConvertingStreamSource : public BnStreamSource {
+ MyConvertingStreamSource(const char *filename);
+
+ virtual void setListener(const sp<IStreamListener> &listener);
+ virtual void setBuffers(const Vector<sp<IMemory> > &buffers);
+
+ virtual void onBufferAvailable(size_t index);
+
+protected:
+ virtual ~MyConvertingStreamSource();
+
+private:
+ Mutex mLock;
+ Condition mCondition;
+
+ sp<IStreamListener> mListener;
+ Vector<sp<IMemory> > mBuffers;
+
+ sp<MPEG2TSWriter> mWriter;
+
+ ssize_t mCurrentBufferIndex;
+ size_t mCurrentBufferOffset;
+
+ List<size_t> mBufferQueue;
+
+ static ssize_t WriteDataWrapper(void *me, const void *data, size_t size);
+ ssize_t writeData(const void *data, size_t size);
+
+ DISALLOW_EVIL_CONSTRUCTORS(MyConvertingStreamSource);
+};
+
+////////////////////////////////////////////////////////////////////////////////
+
+MyConvertingStreamSource::MyConvertingStreamSource(const char *filename)
+ : mCurrentBufferIndex(-1),
+ mCurrentBufferOffset(0) {
+ sp<DataSource> dataSource = DataSource::CreateFromURI(filename);
+ CHECK(dataSource != NULL);
+
+ sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
+ CHECK(extractor != NULL);
+
+ mWriter = new MPEG2TSWriter(
+ this, &MyConvertingStreamSource::WriteDataWrapper);
+
+ for (size_t i = 0; i < extractor->countTracks(); ++i) {
+ const sp<MetaData> &meta = extractor->getTrackMetaData(i);
+
+ const char *mime;
+ CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+ if (strncasecmp("video/", mime, 6) && strncasecmp("audio/", mime, 6)) {
+ continue;
+ }
+
+ CHECK_EQ(mWriter->addSource(extractor->getTrack(i)), (status_t)OK);
+ }
+
+ CHECK_EQ(mWriter->start(), (status_t)OK);
+}
+
+MyConvertingStreamSource::~MyConvertingStreamSource() {
+}
+
+void MyConvertingStreamSource::setListener(
+ const sp<IStreamListener> &listener) {
+ mListener = listener;
+}
+
+void MyConvertingStreamSource::setBuffers(
+ const Vector<sp<IMemory> > &buffers) {
+ mBuffers = buffers;
+}
+
+ssize_t MyConvertingStreamSource::WriteDataWrapper(
+ void *me, const void *data, size_t size) {
+ return static_cast<MyConvertingStreamSource *>(me)->writeData(data, size);
+}
+
+ssize_t MyConvertingStreamSource::writeData(const void *data, size_t size) {
+ size_t totalWritten = 0;
+
+ while (size > 0) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mCurrentBufferIndex < 0) {
+ while (mBufferQueue.empty()) {
+ mCondition.wait(mLock);
+ }
+
+ mCurrentBufferIndex = *mBufferQueue.begin();
+ mCurrentBufferOffset = 0;
+
+ mBufferQueue.erase(mBufferQueue.begin());
+ }
+
+ sp<IMemory> mem = mBuffers.itemAt(mCurrentBufferIndex);
+
+ size_t copy = size;
+ if (copy + mCurrentBufferOffset > mem->size()) {
+ copy = mem->size() - mCurrentBufferOffset;
+ }
+
+ memcpy((uint8_t *)mem->pointer() + mCurrentBufferOffset, data, copy);
+ mCurrentBufferOffset += copy;
+
+ if (mCurrentBufferOffset == mem->size()) {
+ mListener->queueBuffer(mCurrentBufferIndex, mCurrentBufferOffset);
+ mCurrentBufferIndex = -1;
+ }
+
+ data = (const uint8_t *)data + copy;
+ size -= copy;
+
+ totalWritten += copy;
+ }
+
+ return (ssize_t)totalWritten;
+}
+
+void MyConvertingStreamSource::onBufferAvailable(size_t index) {
+ Mutex::Autolock autoLock(mLock);
+
+ mBufferQueue.push_back(index);
+ mCondition.signal();
+
+ if (mWriter->reachedEOS()) {
+ if (mCurrentBufferIndex >= 0) {
+ mListener->queueBuffer(mCurrentBufferIndex, mCurrentBufferOffset);
+ mCurrentBufferIndex = -1;
+ }
+
+ mListener->issueCommand(IStreamListener::EOS, false /* synchronous */);
+ }
+}
////////////////////////////////////////////////////////////////////////////////
@@ -139,6 +283,8 @@ private:
int main(int argc, char **argv) {
android::ProcessState::self()->startThreadPool();
+ DataSource::RegisterDefaultSniffers();
+
if (argc != 2) {
fprintf(stderr, "Usage: %s filename\n", argv[0]);
return 1;
@@ -159,10 +305,10 @@ int main(int argc, char **argv) {
CHECK(control != NULL);
CHECK(control->isValid());
- CHECK_EQ(composerClient->openTransaction(), (status_t)OK);
+ SurfaceComposerClient::openGlobalTransaction();
CHECK_EQ(control->setLayer(30000), (status_t)OK);
CHECK_EQ(control->show(), (status_t)OK);
- CHECK_EQ(composerClient->closeTransaction(), (status_t)OK);
+ SurfaceComposerClient::closeGlobalTransaction();
sp<Surface> surface = control->getSurface();
CHECK(surface != NULL);
@@ -173,17 +319,28 @@ int main(int argc, char **argv) {
CHECK(service.get() != NULL);
- int fd = open(argv[1], O_RDONLY);
+ sp<MyClient> client = new MyClient;
+
+ sp<IStreamSource> source;
- if (fd < 0) {
- fprintf(stderr, "Failed to open file '%s'.", argv[1]);
- return 1;
- }
+ size_t len = strlen(argv[1]);
+ if (len >= 3 && !strcasecmp(".ts", &argv[1][len - 3])) {
+ int fd = open(argv[1], O_RDONLY);
- sp<MyClient> client = new MyClient;
+ if (fd < 0) {
+ fprintf(stderr, "Failed to open file '%s'.", argv[1]);
+ return 1;
+ }
+
+ source = new MyStreamSource(fd);
+ } else {
+ printf("Converting file to transport stream for streaming...\n");
+
+ source = new MyConvertingStreamSource(argv[1]);
+ }
sp<IMediaPlayer> player =
- service->create(getpid(), client, new MyStreamSource(fd), 0);
+ service->create(getpid(), client, source, 0);
if (player != NULL) {
player->setVideoSurface(surface);
@@ -196,9 +353,6 @@ int main(int argc, char **argv) {
fprintf(stderr, "failed to instantiate player.\n");
}
- close(fd);
- fd = -1;
-
composerClient->dispose();
return 0;
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 164acbcdf71f..68c992671f97 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -31,82 +31,151 @@ import android.view.accessibility.AccessibilityNodeInfo;
* An accessibility service runs in the background and receives callbacks by the system
* when {@link AccessibilityEvent}s are fired. Such events denote some state transition
* in the user interface, for example, the focus has changed, a button has been clicked,
- * etc.
+ * etc. Such a service can optionally request the capability for querying the content
+ * of the active window. Development of an accessibility service requires extends this
+ * class and implements its abstract methods.
* <p>
- * An accessibility service extends this class and implements its abstract methods. Such
- * a service is declared as any other service in an AndroidManifest.xml but it must also
- * specify that it handles the "android.accessibilityservice.AccessibilityService"
- * {@link android.content.Intent}. Following is an example of such a declaration:
- * <p>
- * <code>
- * &lt;service android:name=".MyAccessibilityService"&gt;<br>
- * &nbsp;&nbsp;&lt;intent-filter&gt;<br>
- * &nbsp;&nbsp;&nbsp;&nbsp;&lt;action android:name="android.accessibilityservice.AccessibilityService" /&gt;<br>
- * &nbsp;&nbsp;&lt;/intent-filter&gt;<br>
- * &lt;/service&gt;<br>
- * </code>
+ * <strong>Lifecycle</strong>
* </p>
* <p>
- * The lifecycle of an accessibility service is managed exclusively by the system. Starting
- * or stopping an accessibility service is triggered by an explicit user action through
+ * The lifecycle of an accessibility service is managed exclusively by the system and
+ * follows the established service life cycle. Additionally, starting or stopping an
+ * accessibility service is triggered exclusively by an explicit user action through
* enabling or disabling it in the device settings. After the system binds to a service it
* calls {@link AccessibilityService#onServiceConnected()}. This method can be
* overriden by clients that want to perform post binding setup.
* </p>
* <p>
+ * <strong>Declaration</strong>
+ * </p>
+ * <p>
+ * An accessibility is declared as any other service in an AndroidManifest.xml but it
+ * must also specify that it handles the "android.accessibilityservice.AccessibilityService"
+ * {@link android.content.Intent}. Failure to declare this intent will cause the system to
+ * ignore the accessibility service. Following is an example declaration:
+ * </p>
+ * <p>
+ * <code>
+ * <pre>
+ * &lt;service android:name=".MyAccessibilityService"&gt;
+ * &lt;intent-filter&gt;
+ * &lt;action android:name="android.accessibilityservice.AccessibilityService" /&gt;
+ * &lt;/intent-filter&gt;
+ * . . .
+ * &lt;/service&gt;
+ * </pre>
+ * </code>
+ * </p>
+ * <p>
+ * <strong>Configuration</strong>
+ * </p>
+ * <p>
* An accessibility service can be configured to receive specific types of accessibility events,
* listen only to specific packages, get events from each type only once in a given time frame,
* retrieve window content, specify a settings activity, etc.
* </p>
+ * <p>
* There are two approaches for configuring an accessibility service:
+ * </p>
* <ul>
- * <li>
- * Providing a {@link #SERVICE_META_DATA meta-data} entry in the manifest when declaring
- * the service. A service declaration with a meta-data tag is presented below:
- * <p>
- * <code>
- * &lt;service android:name=".MyAccessibilityService"&gt;<br>
- * &nbsp;&nbsp;&lt;intent-filter&gt;<br>
- * &nbsp;&nbsp;&nbsp;&nbsp;&lt;action android:name="android.accessibilityservice.AccessibilityService" /&gt;<br>
- * &nbsp;&nbsp;&lt;/intent-filter&gt;<br>
- * &nbsp;&nbsp;&lt;meta-data android:name="android.accessibilityservice.as" android:resource="@xml/accessibilityservice" /&gt;<br>
- * &lt;/service&gt;<br>
- * </code>
- * </p>
- * <p>
- * <strong>
- * This approach enables setting all accessibility service properties.
- * </strong>
- * </p>
- * <p>
- * For more details refer to {@link #SERVICE_META_DATA}.
- * </p>
- * </li>
- * <li>
- * Calling {@link AccessibilityService#setServiceInfo(AccessibilityServiceInfo)}. Note
- * that this method can be called any time to change the service configuration.<br>
- * <p>
- * <strong>
- * This approach enables setting only dynamically configurable accessibility
- * service properties:
- * {@link AccessibilityServiceInfo#eventTypes},
- * {@link AccessibilityServiceInfo#feedbackType},
- * {@link AccessibilityServiceInfo#flags},
- * {@link AccessibilityServiceInfo#notificationTimeout},
- * {@link AccessibilityServiceInfo#packageNames}
- * </strong>
- * </p>
- * <p>
- * For more details refer to {@link AccessibilityServiceInfo}.
- * </p>
- * </li>
+ * <li>
+ * Providing a {@link #SERVICE_META_DATA meta-data} entry in the manifest when declaring
+ * the service. A service declaration with a meta-data tag is presented below:
+ * <p>
+ * <code>
+ * <pre>
+ * &lt;service android:name=".MyAccessibilityService"&gt;
+ * &lt;intent-filter&gt;
+ * &lt;action android:name="android.accessibilityservice.AccessibilityService" /&gt;
+ * &lt;/intent-filter&gt;
+ * &lt;meta-data android:name="android.accessibilityservice" android:resource="@xml/accessibilityservice" /&gt;
+ * &lt;/service&gt;
+ * </pre>
+ * </code>
+ * </p>
+ * <p>
+ * <strong>Note:</strong>This approach enables setting all properties.
+ * </p>
+ * <p>
+ * For more details refer to {@link #SERVICE_META_DATA} and
+ * <code>&lt;{@link android.R.styleable#AccessibilityService accessibility-service}&gt;</code>..
+ * </p>
+ * </li>
+ * <li>
+ * Calling {@link AccessibilityService#setServiceInfo(AccessibilityServiceInfo)}. Note
+ * that this method can be called any time to dynamically change the service configuration.
+ * <p>
+ * <strong>Note:</strong> This approach enables setting only dynamically configurable properties:
+ * {@link AccessibilityServiceInfo#eventTypes},
+ * {@link AccessibilityServiceInfo#feedbackType},
+ * {@link AccessibilityServiceInfo#flags},
+ * {@link AccessibilityServiceInfo#notificationTimeout},
+ * {@link AccessibilityServiceInfo#packageNames}
+ * </p>
+ * <p>
+ * For more details refer to {@link AccessibilityServiceInfo}.
+ * </p>
+ * </li>
* </ul>
* <p>
- * An accessibility service can be registered for events in specific packages to provide a
- * specific type of feedback and is notified with a certain timeout after the last event
- * of interest has been fired.
+ * <strong>Retrieving window content</strong>
+ * </p>
+ * <p>
+ * An service can specify in its declaration that it can retrieve the active window
+ * content which is represented as a tree of {@link AccessibilityNodeInfo}. Note that
+ * declaring this capability requires that the service declares its configuration via
+ * an XML resource referenced by {@link #SERVICE_META_DATA}.
+ * </p>
+ * <p>
+ * For security purposes an accessibility service can retrieve only the content of the
+ * currently active window. The currently active window is defined as the window from
+ * which was fired the last event of the following types:
+ * {@link AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_START},
+ * {@link AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END},
+ * {@link AccessibilityEvent#TYPE_VIEW_CLICKED},
+ * {@link AccessibilityEvent#TYPE_VIEW_FOCUSED},
+ * {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER},
+ * {@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT},
+ * {@link AccessibilityEvent#TYPE_VIEW_LONG_CLICKED},
+ * {@link AccessibilityEvent#TYPE_VIEW_SELECTED},
+ * {@link AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED},
+ * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED},
+ * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED},
+ * {@link AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED},
+ * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED}.
+ * In other words, the active window is the one where the user interaction is taking place.
+ * </p>
+ * <p>
+ * The entry point for retrieving window content is through calling
+ * {@link AccessibilityEvent#getSource() AccessibilityEvent.getSource()} of the last received
+ * event of the above types or a previous event from the same window
+ * (see {@link AccessibilityEvent#getWindowId() AccessibilityEvent.getWindowId()}). Invoking
+ * this method will return an {@link AccessibilityNodeInfo} that can be used to traverse the
+ * window content which represented as a tree of such objects.
+ * </p>
+ * <p>
+ * <strong>Note</strong>An accessibility service may have requested to be notified for
+ * a subset of the event types, thus be unaware that the active window has changed. Therefore
+ * accessibility service that would like to retrieve window content should:
+ * <ul>
+ * <li>
+ * Register for all event types with no notification timeout and keep track for the active
+ * window by calling {@link AccessibilityEvent#getWindowId()} of the last received event and
+ * compare this with the {@link AccessibilityNodeInfo#getWindowId()} before calling retrieval
+ * methods on the latter.
+ * </li>
+ * <li>
+ * Prepare that a retrieval method on {@link AccessibilityNodeInfo} may fail since the
+ * active window has changed and the service did not get the accessibility event yet. Note
+ * that it is possible to have a retrieval method failing event adopting the strategy
+ * specified in the previous bullet because the accessibility event dispatch is asynchronous
+ * and crosses process boundaries.
+ * </li>
+ * </ul>
+ * </p>
* <p>
* <b>Notification strategy</b>
+ * </p>
* <p>
* For each feedback type only one accessibility service is notified. Services are notified
* in the order of registration. Hence, if two services are registered for the same
@@ -117,9 +186,10 @@ import android.view.accessibility.AccessibilityNodeInfo;
* registration order. This enables "generic" accessibility services that work reasonably
* well with most applications to coexist with "polished" ones that are targeted for
* specific applications.
+ * </p>
* <p>
* <b>Event types</b>
- * <p>
+ * </p>
* {@link AccessibilityEvent#TYPE_VIEW_CLICKED}
* {@link AccessibilityEvent#TYPE_VIEW_LONG_CLICKED}
* {@link AccessibilityEvent#TYPE_VIEW_FOCUSED}
@@ -127,9 +197,16 @@ import android.view.accessibility.AccessibilityNodeInfo;
* {@link AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED}
* {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED}
* {@link AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED}
- * <p>
- * <b>Feedback types</b>
- * <p>
+ * {@link AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_START}
+ * {@link AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END}
+ * {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER}
+ * {@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT}
+ * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED}
+ * {@link AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED}
+ * {@link AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED}
+ * <p>
+ * <b>Feedback types</b>
+ * <p>
* {@link AccessibilityServiceInfo#FEEDBACK_AUDIBLE}
* {@link AccessibilityServiceInfo#FEEDBACK_HAPTIC}
* {@link AccessibilityServiceInfo#FEEDBACK_AUDIBLE}
@@ -140,10 +217,10 @@ import android.view.accessibility.AccessibilityNodeInfo;
* @see AccessibilityServiceInfo
* @see android.view.accessibility.AccessibilityManager
*
- * Note: The event notification timeout is useful to avoid propagating events to the client
- * too frequently since this is accomplished via an expensive interprocess call.
- * One can think of the timeout as a criteria to determine when event generation has
- * settled down.
+ * <strong>Note:</strong> The event notification timeout is useful to avoid propagating
+ * events to the client too frequently since this is accomplished via an expensive
+ * interprocess call. One can think of the timeout as a criteria to determine when
+ * event generation has settled down.
*/
public abstract class AccessibilityService extends Service {
/**
@@ -154,57 +231,25 @@ public abstract class AccessibilityService extends Service {
/**
* Name under which an AccessibilityService component publishes information
- * about itself. This meta-data must reference an XML resource containing
- * an
+ * about itself. This meta-data must reference an XML resource containing an
* <code>&lt;{@link android.R.styleable#AccessibilityService accessibility-service}&gt;</code>
* tag. This is a a sample XML file configuring an accessibility service:
* <p>
* <code>
- * &lt;?xml version="1.0" encoding="utf-8"?&gt;<br>
- * &lt;accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"<br>
- * &nbsp;&nbsp;android:accessibilityEventTypes="typeViewClicked|typeViewFocused"<br>
- * &nbsp;&nbsp;android:packageNames="foo.bar, foo.baz"<br>
- * &nbsp;&nbsp;android:accessibilityFeedbackType="feedbackSpoken"<br>
- * &nbsp;&nbsp;android:notificationTimeout="100"<br>
- * &nbsp;&nbsp;android:accessibilityFlags="flagDefault"<br>
- * &nbsp;&nbsp;android:settingsActivity="foo.bar.TestBackActivity"<br>
- * &nbsp;&nbsp;. . .<br>
+ * <pre>
+ * &lt;accessibility-service
+ * android:accessibilityEventTypes="typeViewClicked|typeViewFocused"
+ * android:packageNames="foo.bar, foo.baz"
+ * android:accessibilityFeedbackType="feedbackSpoken"
+ * android:notificationTimeout="100"
+ * android:accessibilityFlags="flagDefault"
+ * android:settingsActivity="foo.bar.TestBackActivity"
+ * android:canRetrieveWindowContent="true"
+ * . . .
* /&gt;
+ * </pre>
* </code>
* </p>
- * <p>
- * <strong>Note:</strong> A service can retrieve only the content of the active window.
- * An active window is the source of the most recent event of type
- * {@link AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_START},
- * {@link AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END},
- * {@link AccessibilityEvent#TYPE_VIEW_CLICKED},
- * {@link AccessibilityEvent#TYPE_VIEW_FOCUSED},
- * {@link AccessibilityEvent#TYPE_VIEW_HOVER_ENTER},
- * {@link AccessibilityEvent#TYPE_VIEW_HOVER_EXIT},
- * {@link AccessibilityEvent#TYPE_VIEW_LONG_CLICKED},
- * {@link AccessibilityEvent#TYPE_VIEW_SELECTED},
- * {@link AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED},
- * {@link AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED}.
- * Therefore the service should:
- * <ul>
- * <li>
- * Register for all event types with no notification timeout and keep track
- * for the active window by calling
- * {@link AccessibilityEvent#getWindowId()} of the last received
- * event and compare this with the
- * {@link AccessibilityNodeInfo#getWindowId()} before calling
- * retrieval methods on the latter.
- * </li>
- * <li>
- * Prepare that a retrieval method on {@link AccessibilityNodeInfo} may fail
- * since the active window has changed and the service did not get the
- * accessibility event. Note that it is possible to have a retrieval method
- * failing event adopting the strategy specified in the previous bullet
- * because the accessibility event dispatch is asynchronous and crosses
- * process boundaries.
- * </li>
- * <ul>
- * </p>
*/
public static final String SERVICE_META_DATA = "android.accessibilityservice";
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index b9878cd9c97a..ef4adca97a82 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -37,13 +37,13 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
/**
- * This class describes an {@link AccessibilityService}. The system
- * notifies an {@link AccessibilityService} for
- * {@link android.view.accessibility.AccessibilityEvent}s
+ * This class describes an {@link AccessibilityService}. The system notifies an
+ * {@link AccessibilityService} for {@link android.view.accessibility.AccessibilityEvent}s
* according to the information encapsulated in this class.
*
* @see AccessibilityService
* @see android.view.accessibility.AccessibilityEvent
+ * @see android.view.accessibility.AccessibilityManager
*/
public class AccessibilityServiceInfo implements Parcelable {
@@ -93,12 +93,19 @@ public class AccessibilityServiceInfo implements Parcelable {
* @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_CHANGED
* @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOW_STATE_CHANGED
* @see android.view.accessibility.AccessibilityEvent#TYPE_NOTIFICATION_STATE_CHANGED
+ * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_START
+ * @see android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END
+ * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_ENTER
+ * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_HOVER_EXIT
+ * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_SCROLLED
+ * @see android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED
+ * @see android.view.accessibility.AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED
*/
public int eventTypes;
/**
* The package names an {@link AccessibilityService} is interested in. Setting
- * to null is equivalent to all packages.
+ * to <code>null</code> is equivalent to all packages.
* <p>
* <strong>Can be dynamically set at runtime.</strong>
* </p>
@@ -125,10 +132,10 @@ public class AccessibilityServiceInfo implements Parcelable {
* <strong>Can be dynamically set at runtime.</strong>.
* </p>
* <p>
- * Note: The event notification timeout is useful to avoid propagating events to the client
- * too frequently since this is accomplished via an expensive interprocess call.
- * One can think of the timeout as a criteria to determine when event generation has
- * settled down
+ * <strong>Note:</strong> The event notification timeout is useful to avoid propagating
+ * events to the client too frequently since this is accomplished via an expensive
+ * interprocess call. One can think of the timeout as a criteria to determine when
+ * event generation has settled down.
*/
public long notificationTimeout;
@@ -159,7 +166,7 @@ public class AccessibilityServiceInfo implements Parcelable {
private String mSettingsActivityName;
/**
- * Flag whether this accessibility service can retrieve screen content.
+ * Flag whether this accessibility service can retrieve window content.
*/
private boolean mCanRetrieveWindowContent;
@@ -296,12 +303,12 @@ public class AccessibilityServiceInfo implements Parcelable {
}
/**
- * Whether this service can retrieve the currently focused window content.
+ * Whether this service can retrieve the current window's content.
* <p>
* <strong>Statically set from
* {@link AccessibilityService#SERVICE_META_DATA meta-data}.</strong>
* </p>
- * @return True screen content is retrieved.
+ * @return True window content can be retrieved.
*/
public boolean getCanRetrieveWindowContent() {
return mCanRetrieveWindowContent;
diff --git a/core/java/android/accessibilityservice/package.html b/core/java/android/accessibilityservice/package.html
new file mode 100644
index 000000000000..0c640d14368f
--- /dev/null
+++ b/core/java/android/accessibilityservice/package.html
@@ -0,0 +1,22 @@
+<html>
+<body>
+<p>
+ The classes in this package are used for development of accessibility service that
+ provide alternative or augmented feedback to the user.
+</p>
+<p>
+ An {@link android.accessibilityservice.AccessibilityService} runs in the background and
+ receives callbacks by the system when {@link android.view.accessibility.AccessibilityEvent}s
+ are fired. Such events denote some state transition in the user interface, for example, the
+ focus has changed, a button has been clicked, etc. Such a service can optionally request the
+ capability for querying the content of the active window. Development of an accessibility
+ service requires extends this class and implements its abstract methods.
+</p>
+<p>
+ An {@link android.accessibilityservice.AccessibilityServiceInfo} describes an
+ {@link android.accessibilityservice.AccessibilityService}. The system notifies an
+ AccessibilityService for {@link android.view.accessibility.AccessibilityEvent}s
+ according to the information encapsulated in this class.
+</p>
+</body>
+</html>
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 85f40c92963a..fdf4a3af906d 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -251,12 +251,13 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
IBinder b = data.readStrongBinder();
IApplicationThread app =
b != null ? ApplicationThreadNative.asInterface(b) : null;
+ String packageName = data.readString();
b = data.readStrongBinder();
IIntentReceiver rec
= b != null ? IIntentReceiver.Stub.asInterface(b) : null;
IntentFilter filter = IntentFilter.CREATOR.createFromParcel(data);
String perm = data.readString();
- Intent intent = registerReceiver(app, rec, filter, perm);
+ Intent intent = registerReceiver(app, packageName, rec, filter, perm);
reply.writeNoException();
if (intent != null) {
reply.writeInt(1);
@@ -1503,6 +1504,16 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
+ case IS_INTENT_SENDER_TARGETED_TO_PACKAGE_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IIntentSender r = IIntentSender.Stub.asInterface(
+ data.readStrongBinder());
+ boolean res = isIntentSenderTargetedToPackage(r);
+ reply.writeNoException();
+ reply.writeInt(res ? 1 : 0);
+ return true;
+ }
+
}
return super.onTransact(code, data, reply, flags);
@@ -1702,7 +1713,7 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
return res;
}
- public Intent registerReceiver(IApplicationThread caller,
+ public Intent registerReceiver(IApplicationThread caller, String packageName,
IIntentReceiver receiver,
IntentFilter filter, String perm) throws RemoteException
{
@@ -1710,6 +1721,7 @@ class ActivityManagerProxy implements IActivityManager
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
+ data.writeString(packageName);
data.writeStrongBinder(receiver != null ? receiver.asBinder() : null);
filter.writeToParcel(data, 0);
data.writeString(perm);
@@ -3385,5 +3397,18 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
}
+ public boolean isIntentSenderTargetedToPackage(IIntentSender sender) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(sender.asBinder());
+ mRemote.transact(IS_INTENT_SENDER_TARGETED_TO_PACKAGE_TRANSACTION, data, reply, 0);
+ reply.readException();
+ boolean res = reply.readInt() != 0;
+ data.recycle();
+ reply.recycle();
+ return res;
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 94a4afaf5629..8749d3e17e0e 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -61,7 +61,6 @@ import android.net.wifi.IWifiManager;
import android.net.wifi.WifiManager;
import android.nfc.NfcManager;
import android.os.Binder;
-import android.os.Build;
import android.os.Bundle;
import android.os.DropBoxManager;
import android.os.Environment;
@@ -81,7 +80,6 @@ import android.content.ClipboardManager;
import android.util.AndroidRuntimeException;
import android.util.Log;
import android.view.ContextThemeWrapper;
-import android.view.Display;
import android.view.WindowManagerImpl;
import android.view.accessibility.AccessibilityManager;
import android.view.inputmethod.InputMethodManager;
@@ -142,6 +140,7 @@ class ContextImpl extends Context {
new HashMap<String, SharedPreferencesImpl>();
/*package*/ LoadedApk mPackageInfo;
+ private String mBasePackageName;
private Resources mResources;
/*package*/ ActivityThread mMainThread;
private Context mOuterContext;
@@ -1030,7 +1029,7 @@ class ContextImpl extends Context {
}
try {
return ActivityManagerNative.getDefault().registerReceiver(
- mMainThread.getApplicationThread(),
+ mMainThread.getApplicationThread(), mBasePackageName,
rd, filter, broadcastPermission);
} catch (RemoteException e) {
return null;
@@ -1397,7 +1396,7 @@ class ContextImpl extends Context {
if (pi != null) {
ContextImpl c = new ContextImpl();
c.mRestricted = (flags & CONTEXT_RESTRICTED) == CONTEXT_RESTRICTED;
- c.init(pi, null, mMainThread, mResources);
+ c.init(pi, null, mMainThread, mResources, mBasePackageName);
if (c.mResources != null) {
return c;
}
@@ -1450,6 +1449,7 @@ class ContextImpl extends Context {
*/
public ContextImpl(ContextImpl context) {
mPackageInfo = context.mPackageInfo;
+ mBasePackageName = context.mBasePackageName;
mResources = context.mResources;
mMainThread = context.mMainThread;
mContentResolver = context.mContentResolver;
@@ -1458,13 +1458,14 @@ class ContextImpl extends Context {
final void init(LoadedApk packageInfo,
IBinder activityToken, ActivityThread mainThread) {
- init(packageInfo, activityToken, mainThread, null);
+ init(packageInfo, activityToken, mainThread, null, null);
}
final void init(LoadedApk packageInfo,
IBinder activityToken, ActivityThread mainThread,
- Resources container) {
+ Resources container, String basePackageName) {
mPackageInfo = packageInfo;
+ mBasePackageName = basePackageName != null ? basePackageName : packageInfo.mPackageName;
mResources = mPackageInfo.getResources(mainThread);
if (mResources != null && container != null
@@ -1485,6 +1486,7 @@ class ContextImpl extends Context {
final void init(Resources resources, ActivityThread mainThread) {
mPackageInfo = null;
+ mBasePackageName = null;
mResources = resources;
mMainThread = mainThread;
mContentResolver = new ApplicationContentResolver(this, mainThread);
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index e2588cfb5eb1..9e207646a9a2 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -103,7 +103,7 @@ public interface IActivityManager extends IInterface {
throws RemoteException;
public void finishSubActivity(IBinder token, String resultWho, int requestCode) throws RemoteException;
public boolean willActivityBeVisible(IBinder token) throws RemoteException;
- public Intent registerReceiver(IApplicationThread caller,
+ public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter,
String requiredPermission) throws RemoteException;
public void unregisterReceiver(IIntentReceiver receiver) throws RemoteException;
@@ -361,6 +361,8 @@ public interface IActivityManager extends IInterface {
public void registerProcessObserver(IProcessObserver observer) throws RemoteException;
public void unregisterProcessObserver(IProcessObserver observer) throws RemoteException;
+ public boolean isIntentSenderTargetedToPackage(IIntentSender sender) throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -587,4 +589,5 @@ public interface IActivityManager extends IInterface {
int REMOVE_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+131;
int REGISTER_PROCESS_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+132;
int UNREGISTER_PROCESS_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+133;
+ int IS_INTENT_SENDER_TARGETED_TO_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+134;
}
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index 5b43b650abb1..b4827cbb7a65 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -365,7 +365,7 @@ public final class PendingIntent implements Parcelable {
* is no longer allowing more intents to be sent through it.
*/
public void send() throws CanceledException {
- send(null, 0, null, null, null);
+ send(null, 0, null, null, null, null);
}
/**
@@ -379,7 +379,7 @@ public final class PendingIntent implements Parcelable {
* is no longer allowing more intents to be sent through it.
*/
public void send(int code) throws CanceledException {
- send(null, code, null, null, null);
+ send(null, code, null, null, null, null);
}
/**
@@ -399,7 +399,7 @@ public final class PendingIntent implements Parcelable {
*/
public void send(Context context, int code, Intent intent)
throws CanceledException {
- send(context, code, intent, null, null);
+ send(context, code, intent, null, null, null);
}
/**
@@ -420,7 +420,7 @@ public final class PendingIntent implements Parcelable {
*/
public void send(int code, OnFinished onFinished, Handler handler)
throws CanceledException {
- send(null, code, null, onFinished, handler);
+ send(null, code, null, onFinished, handler, null);
}
/**
@@ -449,20 +449,64 @@ public final class PendingIntent implements Parcelable {
* @see #send(int)
* @see #send(Context, int, Intent)
* @see #send(int, android.app.PendingIntent.OnFinished, Handler)
+ * @see #send(Context, int, Intent, OnFinished, Handler, String)
*
* @throws CanceledException Throws CanceledException if the PendingIntent
* is no longer allowing more intents to be sent through it.
*/
public void send(Context context, int code, Intent intent,
OnFinished onFinished, Handler handler) throws CanceledException {
+ send(context, code, intent, onFinished, handler, null);
+ }
+
+ /**
+ * Perform the operation associated with this PendingIntent, allowing the
+ * caller to specify information about the Intent to use and be notified
+ * when the send has completed.
+ *
+ * <p>For the intent parameter, a PendingIntent
+ * often has restrictions on which fields can be supplied here, based on
+ * how the PendingIntent was retrieved in {@link #getActivity},
+ * {@link #getBroadcast}, or {@link #getService}.
+ *
+ * @param context The Context of the caller. This may be null if
+ * <var>intent</var> is also null.
+ * @param code Result code to supply back to the PendingIntent's target.
+ * @param intent Additional Intent data. See {@link Intent#fillIn
+ * Intent.fillIn()} for information on how this is applied to the
+ * original Intent. Use null to not modify the original Intent.
+ * @param onFinished The object to call back on when the send has
+ * completed, or null for no callback.
+ * @param handler Handler identifying the thread on which the callback
+ * should happen. If null, the callback will happen from the thread
+ * pool of the process.
+ * @param requiredPermission Name of permission that a recipient of the PendingIntent
+ * is required to hold. This is only valid for broadcast intents, and
+ * corresponds to the permission argument in
+ * {@link Context#sendBroadcast(Intent, String) Context.sendOrderedBroadcast(Intent, String)}.
+ * If null, no permission is required.
+ *
+ * @see #send()
+ * @see #send(int)
+ * @see #send(Context, int, Intent)
+ * @see #send(int, android.app.PendingIntent.OnFinished, Handler)
+ * @see #send(Context, int, Intent, OnFinished, Handler)
+ *
+ * @throws CanceledException Throws CanceledException if the PendingIntent
+ * is no longer allowing more intents to be sent through it.
+ */
+ public void send(Context context, int code, Intent intent,
+ OnFinished onFinished, Handler handler, String requiredPermission)
+ throws CanceledException {
try {
String resolvedType = intent != null ?
intent.resolveTypeIfNeeded(context.getContentResolver())
: null;
int res = mTarget.send(code, intent, resolvedType,
onFinished != null
- ? new FinishedDispatcher(this, onFinished, handler)
- : null);
+ ? new FinishedDispatcher(this, onFinished, handler)
+ : null,
+ requiredPermission);
if (res < 0) {
throw new CanceledException();
}
@@ -491,6 +535,20 @@ public final class PendingIntent implements Parcelable {
}
/**
+ * @hide
+ * Check to verify that this PendingIntent targets a specific package.
+ */
+ public boolean isTargetedToPackage() {
+ try {
+ return ActivityManagerNative.getDefault()
+ .isIntentSenderTargetedToPackage(mTarget);
+ } catch (RemoteException e) {
+ // Should never happen.
+ return false;
+ }
+ }
+
+ /**
* Comparison operator on two PendingIntent objects, such that true
* is returned then they both represent the same operation from the
* same package. This allows you to use {@link #getActivity},
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 41eea2e83b31..42eda0212e01 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -188,8 +188,9 @@ public class SearchDialog extends Dialog {
mSearchPlate = mSearchView.findViewById(com.android.internal.R.id.search_plate);
mWorkingSpinner = getContext().getResources().
getDrawable(com.android.internal.R.drawable.search_spinner);
- mSearchAutoComplete.setCompoundDrawablesWithIntrinsicBounds(
- null, null, mWorkingSpinner, null);
+ // TODO: Restore the spinner for slow suggestion lookups
+ // mSearchAutoComplete.setCompoundDrawablesWithIntrinsicBounds(
+ // null, null, mWorkingSpinner, null);
setWorking(false);
// pre-hide all the extraneous elements
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 85a2fa831f65..7274362e77b5 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -329,6 +329,15 @@ public class SearchManager
public final static String SUGGEST_COLUMN_FLAGS = "suggest_flags";
/**
+ * Column name for suggestions cursor. <i>Optional.</i> This column may be
+ * used to specify the time in (@link System#currentTimeMillis
+ * System.currentTImeMillis()} (wall time in UTC) when an item was last
+ * accessed within the results-providing application. If set, this may be
+ * used to show more-recently-used items first.
+ */
+ public final static String SUGGEST_COLUMN_LAST_ACCESS_HINT = "suggest_last_access_hint";
+
+ /**
* Column value for suggestion column {@link #SUGGEST_COLUMN_SHORTCUT_ID} when a suggestion
* should not be stored as a shortcut in global search.
*/
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index aecec66b9f30..fed6d815c9f2 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1029,6 +1029,12 @@ public abstract class Context {
*
* <p>See {@link BroadcastReceiver} for more information on Intent broadcasts.
*
+ * <p>As of {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH}, receivers
+ * registered with this method will correctly respect the
+ * {@link Intent#setPackage(String)} specified for an Intent being broadcast.
+ * Prior to that, it would be ignored and delivered to all matching registered
+ * receivers. Be careful if using this for security.</p>
+ *
* <p class="note">Note: this method <em>cannot be called from a
* {@link BroadcastReceiver} component;</em> that is, from a BroadcastReceiver
* that is declared in an application's manifest. It is okay, however, to call
@@ -1059,6 +1065,12 @@ public abstract class Context {
*
* <p>See {@link BroadcastReceiver} for more information on Intent broadcasts.
*
+ * <p>As of {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH}, receivers
+ * registered with this method will correctly respect the
+ * {@link Intent#setPackage(String)} specified for an Intent being broadcast.
+ * Prior to that, it would be ignored and delivered to all matching registered
+ * receivers. Be careful if using this for security.</p>
+ *
* @param receiver The BroadcastReceiver to handle the broadcast.
* @param filter Selects the Intent broadcasts to be received.
* @param broadcastPermission String naming a permissions that a
diff --git a/core/java/android/content/IIntentSender.aidl b/core/java/android/content/IIntentSender.aidl
index b7da47219ce4..7dbd6f2ab92d 100644
--- a/core/java/android/content/IIntentSender.aidl
+++ b/core/java/android/content/IIntentSender.aidl
@@ -22,5 +22,5 @@ import android.content.Intent;
/** @hide */
interface IIntentSender {
int send(int code, in Intent intent, String resolvedType,
- IIntentReceiver finishedReceiver);
+ IIntentReceiver finishedReceiver, String requiredPermission);
}
diff --git a/core/java/android/content/IntentSender.java b/core/java/android/content/IntentSender.java
index 007a71515214..4db4bdca3657 100644
--- a/core/java/android/content/IntentSender.java
+++ b/core/java/android/content/IntentSender.java
@@ -154,14 +154,47 @@ public class IntentSender implements Parcelable {
*/
public void sendIntent(Context context, int code, Intent intent,
OnFinished onFinished, Handler handler) throws SendIntentException {
+ sendIntent(context, code, intent, onFinished, handler, null);
+ }
+
+ /**
+ * Perform the operation associated with this IntentSender, allowing the
+ * caller to specify information about the Intent to use and be notified
+ * when the send has completed.
+ *
+ * @param context The Context of the caller. This may be null if
+ * <var>intent</var> is also null.
+ * @param code Result code to supply back to the IntentSender's target.
+ * @param intent Additional Intent data. See {@link Intent#fillIn
+ * Intent.fillIn()} for information on how this is applied to the
+ * original Intent. Use null to not modify the original Intent.
+ * @param onFinished The object to call back on when the send has
+ * completed, or null for no callback.
+ * @param handler Handler identifying the thread on which the callback
+ * should happen. If null, the callback will happen from the thread
+ * pool of the process.
+ * @param requiredPermission Name of permission that a recipient of the PendingIntent
+ * is required to hold. This is only valid for broadcast intents, and
+ * corresponds to the permission argument in
+ * {@link Context#sendBroadcast(Intent, String) Context.sendOrderedBroadcast(Intent, String)}.
+ * If null, no permission is required.
+ *
+ *
+ * @throws SendIntentException Throws CanceledIntentException if the IntentSender
+ * is no longer allowing more intents to be sent through it.
+ */
+ public void sendIntent(Context context, int code, Intent intent,
+ OnFinished onFinished, Handler handler, String requiredPermission)
+ throws SendIntentException {
try {
String resolvedType = intent != null ?
intent.resolveTypeIfNeeded(context.getContentResolver())
: null;
int res = mTarget.send(code, intent, resolvedType,
onFinished != null
- ? new FinishedDispatcher(this, onFinished, handler)
- : null);
+ ? new FinishedDispatcher(this, onFinished, handler)
+ : null,
+ requiredPermission);
if (res < 0) {
throw new SendIntentException();
}
diff --git a/core/java/android/content/pm/PackageStats.java b/core/java/android/content/pm/PackageStats.java
index 11068e5d164e..1205da7cdcc6 100755
--- a/core/java/android/content/pm/PackageStats.java
+++ b/core/java/android/content/pm/PackageStats.java
@@ -40,6 +40,12 @@ public class PackageStats implements Parcelable {
public long cacheSize;
/**
+ * Size of the secure container on external storage holding the
+ * application's code.
+ */
+ public long externalCodeSize;
+
+ /**
* Size of the external data used by the application (e.g.,
* <sdcard>/Android/data/<app>)
*/
@@ -80,6 +86,8 @@ public class PackageStats implements Parcelable {
sb.append(dataSize);
sb.append(",cacheSize=");
sb.append(cacheSize);
+ sb.append(",externalCodeSize=");
+ sb.append(externalCodeSize);
sb.append(",externalDataSize=");
sb.append(externalDataSize);
sb.append(",externalCacheSize=");
@@ -100,6 +108,7 @@ public class PackageStats implements Parcelable {
codeSize = source.readLong();
dataSize = source.readLong();
cacheSize = source.readLong();
+ externalCodeSize = source.readLong();
externalDataSize = source.readLong();
externalCacheSize = source.readLong();
externalMediaSize = source.readLong();
@@ -111,6 +120,7 @@ public class PackageStats implements Parcelable {
codeSize = pStats.codeSize;
dataSize = pStats.dataSize;
cacheSize = pStats.cacheSize;
+ externalCodeSize = pStats.externalCodeSize;
externalDataSize = pStats.externalDataSize;
externalCacheSize = pStats.externalCacheSize;
externalMediaSize = pStats.externalMediaSize;
@@ -126,6 +136,7 @@ public class PackageStats implements Parcelable {
dest.writeLong(codeSize);
dest.writeLong(dataSize);
dest.writeLong(cacheSize);
+ dest.writeLong(externalCodeSize);
dest.writeLong(externalDataSize);
dest.writeLong(externalCacheSize);
dest.writeLong(externalMediaSize);
diff --git a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
index df8cf9a8164f..e10f2184508b 100644
--- a/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
+++ b/core/java/android/inputmethodservice/IInputMethodSessionWrapper.java
@@ -47,6 +47,7 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
private static final int DO_APP_PRIVATE_COMMAND = 100;
private static final int DO_TOGGLE_SOFT_INPUT = 105;
private static final int DO_FINISH_SESSION = 110;
+ private static final int DO_VIEW_CLICKED = 115;
HandlerCaller mCaller;
InputMethodSession mInputMethodSession;
@@ -133,6 +134,10 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
mInputMethodSession = null;
return;
}
+ case DO_VIEW_CLICKED: {
+ mInputMethodSession.viewClicked(msg.arg1 == 1);
+ return;
+ }
}
Log.w(TAG, "Unhandled message code: " + msg.what);
}
@@ -167,7 +172,11 @@ class IInputMethodSessionWrapper extends IInputMethodSession.Stub
oldSelStart, oldSelEnd, newSelStart, newSelEnd,
candidatesStart, candidatesEnd));
}
-
+
+ public void viewClicked(boolean focusChanged) {
+ mCaller.executeOrSendMessage(mCaller.obtainMessageI(DO_VIEW_CLICKED, focusChanged ? 1 : 0));
+ }
+
public void updateCursor(Rect newCursor) {
mCaller.executeOrSendMessage(mCaller.obtainMessageO(DO_UPDATE_CURSOR,
newCursor));
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index feb246ed7125..9481a880fb08 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -488,7 +488,15 @@ public class InputMethodService extends AbstractInputMethodService {
InputMethodService.this.onUpdateSelection(oldSelStart, oldSelEnd,
newSelStart, newSelEnd, candidatesStart, candidatesEnd);
}
-
+
+ @Override
+ public void viewClicked(boolean focusChanged) {
+ if (!isEnabled()) {
+ return;
+ }
+ InputMethodService.this.onViewClicked(focusChanged);
+ }
+
/**
* Call {@link InputMethodService#onUpdateCursor
* InputMethodService.onUpdateCursor()}.
@@ -1609,6 +1617,16 @@ public class InputMethodService extends AbstractInputMethodService {
}
/**
+ * Called when the user tapped or clicked a text view.
+ * IMEs can't rely on this method being called because this was not part of the original IME
+ * protocol, so applications with custom text editing written before this method appeared will
+ * not call to inform the IME of this interaction.
+ * @param focusChanged true if the user changed the focused view by this click.
+ */
+ public void onViewClicked(boolean focusChanged) {
+ }
+
+ /**
* Called when the application has reported a new location of its text
* cursor. This is only called if explicitly requested by the input method.
* The default implementation does nothing.
diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl
index ae9aa05e0bce..054825024b9a 100644
--- a/core/java/android/net/INetworkStatsService.aidl
+++ b/core/java/android/net/INetworkStatsService.aidl
@@ -33,4 +33,7 @@ interface INetworkStatsService {
/** Return usage summary per UID for traffic that matches template. */
NetworkStats getSummaryForAllUid(in NetworkTemplate template, long start, long end, boolean includeTags);
+ /** Force update of statistics. */
+ void forceUpdate();
+
}
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 21fad2c1d91e..593b2b74e301 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -49,6 +49,8 @@ public class NetworkPolicyManager {
/** Reject traffic on metered networks. */
public static final int RULE_REJECT_METERED = 0x1;
+ private static final boolean ALLOW_PLATFORM_APP_POLICY = true;
+
/**
* {@link Intent} action launched when user selects {@link NetworkPolicy}
* warning notification.
@@ -223,25 +225,27 @@ public class NetworkPolicyManager {
return false;
}
- final PackageManager pm = context.getPackageManager();
- final HashSet<Signature> systemSignature;
- try {
- systemSignature = Sets.newHashSet(
- pm.getPackageInfo("android", GET_SIGNATURES).signatures);
- } catch (NameNotFoundException e) {
- throw new RuntimeException("problem finding system signature", e);
- }
+ if (!ALLOW_PLATFORM_APP_POLICY) {
+ final PackageManager pm = context.getPackageManager();
+ final HashSet<Signature> systemSignature;
+ try {
+ systemSignature = Sets.newHashSet(
+ pm.getPackageInfo("android", GET_SIGNATURES).signatures);
+ } catch (NameNotFoundException e) {
+ throw new RuntimeException("problem finding system signature", e);
+ }
- try {
- // reject apps signed with system cert
- for (String packageName : pm.getPackagesForUid(uid)) {
- final HashSet<Signature> packageSignature = Sets.newHashSet(
- pm.getPackageInfo(packageName, GET_SIGNATURES).signatures);
- if (packageSignature.containsAll(systemSignature)) {
- return false;
+ try {
+ // reject apps signed with platform cert
+ for (String packageName : pm.getPackagesForUid(uid)) {
+ final HashSet<Signature> packageSignature = Sets.newHashSet(
+ pm.getPackageInfo(packageName, GET_SIGNATURES).signatures);
+ if (packageSignature.containsAll(systemSignature)) {
+ return false;
+ }
}
+ } catch (NameNotFoundException e) {
}
- } catch (NameNotFoundException e) {
}
// nothing found above; we can apply policy to UID
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index ff6e220cac41..dd2945ca18af 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -279,10 +279,17 @@ public class NetworkStatsHistory implements Parcelable {
return (long) (start + (r.nextFloat() * (end - start)));
}
- public void dump(String prefix, PrintWriter pw) {
+ public void dump(String prefix, PrintWriter pw, boolean fullHistory) {
pw.print(prefix);
pw.print("NetworkStatsHistory: bucketDuration="); pw.println(bucketDuration);
- for (int i = 0; i < bucketCount; i++) {
+
+ final int start = fullHistory ? 0 : Math.max(0, bucketCount - 32);
+ if (start > 0) {
+ pw.print(prefix);
+ pw.print(" (omitting "); pw.print(start); pw.println(" buckets)");
+ }
+
+ for (int i = start; i < bucketCount; i++) {
pw.print(prefix);
pw.print(" bucketStart="); pw.print(bucketStart[i]);
pw.print(" rx="); pw.print(rx[i]);
@@ -293,7 +300,7 @@ public class NetworkStatsHistory implements Parcelable {
@Override
public String toString() {
final CharArrayWriter writer = new CharArrayWriter();
- dump("", new PrintWriter(writer));
+ dump("", new PrintWriter(writer), false);
return writer.toString();
}
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index 040489e664f4..2b59dba15c0e 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -25,8 +25,9 @@ import android.os.INetworkManagementService;
import android.os.RemoteException;
import android.os.ServiceManager;
-import dalvik.system.BlockGuard;
+import com.android.server.NetworkManagementSocketTagger;
+import dalvik.system.SocketTagger;
import java.net.Socket;
import java.net.SocketException;
@@ -92,7 +93,7 @@ public class TrafficStats {
* {@link #tagSocket(Socket)}.
*/
public static void setThreadStatsTag(int tag) {
- BlockGuard.setThreadSocketStatsTag(tag);
+ NetworkManagementSocketTagger.setThreadSocketStatsTag(tag);
}
/**
@@ -104,7 +105,7 @@ public class TrafficStats {
}
public static void clearThreadStatsTag() {
- BlockGuard.setThreadSocketStatsTag(-1);
+ NetworkManagementSocketTagger.setThreadSocketStatsTag(-1);
}
/**
@@ -121,12 +122,12 @@ public class TrafficStats {
* {@hide}
*/
public static void setThreadStatsUid(int uid) {
- BlockGuard.setThreadSocketStatsUid(uid);
+ NetworkManagementSocketTagger.setThreadSocketStatsUid(uid);
}
/** {@hide} */
public static void clearThreadStatsUid() {
- BlockGuard.setThreadSocketStatsUid(-1);
+ NetworkManagementSocketTagger.setThreadSocketStatsUid(-1);
}
/**
@@ -139,14 +140,14 @@ public class TrafficStats {
* @see #setThreadStatsUid(int)
*/
public static void tagSocket(Socket socket) throws SocketException {
- BlockGuard.tagSocketFd(socket.getFileDescriptor$());
+ SocketTagger.get().tag(socket);
}
/**
* Remove any statistics parameters from the given {@link Socket}.
*/
public static void untagSocket(Socket socket) throws SocketException {
- BlockGuard.untagSocketFd(socket.getFileDescriptor$());
+ SocketTagger.get().untag(socket);
}
/**
diff --git a/core/java/android/nfc/NdefRecord.java b/core/java/android/nfc/NdefRecord.java
index 5ade9eb9fbc5..0eb8cd81bcdd 100644
--- a/core/java/android/nfc/NdefRecord.java
+++ b/core/java/android/nfc/NdefRecord.java
@@ -338,7 +338,15 @@ public final class NdefRecord implements Parcelable {
* @hide
*/
public static NdefRecord createUri(Uri uri) {
- String uriString = uri.toString();
+ return createUri(uri.toString());
+ }
+
+ /**
+ * Creates an NDEF record of well known type URI.
+ * TODO: Make a public API
+ * @hide
+ */
+ public static NdefRecord createUri(String uriString) {
byte prefix = 0x0;
for (int i = 1; i < URI_PREFIX_MAP.length; i++) {
if (uriString.startsWith(URI_PREFIX_MAP[i])) {
diff --git a/core/java/android/nfc/Tag.java b/core/java/android/nfc/Tag.java
index 54583d61f4f9..a73067a5f709 100644
--- a/core/java/android/nfc/Tag.java
+++ b/core/java/android/nfc/Tag.java
@@ -313,14 +313,16 @@ public final class Tag implements Parcelable {
*/
@Override
public String toString() {
- StringBuilder sb = new StringBuilder("TAG ")
- .append("uid = ")
- .append(mId)
- .append(" Tech [");
- for (int i : mTechList) {
- sb.append(i)
- .append(", ");
+ StringBuilder sb = new StringBuilder("TAG: Tech [");
+ String[] techList = getTechList();
+ int length = techList.length;
+ for (int i = 0; i < length; i++) {
+ sb.append(techList[i]);
+ if (i < length - 1) {
+ sb.append(", ");
+ }
}
+ sb.append("]");
return sb.toString();
}
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 1b09242d4c03..fcf479631b03 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -210,6 +210,21 @@ interface INetworkManagementService
NetworkStats getNetworkStatsUidDetail(int uid);
/**
+ * Set quota for an interface.
+ */
+ void setInterfaceQuota(String iface, long quota);
+
+ /**
+ * Remove quota for an interface.
+ */
+ void removeInterfaceQuota(String iface);
+
+ /**
+ * Control network activity of a UID over interfaces with a quota limit.
+ */
+ void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces);
+
+ /**
* Configures bandwidth throttling on an interface.
*/
void setInterfaceThrottle(String iface, int rxKbps, int txKbps);
@@ -226,6 +241,4 @@ interface INetworkManagementService
*/
int getInterfaceTxThrottle(String iface);
- void setBandwidthControlEnabled(boolean enabled);
-
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index d475f36df9bb..05e39ac55a89 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -92,12 +92,6 @@ public class Process {
public static final int SDCARD_RW_GID = 1015;
/**
- * Defines the UID for the KeyChain service.
- * @hide
- */
- public static final int KEYCHAIN_UID = 1020;
-
- /**
* Defines the UID/GID for the NFC service process.
* @hide
*/
diff --git a/core/java/android/os/storage/IMountService.java b/core/java/android/os/storage/IMountService.java
index c2dc8aeefc43..93020601b29c 100644
--- a/core/java/android/os/storage/IMountService.java
+++ b/core/java/android/os/storage/IMountService.java
@@ -655,6 +655,26 @@ public interface IMountService extends IInterface {
}
return _result;
}
+
+ /*
+ * Returns the filesystem path of a mounted secure container.
+ */
+ public String getSecureContainerFilesystemPath(String id) throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ String _result;
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ _data.writeString(id);
+ mRemote.transact(Stub.TRANSACTION_getSecureContainerFilesystemPath, _data, _reply, 0);
+ _reply.readException();
+ _result = _reply.readString();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ return _result;
+ }
}
private static final String DESCRIPTOR = "IMountService";
@@ -719,6 +739,8 @@ public interface IMountService extends IInterface {
static final int TRANSACTION_getVolumeList = IBinder.FIRST_CALL_TRANSACTION + 29;
+ static final int TRANSACTION_getSecureContainerFilesystemPath = IBinder.FIRST_CALL_TRANSACTION + 30;
+
/**
* Cast an IBinder object into an IMountService interface, generating a
* proxy if needed.
@@ -1031,6 +1053,15 @@ public interface IMountService extends IInterface {
reply.writeParcelableArray(result, 0);
return true;
}
+ case TRANSACTION_getSecureContainerFilesystemPath: {
+ data.enforceInterface(DESCRIPTOR);
+ String id;
+ id = data.readString();
+ String path = getSecureContainerFilesystemPath(id);
+ reply.writeNoException();
+ reply.writeString(path);
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
}
@@ -1210,4 +1241,6 @@ public interface IMountService extends IInterface {
* Returns list of all mountable volumes.
*/
public Parcelable[] getVolumeList() throws RemoteException;
+
+ public String getSecureContainerFilesystemPath(String id) throws RemoteException;
}
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index 3971045f3451..b492615a50c2 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -17,9 +17,6 @@
package android.provider;
-import com.android.internal.util.ArrayUtils;
-
-import android.accounts.Account;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.ContentProviderClient;
@@ -35,13 +32,10 @@ import android.database.Cursor;
import android.database.DatabaseUtils;
import android.net.Uri;
import android.os.RemoteException;
-import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.format.Time;
import android.util.Log;
-import java.util.Arrays;
-
/**
* <p>
* The contract between the calendar provider and applications. Contains
@@ -97,6 +91,8 @@ public final class CalendarContract {
/**
* Broadcast Action: This is the intent that gets fired when an alarm
* notification needs to be posted for a reminder.
+ *
+ * @SdkConstant
*/
public static final String ACTION_EVENT_REMINDER = "android.intent.action.EVENT_REMINDER";
@@ -122,8 +118,7 @@ public final class CalendarContract {
/**
* The content:// style URL for the top-level calendar authority
*/
- public static final Uri CONTENT_URI =
- Uri.parse("content://" + AUTHORITY);
+ public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY);
/**
* An optional insert, update or delete URI parameter that allows the caller
@@ -572,29 +567,6 @@ public final class CalendarContract {
* </ul>
*/
public static class Calendars implements BaseColumns, SyncColumns, CalendarColumns {
- private static final String WHERE_DELETE_FOR_ACCOUNT = Calendars.ACCOUNT_NAME + "=?"
- + " AND "
- + Calendars.ACCOUNT_TYPE + "=?";
-
- /**
- * Helper function for generating a calendars query. This is blocking
- * and should not be used on the UI thread. See
- * {@link ContentResolver#query(Uri, String[], String, String[], String)}
- * for more details about using the parameters.
- *
- * @param cr The ContentResolver to query with
- * @param projection A list of columns to return
- * @param selection A formatted selection string
- * @param selectionArgs arguments to the selection string
- * @param orderBy How to order the returned rows
- * @return
- */
- public static final Cursor query(ContentResolver cr, String[] projection, String selection,
- String[] selectionArgs, String orderBy) {
- return cr.query(CONTENT_URI, projection, selection, selectionArgs,
- orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
- }
-
/**
* The content:// style URL for accessing Calendars
*/
@@ -622,7 +594,9 @@ public final class CalendarContract {
* These fields are only writable by a sync adapter. To modify them the
* caller must include {@link #CALLER_IS_SYNCADAPTER},
* {@link #ACCOUNT_NAME}, and {@link #ACCOUNT_TYPE} in the Uri's query
- * parameters.
+ * parameters. TODO move to provider
+ *
+ * @hide
*/
public static final String[] SYNC_WRITABLE_COLUMNS = new String[] {
ACCOUNT_NAME,
@@ -737,7 +711,7 @@ public final class CalendarContract {
/**
* the projection used by the attendees query
*/
- private static final String[] PROJECTION = new String[] {
+ public static final String[] PROJECTION = new String[] {
_ID, ATTENDEE_NAME, ATTENDEE_EMAIL, ATTENDEE_RELATIONSHIP, ATTENDEE_STATUS,};
private static final String ATTENDEES_WHERE = Attendees.EVENT_ID + "=?";
@@ -1420,37 +1394,6 @@ public final class CalendarContract {
CalendarColumns {
/**
- * Queries all events with the given projection. This is a blocking call
- * and should not be done on the UI thread.
- *
- * @param cr The content resolver to use for the query
- * @param projection The columns to return
- * @return A Cursor containing all events in the db
- */
- public static final Cursor query(ContentResolver cr, String[] projection) {
- return cr.query(CONTENT_URI, projection, null, null, DEFAULT_SORT_ORDER);
- }
-
- /**
- * Queries events using the given projection, selection filter, and
- * ordering. This is a blocking call and should not be done on the UI
- * thread. For selection and selectionArgs usage see
- * {@link ContentResolver#query(Uri, String[], String, String[], String)}
- *
- * @param cr The content resolver to use for the query
- * @param projection The columns to return
- * @param selection Filter on the query as an SQL WHERE statement
- * @param selectionArgs Args to replace any '?'s in the selection
- * @param orderBy How to order the rows as an SQL ORDER BY statement
- * @return A Cursor containing the matching events
- */
- public static final Cursor query(ContentResolver cr, String[] projection, String selection,
- String[] selectionArgs, String orderBy) {
- return cr.query(CONTENT_URI, projection, selection, null,
- orderBy == null ? DEFAULT_SORT_ORDER : orderBy);
- }
-
- /**
* The content:// style URL for interacting with events. Appending an
* event id using {@link ContentUris#withAppendedId(Uri, long)} will
* specify a single event.
@@ -1464,7 +1407,7 @@ public final class CalendarContract {
* appended event ID. Deletion of exceptions requires both the original event ID and
* the exception event ID (see {@link Uri.Builder#appendPath}).
*/
- public static final Uri EXCEPTION_CONTENT_URI =
+ public static final Uri CONTENT_EXCEPTION_URI =
Uri.parse("content://" + AUTHORITY + "/exception");
/**
@@ -1475,7 +1418,9 @@ public final class CalendarContract {
/**
* These are columns that should only ever be updated by the provider,
* either because they are views mapped to another table or because they
- * are used for provider only functionality.
+ * are used for provider only functionality. TODO move to provider
+ *
+ * @hide
*/
public static String[] PROVIDER_WRITABLE_COLUMNS = new String[] {
ACCOUNT_NAME,
@@ -1505,7 +1450,9 @@ public final class CalendarContract {
/**
* These fields are only writable by a sync adapter. To modify them the
* caller must include CALLER_IS_SYNCADAPTER, _SYNC_ACCOUNT, and
- * _SYNC_ACCOUNT_TYPE in the query parameters.
+ * _SYNC_ACCOUNT_TYPE in the query parameters. TODO move to provider.
+ *
+ * @hide
*/
public static final String[] SYNC_WRITABLE_COLUMNS = new String[] {
_SYNC_ID,
@@ -1672,11 +1619,6 @@ public final class CalendarContract {
public static final String END_MINUTE = "endMinute";
}
- /**
- * CalendarCache stores some settings for calendar including the current
- * time zone for the instaces. These settings are stored using a key/value
- * scheme.
- */
protected interface CalendarCacheColumns {
/**
* The key for the setting. Keys are defined in {@link CalendarCache}.
@@ -1689,6 +1631,11 @@ public final class CalendarContract {
public static final String VALUE = "value";
}
+ /**
+ * CalendarCache stores some settings for calendar including the current
+ * time zone for the instances. These settings are stored using a key/value
+ * scheme. A {@link #KEY} must be specified when updating these values.
+ */
public static class CalendarCache implements CalendarCacheColumns {
/**
* The URI to use for retrieving the properties from the Calendar db.
@@ -1697,22 +1644,11 @@ public final class CalendarContract {
Uri.parse("content://" + AUTHORITY + "/properties");
/**
- * If updating a property, this must be provided as the selection. All
- * other selections will fail. For queries this field can be omitted to
- * retrieve all properties or used to query a single property. Valid
- * keys include {@link #TIMEZONE_KEY_TYPE},
- * {@link #TIMEZONE_KEY_INSTANCES}, and
- * {@link #TIMEZONE_KEY_INSTANCES_PREVIOUS}, though the last one can
- * only be read, not written.
- */
- public static final String WHERE = "key=?";
-
- /**
* They key for updating the use of auto/home time zones in Calendar.
* Valid values are {@link #TIMEZONE_TYPE_AUTO} or
* {@link #TIMEZONE_TYPE_HOME}.
*/
- public static final String TIMEZONE_KEY_TYPE = "timezoneType";
+ public static final String KEY_TIMEZONE_TYPE = "timezoneType";
/**
* The key for updating the time zone used by the provider when it
@@ -1720,24 +1656,24 @@ public final class CalendarContract {
* type is set to {@link #TIMEZONE_TYPE_HOME}. A valid time zone id
* should be written to this field.
*/
- public static final String TIMEZONE_KEY_INSTANCES = "timezoneInstances";
+ public static final String KEY_TIMEZONE_INSTANCES = "timezoneInstances";
/**
* The key for reading the last time zone set by the user. This should
* only be read by apps and it will be automatically updated whenever
- * {@link #TIMEZONE_KEY_INSTANCES} is updated with
+ * {@link #KEY_TIMEZONE_INSTANCES} is updated with
* {@link #TIMEZONE_TYPE_HOME} set.
*/
- public static final String TIMEZONE_KEY_INSTANCES_PREVIOUS = "timezoneInstancesPrevious";
+ public static final String KEY_TIMEZONE_INSTANCES_PREVIOUS = "timezoneInstancesPrevious";
/**
- * The value to write to {@link #TIMEZONE_KEY_TYPE} if the provider
+ * The value to write to {@link #KEY_TIMEZONE_TYPE} if the provider
* should stay in sync with the device's time zone.
*/
public static final String TIMEZONE_TYPE_AUTO = "auto";
/**
- * The value to write to {@link #TIMEZONE_KEY_TYPE} if the provider
+ * The value to write to {@link #KEY_TIMEZONE_TYPE} if the provider
* should use a fixed time zone set by the user.
*/
public static final String TIMEZONE_TYPE_HOME = "home";
@@ -1814,7 +1750,7 @@ public final class CalendarContract {
/**
* The projection used by the EventDays query.
*/
- private static final String[] PROJECTION = {
+ public static final String[] PROJECTION = {
STARTDAY, ENDDAY
};
private static final String SELECTION = "selected=1";
@@ -1900,7 +1836,7 @@ public final class CalendarContract {
/**
* The projection used by the reminders query.
*/
- private static final String[] PROJECTION = new String[] {
+ public static final String[] PROJECTION = new String[] {
_ID, MINUTES, METHOD,};
@SuppressWarnings("hiding")
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/reminders");
@@ -1967,17 +1903,28 @@ public final class CalendarContract {
public static final String NOTIFY_TIME = "notifyTime";
/**
- * The state of this alert. It starts out as {@link #SCHEDULED}, then
- * when the alarm goes off, it changes to {@link #FIRED}, and then when
- * the user dismisses the alarm it changes to {@link #DISMISSED}. Column
+ * The state of this alert. It starts out as {@link #STATE_SCHEDULED}, then
+ * when the alarm goes off, it changes to {@link #STATE_FIRED}, and then when
+ * the user dismisses the alarm it changes to {@link #STATE_DISMISSED}. Column
* name.
* <P>Type: INTEGER</P>
*/
public static final String STATE = "state";
- public static final int SCHEDULED = 0;
- public static final int FIRED = 1;
- public static final int DISMISSED = 2;
+ /**
+ * An alert begins in this state when it is first created.
+ */
+ public static final int STATE_SCHEDULED = 0;
+ /**
+ * After a notification for an alert has been created it should be
+ * updated to fired.
+ */
+ public static final int STATE_FIRED = 1;
+ /**
+ * Once the user has dismissed the notification the alert's state should
+ * be set to dismissed so it is not fired again.
+ */
+ public static final int STATE_DISMISSED = 2;
/**
* The number of minutes that this alarm precedes the start time. Column
@@ -2024,7 +1971,7 @@ public final class CalendarContract {
private static final String WHERE_FINDNEXTALARMTIME = ALARM_TIME + ">=?";
private static final String SORT_ORDER_ALARMTIME_ASC = ALARM_TIME + " ASC";
- private static final String WHERE_RESCHEDULE_MISSED_ALARMS = STATE + "=" + SCHEDULED
+ private static final String WHERE_RESCHEDULE_MISSED_ALARMS = STATE + "=" + STATE_SCHEDULED
+ " AND " + ALARM_TIME + "<?"
+ " AND " + ALARM_TIME + ">?"
+ " AND " + END + ">=?";
@@ -2038,10 +1985,11 @@ public final class CalendarContract {
public static final Uri CONTENT_URI_BY_INSTANCE =
Uri.parse("content://" + AUTHORITY + "/calendar_alerts/by_instance");
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
/**
- * Helper for inserting an alarm time associated with an event
+ * Helper for inserting an alarm time associated with an event TODO move
+ * to Provider
*
* @hide
*/
@@ -2056,51 +2004,32 @@ public final class CalendarContract {
values.put(CalendarAlerts.CREATION_TIME, currentTime);
values.put(CalendarAlerts.RECEIVED_TIME, 0);
values.put(CalendarAlerts.NOTIFY_TIME, 0);
- values.put(CalendarAlerts.STATE, SCHEDULED);
+ values.put(CalendarAlerts.STATE, STATE_SCHEDULED);
values.put(CalendarAlerts.MINUTES, minutes);
return cr.insert(CONTENT_URI, values);
}
/**
- * Queries alerts info using the given projection, selection filter, and
- * ordering. This is a blocking call and should not be done on the UI
- * thread. For selection and selectionArgs usage see
- * {@link ContentResolver#query(Uri, String[], String, String[], String)}
- *
- * @param cr The content resolver to use for the query
- * @param projection The columns to return
- * @param selection Filter on the query as an SQL WHERE statement
- * @param selectionArgs Args to replace any '?'s in the selection
- * @param sortOrder How to order the rows as an SQL ORDER BY statement
- * @return A Cursor containing the matching alerts
- */
- public static final Cursor query(ContentResolver cr, String[] projection,
- String selection, String[] selectionArgs, String sortOrder) {
- return cr.query(CONTENT_URI, projection, selection, selectionArgs,
- sortOrder);
- }
-
- /**
* Finds the next alarm after (or equal to) the given time and returns
* the time of that alarm or -1 if no such alarm exists. This is a
- * blocking call and should not be done on the UI thread.
+ * blocking call and should not be done on the UI thread. TODO move to
+ * provider
*
* @param cr the ContentResolver
* @param millis the time in UTC milliseconds
* @return the next alarm time greater than or equal to "millis", or -1
* if no such alarm exists.
+ * @hide
*/
public static final long findNextAlarmTime(ContentResolver cr, long millis) {
String selection = ALARM_TIME + ">=" + millis;
// TODO: construct an explicit SQL query so that we can add
// "LIMIT 1" to the end and get just one result.
String[] projection = new String[] { ALARM_TIME };
- Cursor cursor = query(cr, projection,
- WHERE_FINDNEXTALARMTIME,
- new String[] {
+ Cursor cursor = cr.query(CONTENT_URI, projection, WHERE_FINDNEXTALARMTIME,
+ (new String[] {
Long.toString(millis)
- },
- SORT_ORDER_ALARMTIME_ASC);
+ }), SORT_ORDER_ALARMTIME_ASC);
long alarmTime = -1;
try {
if (cursor != null && cursor.moveToFirst()) {
@@ -2116,13 +2045,14 @@ public final class CalendarContract {
/**
* Searches the CalendarAlerts table for alarms that should have fired
- * but have not and then reschedules them. This method can be called
- * at boot time to restore alarms that may have been lost due to a
- * phone reboot.
+ * but have not and then reschedules them. This method can be called at
+ * boot time to restore alarms that may have been lost due to a phone
+ * reboot. TODO move to provider
*
* @param cr the ContentResolver
* @param context the Context
* @param manager the AlarmManager
+ * @hide
*/
public static final void rescheduleMissedAlarms(ContentResolver cr,
Context context, AlarmManager manager) {
@@ -2136,15 +2066,10 @@ public final class CalendarContract {
// TODO: construct an explicit SQL query so that we can add
// "GROUPBY" instead of doing a sort and de-dup
- Cursor cursor = CalendarAlerts.query(cr,
- projection,
- WHERE_RESCHEDULE_MISSED_ALARMS,
- new String[] {
- Long.toString(now),
- Long.toString(ancient),
- Long.toString(now)
- },
- SORT_ORDER_ALARMTIME_ASC);
+ Cursor cursor = cr.query(CalendarAlerts.CONTENT_URI, projection,
+ WHERE_RESCHEDULE_MISSED_ALARMS, (new String[] {
+ Long.toString(now), Long.toString(ancient), Long.toString(now)
+ }), SORT_ORDER_ALARMTIME_ASC);
if (cursor == null) {
return;
}
@@ -2177,12 +2102,13 @@ public final class CalendarContract {
* keep scheduled reminders up to date but apps may use this to
* implement snooze functionality without modifying the reminders table.
* Scheduled alarms will generate an intent using
- * {@link #ACTION_EVENT_REMINDER}.
+ * {@link #ACTION_EVENT_REMINDER}. TODO Move to provider
*
* @param context A context for referencing system resources
* @param manager The AlarmManager to use or null
* @param alarmTime The time to fire the intent in UTC millis since
* epoch
+ * @hide
*/
public static void scheduleAlarm(Context context, AlarmManager manager, long alarmTime) {
if (DEBUG) {
@@ -2204,31 +2130,28 @@ public final class CalendarContract {
}
/**
- * Searches for an entry in the CalendarAlerts table that matches
- * the given event id, begin time and alarm time. If one is found
- * then this alarm already exists and this method returns true.
- *
+ * Searches for an entry in the CalendarAlerts table that matches the
+ * given event id, begin time and alarm time. If one is found then this
+ * alarm already exists and this method returns true. TODO Move to
+ * provider
+ *
* @param cr the ContentResolver
* @param eventId the event id to match
* @param begin the start time of the event in UTC millis
* @param alarmTime the alarm time of the event in UTC millis
- * @return true if there is already an alarm for the given event
- * with the same start time and alarm time.
+ * @return true if there is already an alarm for the given event with
+ * the same start time and alarm time.
+ * @hide
*/
public static final boolean alarmExists(ContentResolver cr, long eventId,
long begin, long alarmTime) {
// TODO: construct an explicit SQL query so that we can add
// "LIMIT 1" to the end and get just one result.
String[] projection = new String[] { ALARM_TIME };
- Cursor cursor = query(cr,
- projection,
- WHERE_ALARM_EXISTS,
- new String[] {
- Long.toString(eventId),
- Long.toString(begin),
- Long.toString(alarmTime)
- },
- null);
+ Cursor cursor = cr.query(CONTENT_URI, projection, WHERE_ALARM_EXISTS,
+ (new String[] {
+ Long.toString(eventId), Long.toString(begin), Long.toString(alarmTime)
+ }), null);
boolean found = false;
try {
if (cursor != null && cursor.getCount() > 0) {
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 09331939f616..39c6f576b5d7 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -57,6 +57,29 @@ public class CallLog {
Uri.parse("content://call_log/calls/filter");
/**
+ * An optional URI parameter which instructs the provider to allow the operation to be
+ * applied to voicemail records as well.
+ * <p>
+ * TYPE: Boolean
+ * <p>
+ * Using this parameter with a value of {@code true} will result in a security error if the
+ * calling package does not have appropriate permissions to access voicemails.
+ *
+ * @hide
+ */
+ public static final String ALLOW_VOICEMAILS_PARAM_KEY = "allow_voicemails";
+
+ /**
+ * Content uri with {@link #ALLOW_VOICEMAILS_PARAM_KEY} set. This can directly be used to
+ * access call log entries that includes voicemail records.
+ *
+ * @hide
+ */
+ public static final Uri CONTENT_URI_WITH_VOICEMAIL = CONTENT_URI.buildUpon()
+ .appendQueryParameter(ALLOW_VOICEMAILS_PARAM_KEY, "true")
+ .build();
+
+ /**
* The default sort order for this table
*/
public static final String DEFAULT_SORT_ORDER = "date DESC";
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index ab0cb505eb2d..d99c7605bebe 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -52,18 +52,27 @@ public class VoicemailContract {
/** The authority used by the voicemail provider. */
public static final String AUTHORITY = "com.android.voicemail";
-
- /** URI to insert/retrieve all voicemails. */
+ /**
+ * URI to insert/retrieve all voicemails.
+ * @deprecated
+ */
public static final Uri CONTENT_URI =
Uri.parse("content://" + AUTHORITY + "/voicemail");
- /** URI to insert/retrieve voicemails by a given voicemail source. */
+ /**
+ * URI to insert/retrieve voicemails by a given voicemail source.
+ * @deprecated
+ */
public static final Uri CONTENT_URI_SOURCE =
Uri.parse("content://" + AUTHORITY + "/voicemail/source/");
+ /**
+ * Parameter key used in the URI to specify the voicemail source package name.
+ * <p> This field must be set in all requests that originate from a voicemail source.
+ */
+ public static final String PARAM_KEY_SOURCE_PACKAGE = "source_package";
// TODO: Move ACTION_NEW_VOICEMAIL to the Intent class.
/** Broadcast intent when a new voicemail record is inserted. */
public static final String ACTION_NEW_VOICEMAIL = "android.intent.action.NEW_VOICEMAIL";
-
/**
* Extra included in {@value Intent#ACTION_PROVIDER_CHANGED} and
* {@value #ACTION_NEW_VOICEMAIL} broadcast intents to indicate if the receiving
@@ -71,15 +80,27 @@ public class VoicemailContract {
*/
public static final String EXTRA_SELF_CHANGE = "com.android.voicemail.extra.SELF_CHANGE";
- /** The mime type for a collection of voicemails. */
- public static final String DIR_TYPE =
- "vnd.android.cursor.dir/voicemails";
+ /**
+ * The mime type for a collection of voicemails.
+ * @deprecated */
+ public static final String DIR_TYPE = "vnd.android.cursor.dir/voicemails";
+ /** Defines fields exposed through the /voicemail path of this content provider. */
public static final class Voicemails implements BaseColumns {
/** Not instantiable. */
private Voicemails() {
}
+ /** URI to insert/retrieve voicemails by a given voicemail source. */
+ public static final Uri CONTENT_URI =
+ Uri.parse("content://" + AUTHORITY + "/voicemail");
+ /** URI to insert/retrieve voicemails by a given voicemail source. */
+ public static final Uri CONTENT_URI_SOURCE =
+ Uri.parse("content://" + AUTHORITY + "/voicemail/source/");
+
+ /** The mime type for a collection of voicemails. */
+ public static final String DIR_TYPE = "vnd.android.cursor.dir/voicemails";
+
/**
* Phone number of the voicemail sender.
* <P>Type: TEXT</P>
@@ -143,5 +164,101 @@ public class VoicemailContract {
* @hide
*/
public static final String _DATA = "_data";
+
+ /**
+ * A convenience method to build voicemail URI specific to a source package by appending
+ * {@link VoicemailContract#PARAM_KEY_SOURCE_PACKAGE} param to the base URI.
+ */
+ public static Uri buildSourceUri(String packageName) {
+ return Voicemails.CONTENT_URI.buildUpon()
+ .appendQueryParameter(PARAM_KEY_SOURCE_PACKAGE, packageName).build();
+ }
+ }
+
+ /** Defines fields exposed through the /status path of this content provider. */
+ public static final class Status implements BaseColumns {
+ /** URI to insert/retrieve status of voicemail source. */
+ public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/status");
+ /** The mime type for a collection of voicemail source statuses. */
+ public static final String DIR_TYPE = "vnd.android.cursor.dir/voicemail.source.status";
+ /** The mime type for a collection of voicemails. */
+ public static final String ITEM_TYPE = "vnd.android.cursor.item/voicemail.source.status";
+
+ /** Not instantiable. */
+ private Status() {
+ }
+ /**
+ * The package name of the voicemail source. There can only be a one entry per source.
+ * <P>Type: TEXT</P>
+ */
+ public static final String SOURCE_PACKAGE = "source_package";
+ /**
+ * The URI to call to invoke source specific voicemail settings screen. On a user request
+ * to setup voicemail an intent with action VIEW with this URI will be fired by the system.
+ * <P>Type: TEXT</P>
+ */
+ public static final String SETTINGS_URI = "settings_uri";
+ /**
+ * The URI to call when the user requests to directly access the voicemail from the remote
+ * server. In case of an IVR voicemail system this is typically set to the the voicemail
+ * number specified using a tel:/ URI.
+ * <P>Type: TEXT</P>
+ */
+ public static final String VOICEMAIL_ACCESS_URI = "voicemail_access_uri";
+ /**
+ * The configuration state of the voicemail source.
+ * <P> Possible values:
+ * {@link #CONFIGURATION_STATE_OK},
+ * {@link #CONFIGURATION_STATE_NOT_CONFIGURED},
+ * {@link #CONFIGURATION_STATE_CAN_BE_CONFIGURED}
+ * <P>Type: INTEGER</P>
+ */
+ public static final String CONFIGURATION_STATE = "configuration_state";
+ public static final int CONFIGURATION_STATE_OK = 0;
+ public static final int CONFIGURATION_STATE_NOT_CONFIGURED = 1;
+ /**
+ * This state must be used when the source has verified that the current user can be
+ * upgraded to visual voicemail and would like to show a set up invitation message.
+ */
+ public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2;
+ /**
+ * The data channel state of the voicemail source. This the channel through which the source
+ * pulls voicemail data from a remote server.
+ * <P> Possible values:
+ * {@link #DATA_CHANNEL_STATE_OK},
+ * {@link #DATA_CHANNEL_STATE_NO_CONNECTION}
+ * </P>
+ * <P>Type: INTEGER</P>
+ */
+ public static final String DATA_CHANNEL_STATE = "data_channel_state";
+ public static final int DATA_CHANNEL_STATE_OK = 0;
+ public static final int DATA_CHANNEL_STATE_NO_CONNECTION = 1;
+ /**
+ * The notification channel state of the voicemail source. This is the channel through which
+ * the source gets notified of new voicemails on the remote server.
+ * <P> Possible values:
+ * {@link #NOTIFICATION_CHANNEL_STATE_OK},
+ * {@link #NOTIFICATION_CHANNEL_STATE_NO_CONNECTION},
+ * {@link #NOTIFICATION_CHANNEL_STATE_MESSAGE_WAITING}
+ * </P>
+ * <P>Type: INTEGER</P>
+ */
+ public static final String NOTIFICATION_CHANNEL_STATE = "notification_channel_state";
+ public static final int NOTIFICATION_CHANNEL_STATE_OK = 0;
+ public static final int NOTIFICATION_CHANNEL_STATE_NO_CONNECTION = 1;
+ /**
+ * Use this state when the notification can only tell that there are pending messages on
+ * the server but no details of the sender/time etc are known.
+ */
+ public static final int NOTIFICATION_CHANNEL_STATE_MESSAGE_WAITING = 2;
+
+ /**
+ * A convenience method to build status URI specific to a source package by appending
+ * {@link VoicemailContract#PARAM_KEY_SOURCE_PACKAGE} param to the base URI.
+ */
+ public static Uri buildSourceUri(String packageName) {
+ return Status.CONTENT_URI.buildUpon()
+ .appendQueryParameter(PARAM_KEY_SOURCE_PACKAGE, packageName).build();
+ }
}
}
diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java
index ca2212cda581..8a6fdb4fb325 100644
--- a/core/java/android/server/BluetoothA2dpService.java
+++ b/core/java/android/server/BluetoothA2dpService.java
@@ -517,6 +517,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState);
intent.putExtra(BluetoothProfile.EXTRA_STATE, state);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
if (DBG) log("A2DP state : device: " + device + " State:" + prevState + "->" + state);
@@ -530,6 +531,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub {
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState);
intent.putExtra(BluetoothProfile.EXTRA_STATE, state);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
mContext.sendBroadcast(intent, BLUETOOTH_PERM);
if (DBG) log("A2DP Playing state : device: " + device + " State:" + prevState + "->" + state);
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index b5ae298f36e6..b5ae298f36e6 100755..100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 4107c5a791d6..aae9ccffc309 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -1,4 +1,4 @@
-/*
+ /*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -266,7 +266,7 @@ public abstract class Layout {
}
}
- Alignment align = mAlignment;
+ Alignment paraAlign = mAlignment;
TabStops tabStops = null;
boolean tabStopsIsInitialized = false;
@@ -310,10 +310,10 @@ public abstract class Layout {
ParagraphStyle.class);
spans = getParagraphSpans(sp, start, spanEnd, ParagraphStyle.class);
- align = mAlignment;
+ paraAlign = mAlignment;
for (int n = spans.length-1; n >= 0; n--) {
if (spans[n] instanceof AlignmentSpan) {
- align = ((AlignmentSpan) spans[n]).getAlignment();
+ paraAlign = ((AlignmentSpan) spans[n]).getAlignment();
break;
}
}
@@ -360,6 +360,16 @@ public abstract class Layout {
tabStopsIsInitialized = true;
}
+ // Determine whether the line aligns to normal, opposite, or center.
+ Alignment align = paraAlign;
+ if (align == Alignment.ALIGN_LEFT) {
+ align = (dir == DIR_LEFT_TO_RIGHT) ?
+ Alignment.ALIGN_NORMAL : Alignment.ALIGN_OPPOSITE;
+ } else if (align == Alignment.ALIGN_RIGHT) {
+ align = (dir == DIR_LEFT_TO_RIGHT) ?
+ Alignment.ALIGN_OPPOSITE : Alignment.ALIGN_NORMAL;
+ }
+
int x;
if (align == Alignment.ALIGN_NORMAL) {
if (dir == DIR_LEFT_TO_RIGHT) {
@@ -411,7 +421,9 @@ public abstract class Layout {
int dir = getParagraphDirection(line);
int x;
- if (align == Alignment.ALIGN_NORMAL) {
+ if (align == Alignment.ALIGN_LEFT) {
+ x = left;
+ } else if (align == Alignment.ALIGN_NORMAL) {
if (dir == DIR_LEFT_TO_RIGHT) {
x = left;
} else {
@@ -430,7 +442,9 @@ public abstract class Layout {
}
}
int max = (int)getLineExtent(line, tabStops, false);
- if (align == Alignment.ALIGN_OPPOSITE) {
+ if (align == Alignment.ALIGN_RIGHT) {
+ x = right - max;
+ } else if (align == Alignment.ALIGN_OPPOSITE) {
if (dir == DIR_LEFT_TO_RIGHT) {
x = right - max;
} else {
@@ -738,11 +752,15 @@ public abstract class Layout {
int dir = getParagraphDirection(line);
Alignment align = getParagraphAlignment(line);
- if (align == Alignment.ALIGN_NORMAL) {
+ if (align == Alignment.ALIGN_LEFT) {
+ return 0;
+ } else if (align == Alignment.ALIGN_NORMAL) {
if (dir == DIR_RIGHT_TO_LEFT)
return getParagraphRight(line) - getLineMax(line);
else
return 0;
+ } else if (align == Alignment.ALIGN_RIGHT) {
+ return mWidth - getLineMax(line);
} else if (align == Alignment.ALIGN_OPPOSITE) {
if (dir == DIR_RIGHT_TO_LEFT)
return 0;
@@ -765,11 +783,15 @@ public abstract class Layout {
int dir = getParagraphDirection(line);
Alignment align = getParagraphAlignment(line);
- if (align == Alignment.ALIGN_NORMAL) {
+ if (align == Alignment.ALIGN_LEFT) {
+ return getParagraphLeft(line) + getLineMax(line);
+ } else if (align == Alignment.ALIGN_NORMAL) {
if (dir == DIR_RIGHT_TO_LEFT)
return mWidth;
else
return getParagraphLeft(line) + getLineMax(line);
+ } else if (align == Alignment.ALIGN_RIGHT) {
+ return mWidth;
} else if (align == Alignment.ALIGN_OPPOSITE) {
if (dir == DIR_RIGHT_TO_LEFT)
return getLineMax(line);
@@ -1765,8 +1787,10 @@ public abstract class Layout {
ALIGN_NORMAL,
ALIGN_OPPOSITE,
ALIGN_CENTER,
- // XXX ALIGN_LEFT,
- // XXX ALIGN_RIGHT,
+ /** @hide */
+ ALIGN_LEFT,
+ /** @hide */
+ ALIGN_RIGHT,
}
private static final int TAB_INCREMENT = 20;
diff --git a/core/java/android/view/InputEventConsistencyVerifier.java b/core/java/android/view/InputEventConsistencyVerifier.java
index 49f3bbe1bcd7..9b081b207dff 100644
--- a/core/java/android/view/InputEventConsistencyVerifier.java
+++ b/core/java/android/view/InputEventConsistencyVerifier.java
@@ -239,7 +239,7 @@ public final class InputEventConsistencyVerifier {
break;
}
} finally {
- finishEvent(false);
+ finishEvent();
}
}
@@ -302,7 +302,7 @@ public final class InputEventConsistencyVerifier {
problem("Source was not SOURCE_CLASS_TRACKBALL.");
}
} finally {
- finishEvent(false);
+ finishEvent();
}
}
@@ -328,7 +328,9 @@ public final class InputEventConsistencyVerifier {
mTouchEventStreamUnhandled = false;
mTouchEventStreamPointers = 0;
}
- final boolean wasTainted = mTouchEventStreamIsTainted;
+ if (mTouchEventStreamIsTainted) {
+ event.setTainted(true);
+ }
try {
ensureMetaStateIsNormalized(event.getMetaState());
@@ -441,7 +443,7 @@ public final class InputEventConsistencyVerifier {
problem("Source was not SOURCE_CLASS_POINTER.");
}
} finally {
- finishEvent(wasTainted);
+ finishEvent();
}
}
@@ -499,7 +501,7 @@ public final class InputEventConsistencyVerifier {
}
}
} finally {
- finishEvent(false);
+ finishEvent();
}
}
@@ -591,9 +593,9 @@ public final class InputEventConsistencyVerifier {
return true;
}
- private void finishEvent(boolean tainted) {
+ private void finishEvent() {
if (mViolationMessage != null && mViolationMessage.length() != 0) {
- if (!tainted) {
+ if (!mCurrentEvent.isTainted()) {
// Write a log message only if the event was not already tainted.
mViolationMessage.append("\n in ").append(mCaller);
mViolationMessage.append("\n ");
@@ -614,17 +616,14 @@ public final class InputEventConsistencyVerifier {
}
Log.d(mLogTag, mViolationMessage.toString());
- tainted = true;
+
+ // Taint the event so that we do not generate additional violations from it
+ // further downstream.
+ mCurrentEvent.setTainted(true);
}
mViolationMessage.setLength(0);
}
- if (tainted) {
- // Taint the event so that we do not generate additional violations from it
- // further downstream.
- mCurrentEvent.setTainted(true);
- }
-
if (RECENT_EVENTS_TO_LOG != 0) {
if (mRecentEvents == null) {
mRecentEvents = new InputEvent[RECENT_EVENTS_TO_LOG];
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index f45e78bfef10..88f59d4bdd21 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -2885,7 +2885,7 @@ public final class MotionEvent extends InputEvent implements Parcelable {
toolTypeToString(getToolType(i)));
}
- msg.append(", buttonState=").append(KeyEvent.metaStateToString(getButtonState()));
+ msg.append(", buttonState=").append(MotionEvent.buttonStateToString(getButtonState()));
msg.append(", metaState=").append(KeyEvent.metaStateToString(getMetaState()));
msg.append(", flags=0x").append(Integer.toHexString(getFlags()));
msg.append(", edgeFlags=0x").append(Integer.toHexString(getEdgeFlags()));
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 8a72c4a14c66..12458987a63a 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -9135,9 +9135,15 @@ public class View implements Drawable.Callback2, KeyEvent.Callback, Accessibilit
}
/**
- * Reset the resolved layout direction by clearing the corresponding flag
+ * Reset the resolved layout direction.
+ *
+ * Subclasses need to override this method to clear cached information that depends on the
+ * resolved layout direction, or to inform child views that inherit their layout direction.
+ * Overrides must also call the superclass implementation at the start of their implementation.
+ *
+ * @hide
*/
- void resetLayoutDirectionResolution() {
+ protected void resetLayoutDirectionResolution() {
// Reset the current View resolution
mPrivateFlags2 &= ~LAYOUT_DIRECTION_RESOLVED;
}
diff --git a/core/java/android/view/ViewAncestor.java b/core/java/android/view/ViewAncestor.java
index 2b692f3e93f1..d70c79850a18 100644
--- a/core/java/android/view/ViewAncestor.java
+++ b/core/java/android/view/ViewAncestor.java
@@ -4637,13 +4637,18 @@ public final class ViewAncestor extends Handler implements ViewParent,
public void run() {
if (mView != null) {
- // Send the event directly since we do not want to append the
- // source text because this is the text for the entire window
- // and we just want to notify that the content has changed.
- AccessibilityEvent event = AccessibilityEvent.obtain(
- AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
- mView.onInitializeAccessibilityEvent(event);
- AccessibilityManager.getInstance(mView.mContext).sendAccessibilityEvent(event);
+ // Check again for accessibility state since this is executed delayed.
+ AccessibilityManager accessibilityManager =
+ AccessibilityManager.getInstance(mView.mContext);
+ if (accessibilityManager.isEnabled()) {
+ // Send the event directly since we do not want to append the
+ // source text because this is the text for the entire window
+ // and we just want to notify that the content has changed.
+ AccessibilityEvent event = AccessibilityEvent.obtain(
+ AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
+ mView.onInitializeAccessibilityEvent(event);
+ accessibilityManager.sendAccessibilityEvent(event);
+ }
mIsPending = false;
}
}
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index f3a5050001ea..dbcbd6e5ae1f 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -19,6 +19,8 @@ package android.view;
import android.app.AppGlobals;
import android.content.Context;
import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.os.RemoteException;
import android.provider.Settings;
import android.util.DisplayMetrics;
import android.util.SparseArray;
@@ -219,6 +221,9 @@ public class ViewConfiguration {
private final int mOverscrollDistance;
private final int mOverflingDistance;
+ private boolean sHasPermanentMenuKey;
+ private boolean sHasPermanentMenuKeySet;
+
private static final SparseArray<ViewConfiguration> sConfigurations =
new SparseArray<ViewConfiguration>(2);
@@ -254,11 +259,12 @@ public class ViewConfiguration {
* @see android.util.DisplayMetrics
*/
private ViewConfiguration(Context context) {
- final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
+ final Resources res = context.getResources();
+ final DisplayMetrics metrics = res.getDisplayMetrics();
+ final Configuration config = res.getConfiguration();
final float density = metrics.density;
final float sizeAndDensity;
- if (context.getResources().getConfiguration().isLayoutSizeAtLeast(
- Configuration.SCREENLAYOUT_SIZE_XLARGE)) {
+ if (config.isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_XLARGE)) {
sizeAndDensity = density * 1.5f;
} else {
sizeAndDensity = density;
@@ -280,6 +286,17 @@ public class ViewConfiguration {
mOverscrollDistance = (int) (sizeAndDensity * OVERSCROLL_DISTANCE + 0.5f);
mOverflingDistance = (int) (sizeAndDensity * OVERFLING_DISTANCE + 0.5f);
+
+ if (!sHasPermanentMenuKeySet) {
+ IWindowManager wm = Display.getWindowManager();
+ try {
+ sHasPermanentMenuKey = wm.canStatusBarHide() && !res.getBoolean(
+ com.android.internal.R.bool.config_showNavigationBar);
+ sHasPermanentMenuKeySet = true;
+ } catch (RemoteException ex) {
+ sHasPermanentMenuKey = false;
+ }
+ }
}
/**
@@ -640,4 +657,20 @@ public class ViewConfiguration {
public static float getScrollFriction() {
return SCROLL_FRICTION;
}
+
+ /**
+ * Report if the device has a permanent menu key available to the user.
+ *
+ * <p>As of Android 3.0, devices may not have a permanent menu key available.
+ * Apps should use the action bar to present menu options to users.
+ * However, there are some apps where the action bar is inappropriate
+ * or undesirable. This method may be used to detect if a menu key is present.
+ * If not, applications should provide another on-screen affordance to access
+ * functionality.
+ *
+ * @return true if a permanent menu key is present, false otherwise.
+ */
+ public boolean hasPermanentMenuKey() {
+ return sHasPermanentMenuKey;
+ }
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 5ebe4e5c64ed..41412deea742 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1746,6 +1746,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
final long now = SystemClock.uptimeMillis();
event = MotionEvent.obtain(now, now,
MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
+ event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
syntheticEvent = true;
}
@@ -4998,12 +4999,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
viewAncestor.requestTransitionStart(transition);
}
- /**
- * This method will be called when we need to reset the layout direction resolution flag
- *
- */
@Override
- void resetLayoutDirectionResolution() {
+ protected void resetLayoutDirectionResolution() {
super.resetLayoutDirectionResolution();
// Take care of resetting the children resolution too
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 25f01a7dc9fa..ac867690724b 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -25,40 +25,51 @@ import java.util.ArrayList;
import java.util.List;
/**
+ * <p>
* This class represents accessibility events that are sent by the system when
* something notable happens in the user interface. For example, when a
* {@link android.widget.Button} is clicked, a {@link android.view.View} is focused, etc.
+ * </p>
* <p>
* An accessibility event is fired by an individual view which populates the event with
- * a record for its state and requests from its parent to send the event to interested
- * parties. The parent can optionally add a record for itself before dispatching a similar
- * request to its parent. A parent can also choose not to respect the request for sending
- * an event. The accessibility event is sent by the topmost view in the view tree.
- * Therefore, an {@link android.accessibilityservice.AccessibilityService} can explore
- * all records in an accessibility event to obtain more information about the context
- * in which the event was fired.
+ * data for its state and requests from its parent to send the event to interested
+ * parties. The parent can optionally add an {@link AccessibilityRecord} for itself before
+ * dispatching a similar request to its parent. A parent can also choose not to respect the
+ * request for sending an event. The accessibility event is sent by the topmost view in the
+ * view tree. Therefore, an {@link android.accessibilityservice.AccessibilityService} can
+ * explore all records in an accessibility event to obtain more information about the
+ * context in which the event was fired.
+ * </p>
* <p>
- * A client can add, remove, and modify records. The getters and setters for individual
- * properties operate on the current record which can be explicitly set by the client. By
- * default current is the first record. Thus, querying a record would require setting
- * it as the current one and interacting with the property getters and setters.
+ * The main purpose of an accessibility event is to expose enough information for an
+ * {@link android.accessibilityservice.AccessibilityService} to provide meaningful feedback
+ * to the user. Sometimes however, an accessibility service may need more contextual
+ * information then the one in the event pay-load. In such cases the service can obtain
+ * the event source which is an {@link AccessibilityNodeInfo} (snapshot of a View state)
+ * which can be used for exploring the window content. Note that the privilege for accessing
+ * an event's source, thus the window content, has to be explicitly requested. For more
+ * details refer to {@link android.accessibilityservice.AccessibilityService}. If an
+ * accessibility service has not requested to retrieve the window content the event will
+ * not contain reference to its source. Also for events of type
+ * {@link #TYPE_NOTIFICATION_STATE_CHANGED} the source is never available.
+ * </p>
* <p>
* This class represents various semantically different accessibility event
- * types. Each event type has associated a set of related properties. In other
+ * types. Each event type has an associated set of related properties. In other
* words, each event type is characterized via a subset of the properties exposed
* by this class. For each event type there is a corresponding constant defined
- * in this class. Since some event types are semantically close there are mask
- * constants that group them together. Follows a specification of the event
- * types and their associated properties:
+ * in this class. Follows a specification of the event types and their associated properties:
+ * </p>
* <p>
- * <b>VIEW TYPES</b> <br>
+ * <b>VIEW TYPES</b></br>
+ * </p>
* <p>
* <b>View clicked</b> - represents the event of clicking on a {@link android.view.View}
- * like {@link android.widget.Button}, {@link android.widget.CompoundButton}, etc. <br>
- * Type:{@link #TYPE_VIEW_CLICKED} <br>
- * Properties:</br>
+ * like {@link android.widget.Button}, {@link android.widget.CompoundButton}, etc.</br>
+ * <em>Type:</em>{@link #TYPE_VIEW_CLICKED}</br>
+ * <em>Properties:</em></br>
* <ul>
- * <li>{@link #getSource()} - The source info (for registered clients).</li> *
+ * <li>{@link #getSource()} - The source info (for registered clients).</li>
* <li>{@link #getClassName()} - The class name of the source.</li>
* <li>{@link #getPackageName()} - The package name of the source.</li>
* <li>{@link #getEventTime()} - The event time.</li>
@@ -67,13 +78,14 @@ import java.util.List;
* <li>{@link #isPassword()} - Whether the source is password.</li>
* <li>{@link #isChecked()} - Whether the source is checked.</li>
* </ul>
+ * </p>
* <p>
* <b>View long clicked</b> - represents the event of long clicking on a {@link android.view.View}
- * like {@link android.widget.Button}, {@link android.widget.CompoundButton}, etc. <br>
- * Type:{@link #TYPE_VIEW_LONG_CLICKED} <br>
- * Properties:</br>
+ * like {@link android.widget.Button}, {@link android.widget.CompoundButton}, etc </br>
+ * <em>Type:</em>{@link #TYPE_VIEW_LONG_CLICKED}</br>
+ * <em>Properties:</em></br>
* <ul>
- * <li>{@link #getSource()} - The source info (for registered clients).</li> *
+ * <li>{@link #getSource()} - The source info (for registered clients).</li>
* <li>{@link #getClassName()} - The class name of the source.</li>
* <li>{@link #getPackageName()} - The package name of the source.</li>
* <li>{@link #getEventTime()} - The event time.</li>
@@ -82,13 +94,14 @@ import java.util.List;
* <li>{@link #isPassword()} - Whether the source is password.</li>
* <li>{@link #isChecked()} - Whether the source is checked.</li>
* </ul>
+ * </p>
* <p>
* <b>View selected</b> - represents the event of selecting an item usually in
- * the context of an {@link android.widget.AdapterView}. <br>
- * Type: {@link #TYPE_VIEW_SELECTED} <br>
- * Properties:</br>
+ * the context of an {@link android.widget.AdapterView}.</br>
+ * <em>Type:</em> {@link #TYPE_VIEW_SELECTED}</br>
+ * <em>Properties:</em></br>
* <ul>
- * <li>{@link #getSource()} - The source info (for registered clients).</li> *
+ * <li>{@link #getSource()} - The source info (for registered clients).</li>
* <li>{@link #getClassName()} - The class name of the source.</li>
* <li>{@link #getPackageName()} - The package name of the source.</li>
* <li>{@link #getEventTime()} - The event time.</li>
@@ -96,17 +109,17 @@ import java.util.List;
* <li>{@link #isEnabled()} - Whether the source is enabled.</li>
* <li>{@link #isPassword()} - Whether the source is password.</li>
* <li>{@link #isChecked()} - Whether the source is checked.</li>
- * <li>{@link #getItemCount()} -The number of selectable items of the source.</li>
+ * <li>{@link #getItemCount()} - The number of selectable items of the source.</li>
* <li>{@link #getCurrentItemIndex()} - The currently selected item index.</li>
* </ul>
- * <p>
+ * </p>
* <p>
* <b>View focused</b> - represents the event of focusing a
- * {@link android.view.View}. <br>
- * Type: {@link #TYPE_VIEW_FOCUSED} <br>
- * Properties:</br>
+ * {@link android.view.View}.</br>
+ * <em>Type:</em> {@link #TYPE_VIEW_FOCUSED}</br>
+ * <em>Properties:</em></br>
* <ul>
- * <li>{@link #getSource()} - The source info (for registered clients).</li> *
+ * <li>{@link #getSource()} - The source info (for registered clients).</li>
* <li>{@link #getClassName()} - The class name of the source.</li>
* <li>{@link #getPackageName()} - The package name of the source.</li>
* <li>{@link #getEventTime()} - The event time.</li>
@@ -114,16 +127,17 @@ import java.util.List;
* <li>{@link #isEnabled()} - Whether the source is enabled.</li>
* <li>{@link #isPassword()} - Whether the source is password.</li>
* <li>{@link #isChecked()} - Whether the source is checked.</li>
- * <li>{@link #getItemCount()} -The number of focusable items on the screen.</li>
+ * <li>{@link #getItemCount()} - The number of focusable items on the screen.</li>
* <li>{@link #getCurrentItemIndex()} - The currently focused item index.</li>
* </ul>
+ * </p>
* <p>
* <b>View text changed</b> - represents the event of changing the text of an
- * {@link android.widget.EditText}. <br>
- * Type: {@link #TYPE_VIEW_TEXT_CHANGED} <br>
- * Properties:</br>
+ * {@link android.widget.EditText}.</br>
+ * <em>Type:</em> {@link #TYPE_VIEW_TEXT_CHANGED}</br>
+ * <em>Properties:</em></br>
* <ul>
- * <li>{@link #getSource()} - The source info (for registered clients).</li> *
+ * <li>{@link #getSource()} - The source info (for registered clients).</li>
* <li>{@link #getClassName()} - The class name of the source.</li>
* <li>{@link #getPackageName()} - The package name of the source.</li>
* <li>{@link #getEventTime()} - The event time.</li>
@@ -136,13 +150,14 @@ import java.util.List;
* <li>{@link #getRemovedCount()} - The number of removed characters.</li>
* <li>{@link #getBeforeText()} - The text of the source before the change.</li>
* </ul>
+ * </p>
* <p>
* <b>View text selection changed</b> - represents the event of changing the text
- * selection of an {@link android.widget.EditText}.<br>
- * Type: {@link #TYPE_VIEW_TEXT_SELECTION_CHANGED} <br>
- * Properties:</br>
+ * selection of an {@link android.widget.EditText}.</br>
+ * <em>Type:</em> {@link #TYPE_VIEW_TEXT_SELECTION_CHANGED} </br>
+ * <em>Properties:</em></br>
* <ul>
- * <li>{@link #getSource()} - The source info (for registered clients).</li> *
+ * <li>{@link #getSource()} - The source info (for registered clients).</li>
* <li>{@link #getClassName()} - The class name of the source.</li>
* <li>{@link #getPackageName()} - The package name of the source.</li>
* <li>{@link #getEventTime()} - The event time.</li>
@@ -152,7 +167,8 @@ import java.util.List;
* <li>{@link #getFromIndex()} - The selection start index.</li>
* <li>{@link #getToIndex()} - The selection end index.</li>
* <li>{@link #getItemCount()} - The length of the source text.</li>
- * <ul>
+ * </ul>
+ * </p>
* <p>
* <b>View scrolled</b> - represents the event of scrolling a view. If
* the source is a descendant of {@link android.widget.AdapterView} the
@@ -161,11 +177,11 @@ import java.util.List;
* is unaware if its pixel size since its adapter is responsible for
* creating views. In all other cases the scroll is reported as the current
* scroll on the X and Y axis respectively plus the height of the source in
- * pixels.<br>
- * Type: {@link #TYPE_VIEW_SCROLLED} <br>
- * Properties:</br>
+ * pixels.</br>
+ * <em>Type:</em> {@link #TYPE_VIEW_SCROLLED}</br>
+ * <em>Properties:</em></br>
* <ul>
- * <li>{@link #getSource()} - The source info (for registered clients).</li> *
+ * <li>{@link #getSource()} - The source info (for registered clients).</li>
* <li>{@link #getClassName()} - The class name of the source.</li>
* <li>{@link #getPackageName()} - The package name of the source.</li>
* <li>{@link #getEventTime()} - The event time.</li>
@@ -181,41 +197,49 @@ import java.util.List;
* (for descendants of AdapterView).</li>
* <li>{@link #getItemCount()} - The total items of the source (for descendants of AdapterView)
* or the height of the source in pixels (all other cases).</li>
- * <ul>
- * <p>
- * <b>TRANSITION TYPES</b> <br>
+ * </ul>
+ * </p>
* <p>
+ * <b>TRANSITION TYPES</b></br>
+ * </p>
* <b>Window state changed</b> - represents the event of opening a
* {@link android.widget.PopupWindow}, {@link android.view.Menu},
- * {@link android.app.Dialog}, etc. <br>
- * Type: {@link #TYPE_WINDOW_STATE_CHANGED} <br>
- * Properties:</br>
+ * {@link android.app.Dialog}, etc.</br>
+ * <em>Type:</em> {@link #TYPE_WINDOW_STATE_CHANGED}</br>
+ * <em>Properties:</em></br>
* <ul>
- * <li>{@link #getSource()} - The source info (for registered clients).</li> *
+ * <li>{@link #getSource()} - The source info (for registered clients).</li>
* <li>{@link #getClassName()} - The class name of the source.</li>
* <li>{@link #getPackageName()} - The package name of the source.</li>
* <li>{@link #getEventTime()} - The event time.</li>
* <li>{@link #getText()} - The text of the source.</li>
* </ul>
+ * </p>
* <p>
* <b>Window content changed</b> - represents the event of change in the
* content of a window. This change can be adding/removing view, changing
- * a view size, etc.<br>
- * Type: {@link #TYPE_WINDOW_CONTENT_CHANGED} <br>
- * Properties:</br>
+ * a view size, etc.</br>
+ * <p>
+ * <strong>Note:</strong> This event is fired only for the window source of the
+ * last accessibility event different from {@link #TYPE_NOTIFICATION_STATE_CHANGED})
+ * and its purpose is to notify clients that the content of the user interaction
+ * window has changed.
+ * </p>
+ * <em>Type:</em> {@link #TYPE_WINDOW_CONTENT_CHANGED}</br>
+ * <em>Properties:</em></br>
* <ul>
- * <li>{@link #getSource()} - The source info (for registered clients).</li> *
+ * <li>{@link #getSource()} - The source info (for registered clients).</li>
* <li>{@link #getClassName()} - The class name of the source.</li>
* <li>{@link #getPackageName()} - The package name of the source.</li>
* <li>{@link #getEventTime()} - The event time.</li>
- * <ul>
+ * </ul>
* <p>
- * <b>NOTIFICATION TYPES</b> <br>
+ * <b>NOTIFICATION TYPES</b></br>
* <p>
- * <b>Notification state changed</b> - represents the event showing/hiding
+ * <b>Notification state changed</b> - represents the event showing
* {@link android.app.Notification}.
- * Type: {@link #TYPE_NOTIFICATION_STATE_CHANGED} <br>
- * Properties:</br>
+ * <em>Type:</em> {@link #TYPE_NOTIFICATION_STATE_CHANGED}</br>
+ * <em>Properties:</em></br>
* <ul>
* <li>{@link #getClassName()} - The class name of the source.</li>
* <li>{@link #getPackageName()} - The package name of the source.</li>
@@ -223,15 +247,17 @@ import java.util.List;
* <li>{@link #getText()} - The text of the source.</li>
* <li>{@link #getParcelableData()} - The posted {@link android.app.Notification}.</li>
* </ul>
+ * </p>
* <p>
* <b>Security note</b>
* <p>
- * Since an event contains the text of its source privacy can be compromised by leaking of
+ * Since an event contains the text of its source privacy can be compromised by leaking
* sensitive information such as passwords. To address this issue any event fired in response
* to manipulation of a PASSWORD field does NOT CONTAIN the text of the password.
*
* @see android.view.accessibility.AccessibilityManager
* @see android.accessibilityservice.AccessibilityService
+ * @see AccessibilityNodeInfo
*/
public final class AccessibilityEvent extends AccessibilityRecord implements Parcelable {
private static final boolean DEBUG = false;
@@ -285,13 +311,13 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
public static final int TYPE_VIEW_TEXT_CHANGED = 0x00000010;
/**
- * Represents the event of opening/closing a {@link android.widget.PopupWindow},
+ * Represents the event of opening a {@link android.widget.PopupWindow},
* {@link android.view.Menu}, {@link android.app.Dialog}, etc.
*/
public static final int TYPE_WINDOW_STATE_CHANGED = 0x00000020;
/**
- * Represents the event showing/hiding a {@link android.app.Notification}.
+ * Represents the event showing a {@link android.app.Notification}.
*/
public static final int TYPE_NOTIFICATION_STATE_CHANGED = 0x00000040;
@@ -340,6 +366,13 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
* @see #TYPE_VIEW_TEXT_CHANGED
* @see #TYPE_WINDOW_STATE_CHANGED
* @see #TYPE_NOTIFICATION_STATE_CHANGED
+ * @see #TYPE_VIEW_HOVER_ENTER
+ * @see #TYPE_VIEW_HOVER_EXIT
+ * @see #TYPE_TOUCH_EXPLORATION_GESTURE_START
+ * @see #TYPE_TOUCH_EXPLORATION_GESTURE_END
+ * @see #TYPE_WINDOW_CONTENT_CHANGED
+ * @see #TYPE_VIEW_SCROLLED
+ * @see #TYPE_VIEW_TEXT_SELECTION_CHANGED
*/
public static final int TYPES_ALL_MASK = 0xFFFFFFFF;
@@ -432,10 +465,10 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
}
/**
- * Gets the records at a given index.
+ * Gets the record at a given index.
*
* @param index The index.
- * @return The records at the specified index.
+ * @return The record at the specified index.
*/
public AccessibilityRecord getRecord(int index) {
return mRecords.get(index);
@@ -506,7 +539,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
/**
* Returns a cached instance if such is available or a new one is
- * instantiated with type property set.
+ * instantiated with its type property set.
*
* @param eventType The event type.
* @return An instance.
@@ -519,7 +552,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
/**
* Returns a cached instance if such is available or a new one is
- * instantiated with type property set.
+ * initialized with from the given <code>event</code>.
*
* @param event The other event.
* @return An instance.
@@ -559,9 +592,10 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
}
/**
- * Return an instance back to be reused.
+ * Recycles an instance back to be reused.
* <p>
- * <b>Note: You must not touch the object after calling this function.</b>
+ * <b>Note: You must not touch the object after calling this function.</b>
+ * </p>
*
* @throws IllegalStateException If the event is already recycled.
*/
@@ -714,7 +748,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
- builder.append("; EventType: ").append(eventTypeToString(mEventType));
+ builder.append("EventType: ").append(eventTypeToString(mEventType));
builder.append("; EventTime: ").append(mEventTime);
builder.append("; PackageName: ").append(mPackageName);
builder.append(super.toString());
@@ -758,11 +792,11 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
* Returns the string representation of an event type. For example,
* {@link #TYPE_VIEW_CLICKED} is represented by the string TYPE_VIEW_CLICKED.
*
- * @param feedbackType The event type
+ * @param eventType The event type
* @return The string representation.
*/
- public static String eventTypeToString(int feedbackType) {
- switch (feedbackType) {
+ public static String eventTypeToString(int eventType) {
+ switch (eventType) {
case TYPE_VIEW_CLICKED:
return "TYPE_VIEW_CLICKED";
case TYPE_VIEW_LONG_CLICKED:
diff --git a/core/java/android/view/accessibility/AccessibilityEventSource.java b/core/java/android/view/accessibility/AccessibilityEventSource.java
index 3d70959b1ef9..f11880bc8c07 100644
--- a/core/java/android/view/accessibility/AccessibilityEventSource.java
+++ b/core/java/android/view/accessibility/AccessibilityEventSource.java
@@ -24,11 +24,12 @@ public interface AccessibilityEventSource {
/**
* Handles the request for sending an {@link AccessibilityEvent} given
* the event type. The method must first check if accessibility is on
- * via calling {@link AccessibilityManager#isEnabled()}, obtain
- * an {@link AccessibilityEvent} from the event pool through calling
- * {@link AccessibilityEvent#obtain(int)}, populate the event, and
- * send it for dispatch via calling
- * {@link AccessibilityManager#sendAccessibilityEvent(AccessibilityEvent)}.
+ * via calling {@link AccessibilityManager#isEnabled() AccessibilityManager.isEnabled()},
+ * obtain an {@link AccessibilityEvent} from the event pool through calling
+ * {@link AccessibilityEvent#obtain(int) AccessibilityEvent.obtain(int)}, populate the
+ * event, and send it for dispatch via calling
+ * {@link AccessibilityManager#sendAccessibilityEvent(AccessibilityEvent)
+ * AccessibilityManager.sendAccessibilityEvent(AccessibilityEvent)}.
*
* @see AccessibilityEvent
* @see AccessibilityManager
@@ -41,7 +42,8 @@ public interface AccessibilityEventSource {
* Handles the request for sending an {@link AccessibilityEvent}. The
* method does not guarantee to check if accessibility is on before
* sending the event for dispatch. It is responsibility of the caller
- * to do the check via calling {@link AccessibilityManager#isEnabled()}.
+ * to do the check via calling {@link AccessibilityManager#isEnabled()
+ * AccessibilityManager.isEnabled()}.
*
* @see AccessibilityEvent
* @see AccessibilityManager
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index eece64af3e16..314b7ca35821 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -37,16 +37,30 @@ import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/**
- * System level service that serves as an event dispatch for {@link AccessibilityEvent}s.
- * Such events are generated when something notable happens in the user interface,
+ * System level service that serves as an event dispatch for {@link AccessibilityEvent}s,
+ * and provides facilities for querying the accessibility state of the system.
+ * Accessibility events are generated when something notable happens in the user interface,
* for example an {@link android.app.Activity} starts, the focus or selection of a
* {@link android.view.View} changes etc. Parties interested in handling accessibility
* events implement and register an accessibility service which extends
* {@link android.accessibilityservice.AccessibilityService}.
+ * <p>
+ * To obtain a handle to the accessibility manager do the following:
+ * </p>
+ * <p>
+ * <code>
+ * <pre>
+ * AccessibilityManager accessibilityManager =
+ * (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
+ * </pre>
+ * </code>
+ * </p>
*
* @see AccessibilityEvent
+ * @see AccessibilityNodeInfo
* @see android.accessibilityservice.AccessibilityService
- * @see android.content.Context#getSystemService
+ * @see Context#getSystemService
+ * @see Context#ACCESSIBILITY_SERVICE
*/
public final class AccessibilityManager {
private static final boolean DEBUG = false;
@@ -72,10 +86,11 @@ public final class AccessibilityManager {
* Listener for the accessibility state.
*/
public interface AccessibilityStateChangeListener {
+
/**
* Called back on change in the accessibility state.
*
- * @param enabled
+ * @param enabled Whether accessibility is enabled.
*/
public void onAccessibilityStateChanged(boolean enabled);
}
@@ -142,9 +157,9 @@ public final class AccessibilityManager {
}
/**
- * Returns if the {@link AccessibilityManager} is enabled.
+ * Returns if the accessibility in the system is enabled.
*
- * @return True if this {@link AccessibilityManager} is enabled, false otherwise.
+ * @return True if accessibility is enabled, false otherwise.
*/
public boolean isEnabled() {
synchronized (mHandler) {
@@ -161,17 +176,15 @@ public final class AccessibilityManager {
* @hide
*/
public IAccessibilityManagerClient getClient() {
- return (IAccessibilityManagerClient) mClient.asBinder();
+ return (IAccessibilityManagerClient) mClient.asBinder();
}
/**
- * Sends an {@link AccessibilityEvent}. If this {@link AccessibilityManager} is not
- * enabled the call is a NOOP.
+ * Sends an {@link AccessibilityEvent}.
*
- * @param event The {@link AccessibilityEvent}.
+ * @param event The event to send.
*
- * @throws IllegalStateException if a client tries to send an {@link AccessibilityEvent}
- * while accessibility is not enabled.
+ * @throws IllegalStateException if accessibility is not enabled.
*/
public void sendAccessibilityEvent(AccessibilityEvent event) {
if (!mIsEnabled) {
@@ -199,7 +212,7 @@ public final class AccessibilityManager {
}
/**
- * Requests interruption of the accessibility feedback from all accessibility services.
+ * Requests feedback interruption from all accessibility services.
*/
public void interrupt() {
if (!mIsEnabled) {
@@ -256,13 +269,20 @@ public final class AccessibilityManager {
* Returns the {@link AccessibilityServiceInfo}s of the enabled accessibility services
* for a given feedback type.
*
- * @param feedbackType The feedback type (can be bitwise or of multiple types).
+ * @param feedbackTypeFlags The feedback type flags.
* @return An unmodifiable list with {@link AccessibilityServiceInfo}s.
+ *
+ * @see AccessibilityServiceInfo#FEEDBACK_AUDIBLE
+ * @see AccessibilityServiceInfo#FEEDBACK_GENERIC
+ * @see AccessibilityServiceInfo#FEEDBACK_HAPTIC
+ * @see AccessibilityServiceInfo#FEEDBACK_SPOKEN
+ * @see AccessibilityServiceInfo#FEEDBACK_VISUAL
*/
- public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType) {
+ public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(
+ int feedbackTypeFlags) {
List<AccessibilityServiceInfo> services = null;
try {
- services = mService.getEnabledAccessibilityServiceList(feedbackType);
+ services = mService.getEnabledAccessibilityServiceList(feedbackTypeFlags);
if (DEBUG) {
Log.i(LOG_TAG, "Installed AccessibilityServices " + services);
}
@@ -273,7 +293,8 @@ public final class AccessibilityManager {
}
/**
- * Registers an {@link AccessibilityStateChangeListener}.
+ * Registers an {@link AccessibilityStateChangeListener} for changes in
+ * the global accessibility state of the system.
*
* @param listener The listener.
* @return True if successfully registered.
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index dbbe7be4d533..031c6aeffd21 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -22,7 +22,6 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
import android.text.TextUtils;
-import android.util.SparseArray;
import android.util.SparseIntArray;
import android.view.View;
@@ -30,12 +29,26 @@ import java.util.Collections;
import java.util.List;
/**
- * This class represents a node of the screen content. From the point of
- * view of an accessibility service the screen content is presented as tree
- * of accessibility nodes.
+ * This class represents a node of the window content as well as actions that
+ * can be requested from its source. From the point of view of an
+ * {@link android.accessibilityservice.AccessibilityService} a window content is
+ * presented as tree of accessibility node info which may or may not map one-to-one
+ * to the view hierarchy. In other words, a custom view is free to report itself as
+ * a tree of accessibility node info.
+ * </p>
+ * <p>
+ * Once an accessibility node info is delivered to an accessibility service it is
+ * made immutable and calling a state mutation method generates an error.
+ * </p>
+ * <p>
+ * Please refer to {@link android.accessibilityservice.AccessibilityService} for
+ * details about how to obtain a handle to window content as a tree of accessibility
+ * node info as well as familiarizing with the security model.
+ * </p>
*
- * TODO(svertoslavganov): Update the documentation, add sample, and describe
- * the security policy.
+ * @see android.accessibilityservice.AccessibilityService
+ * @see AccessibilityEvent
+ * @see AccessibilityManager
*/
public class AccessibilityNodeInfo implements Parcelable {
@@ -85,9 +98,6 @@ public class AccessibilityNodeInfo implements Parcelable {
private static final int PROPERTY_SCROLLABLE = 0x00000200;
- // Readable representations - lazily initialized.
- private static SparseArray<String> sActionSymbolicNames;
-
// Housekeeping.
private static final int MAX_POOL_SIZE = 50;
private static final Object sPoolLock = new Object();
@@ -154,12 +164,11 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Get the child at given index.
* <p>
- * <strong>
- * It is a client responsibility to recycle the received info by
- * calling {@link AccessibilityNodeInfo#recycle()} to avoid creating
- * of multiple instances.
- * </strong>
+ * <strong>Note:</strong> It is a client responsibility to recycle the
+ * received info by calling {@link AccessibilityNodeInfo#recycle()}
+ * to avoid creating of multiple instances.
* </p>
+ *
* @param index The child index.
* @return The child node.
*
@@ -184,9 +193,11 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Adds a child.
* <p>
- * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
* This class is made immutable before being delivered to an AccessibilityService.
* </p>
+ *
* @param child The child.
*
* @throws IllegalStateException If called from an AccessibilityService.
@@ -215,9 +226,11 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Adds an action that can be performed on the node.
* <p>
- * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
* This class is made immutable before being delivered to an AccessibilityService.
* </p>
+ *
* @param action The action.
*
* @throws IllegalStateException If called from an AccessibilityService.
@@ -230,9 +243,10 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Performs an action on the node.
* <p>
- * Note: An action can be performed only if the request is made
+ * <strong>Note:</strong> An action can be performed only if the request is made
* from an {@link android.accessibilityservice.AccessibilityService}.
* </p>
+ *
* @param action The action to perform.
* @return True if the action was performed.
*
@@ -256,6 +270,11 @@ public class AccessibilityNodeInfo implements Parcelable {
* Finds {@link AccessibilityNodeInfo}s by text. The match is case
* insensitive containment. The search is relative to this info i.e.
* this info is the root of the traversed tree.
+ * <p>
+ * <strong>Note:</strong> It is a client responsibility to recycle the
+ * received info by calling {@link AccessibilityNodeInfo#recycle()}
+ * to avoid creating of multiple instances.
+ * </p>
*
* @param text The searched text.
* @return A list of node info.
@@ -277,12 +296,11 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Gets the unique id identifying this node's parent.
* <p>
- * <strong>
- * It is a client responsibility to recycle the received info by
- * calling {@link AccessibilityNodeInfo#recycle()} to avoid creating
- * of multiple instances.
- * </strong>
+ * <strong>Note:</strong> It is a client responsibility to recycle the
+ * received info by calling {@link AccessibilityNodeInfo#recycle()}
+ * to avoid creating of multiple instances.
* </p>
+ *
* @return The node's patent id.
*/
public AccessibilityNodeInfo getParent() {
@@ -302,9 +320,11 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Sets the parent.
* <p>
- * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
* This class is made immutable before being delivered to an AccessibilityService.
* </p>
+ *
* @param parent The parent.
*
* @throws IllegalStateException If called from an AccessibilityService.
@@ -327,9 +347,11 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Sets the node bounds in parent coordinates.
* <p>
- * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
* This class is made immutable before being delivered to an AccessibilityService.
* </p>
+ *
* @param bounds The node bounds.
*
* @throws IllegalStateException If called from an AccessibilityService.
@@ -352,9 +374,11 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Sets the node bounds in screen coordinates.
* <p>
- * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
* This class is made immutable before being delivered to an AccessibilityService.
* </p>
+ *
* @param bounds The node bounds.
*
* @throws IllegalStateException If called from an AccessibilityService.
@@ -376,9 +400,11 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Sets whether this node is checkable.
* <p>
- * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
* This class is made immutable before being delivered to an AccessibilityService.
* </p>
+ *
* @param checkable True if the node is checkable.
*
* @throws IllegalStateException If called from an AccessibilityService.
@@ -399,9 +425,11 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Sets whether this node is checked.
* <p>
- * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
* This class is made immutable before being delivered to an AccessibilityService.
* </p>
+ *
* @param checked True if the node is checked.
*
* @throws IllegalStateException If called from an AccessibilityService.
@@ -422,9 +450,11 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Sets whether this node is focusable.
* <p>
- * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
* This class is made immutable before being delivered to an AccessibilityService.
* </p>
+ *
* @param focusable True if the node is focusable.
*
* @throws IllegalStateException If called from an AccessibilityService.
@@ -445,9 +475,11 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Sets whether this node is focused.
* <p>
- * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
* This class is made immutable before being delivered to an AccessibilityService.
* </p>
+ *
* @param focused True if the node is focused.
*
* @throws IllegalStateException If called from an AccessibilityService.
@@ -468,9 +500,11 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Sets whether this node is selected.
* <p>
- * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
* This class is made immutable before being delivered to an AccessibilityService.
* </p>
+ *
* @param selected True if the node is selected.
*
* @throws IllegalStateException If called from an AccessibilityService.
@@ -491,9 +525,11 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Sets whether this node is clickable.
* <p>
- * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
* This class is made immutable before being delivered to an AccessibilityService.
* </p>
+ *
* @param clickable True if the node is clickable.
*
* @throws IllegalStateException If called from an AccessibilityService.
@@ -514,9 +550,11 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Sets whether this node is long clickable.
* <p>
- * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
* This class is made immutable before being delivered to an AccessibilityService.
* </p>
+ *
* @param longClickable True if the node is long clickable.
*
* @throws IllegalStateException If called from an AccessibilityService.
@@ -537,9 +575,11 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Sets whether this node is enabled.
* <p>
- * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
* This class is made immutable before being delivered to an AccessibilityService.
* </p>
+ *
* @param enabled True if the node is enabled.
*
* @throws IllegalStateException If called from an AccessibilityService.
@@ -560,9 +600,11 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Sets whether this node is a password.
* <p>
- * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
* This class is made immutable before being delivered to an AccessibilityService.
* </p>
+ *
* @param password True if the node is a password.
*
* @throws IllegalStateException If called from an AccessibilityService.
@@ -582,6 +624,11 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Sets if the node is scrollable.
+ * <p>
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
+ * This class is made immutable before being delivered to an AccessibilityService.
+ * </p>
*
* @param scrollable True if the node is scrollable, false otherwise.
*
@@ -604,9 +651,11 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Sets the package this node comes from.
* <p>
- * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
* This class is made immutable before being delivered to an AccessibilityService.
* </p>
+ *
* @param packageName The package name.
*
* @throws IllegalStateException If called from an AccessibilityService.
@@ -628,9 +677,11 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Sets the class this node comes from.
* <p>
- * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
* This class is made immutable before being delivered to an AccessibilityService.
* </p>
+ *
* @param className The class name.
*
* @throws IllegalStateException If called from an AccessibilityService.
@@ -652,9 +703,11 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Sets the text of this node.
* <p>
- * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
* This class is made immutable before being delivered to an AccessibilityService.
* </p>
+ *
* @param text The text.
*
* @throws IllegalStateException If called from an AccessibilityService.
@@ -676,9 +729,11 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Sets the content description of this node.
* <p>
- * Note: Cannot be called from an {@link android.accessibilityservice.AccessibilityService}.
+ * <strong>Note:</strong> Cannot be called from an
+ * {@link android.accessibilityservice.AccessibilityService}.
* This class is made immutable before being delivered to an AccessibilityService.
* </p>
+ *
* @param contentDescription The content description.
*
* @throws IllegalStateException If called from an AccessibilityService.
@@ -820,7 +875,7 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* Return an instance back to be reused.
* <p>
- * <b>Note: You must not touch the object after calling this function.</b>
+ * <strong>Note:</strong> You must not touch the object after calling this function.
*
* @throws IllegalStateException If the info is already recycled.
*/
@@ -842,8 +897,8 @@ public class AccessibilityNodeInfo implements Parcelable {
/**
* {@inheritDoc}
* <p>
- * <b>Note: After the instance is written to a parcel it is recycled.
- * You must not touch the object after calling this function.</b>
+ * <strong>Note:</strong> After the instance is written to a parcel it
+ * is recycled. You must not touch the object after calling this function.
* </p>
*/
public void writeToParcel(Parcel parcel, int flags) {
@@ -885,7 +940,7 @@ public class AccessibilityNodeInfo implements Parcelable {
TextUtils.writeToParcel(mContentDescription, parcel, flags);
// Since instances of this class are fetched via synchronous i.e. blocking
- // calls in IPCs and we always recycle as soon as the instance is marshaled.
+ // calls in IPCs we always recycle as soon as the instance is marshaled.
recycle();
}
@@ -957,15 +1012,18 @@ public class AccessibilityNodeInfo implements Parcelable {
* @return The symbolic name.
*/
private static String getActionSymbolicName(int action) {
- SparseArray<String> actionSymbolicNames = sActionSymbolicNames;
- if (actionSymbolicNames == null) {
- actionSymbolicNames = sActionSymbolicNames = new SparseArray<String>();
- actionSymbolicNames.put(ACTION_FOCUS, "ACTION_FOCUS");
- actionSymbolicNames.put(ACTION_CLEAR_FOCUS, "ACTION_UNFOCUS");
- actionSymbolicNames.put(ACTION_SELECT, "ACTION_SELECT");
- actionSymbolicNames.put(ACTION_CLEAR_SELECTION, "ACTION_UNSELECT");
+ switch (action) {
+ case ACTION_FOCUS:
+ return "ACTION_FOCUS";
+ case ACTION_CLEAR_FOCUS:
+ return "ACTION_CLEAR_FOCUS";
+ case ACTION_SELECT:
+ return "ACTION_SELECT";
+ case ACTION_CLEAR_SELECTION:
+ return "ACTION_CLEAR_SELECTION";
+ default:
+ throw new IllegalArgumentException("Unknown action: " + action);
}
- return actionSymbolicNames.get(action);
}
private boolean canPerformRequestOverConnection(int accessibilityViewId) {
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index b9815c5bbaef..f4d5e897e422 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -25,12 +25,28 @@ import java.util.ArrayList;
import java.util.List;
/**
- * Represents a record in an accessibility event. This class encapsulates
- * the information for a {@link android.view.View}. Note that not all properties
- * are applicable to all view types. For detailed information please refer to
- * {@link AccessibilityEvent}.
+ * Represents a record in an {@link AccessibilityEvent} and contains information
+ * about state change of its source {@link android.view.View}. When a view fires
+ * an accessibility event it requests from its parent to dispatch the
+ * constructed event. The parent may optionally append a record for itself
+ * for providing more context to
+ * {@link android.accessibilityservice.AccessibilityService}s. Hence,
+ * accessibility services can facilitate additional accessibility records
+ * to enhance feedback.
+ * </p>
+ * <p>
+ * Once the accessibility event containing a record is dispatched the record is
+ * made immutable and calling a state mutation method generates an error.
+ * </p>
+ * <p>
+ * <strong>Note:</strong> Not all properties are applicable to all accessibility
+ * event types. For detailed information please refer to {@link AccessibilityEvent}.
+ * </p>
*
* @see AccessibilityEvent
+ * @see AccessibilityManager
+ * @see android.accessibilityservice.AccessibilityService
+ * @see AccessibilityNodeInfo
*/
public class AccessibilityRecord {
@@ -79,32 +95,6 @@ public class AccessibilityRecord {
}
/**
- * Initialize this record from another one.
- *
- * @param record The to initialize from.
- */
- void init(AccessibilityRecord record) {
- mSealed = record.mSealed;
- mBooleanProperties = record.mBooleanProperties;
- mCurrentItemIndex = record.mCurrentItemIndex;
- mItemCount = record.mItemCount;
- mFromIndex = record.mFromIndex;
- mToIndex = record.mToIndex;
- mScrollX = record.mScrollX;
- mScrollY = record.mScrollY;
- mAddedCount = record.mAddedCount;
- mRemovedCount = record.mRemovedCount;
- mClassName = record.mClassName;
- mContentDescription = record.mContentDescription;
- mBeforeText = record.mBeforeText;
- mParcelableData = record.mParcelableData;
- mText.addAll(record.mText);
- mSourceWindowId = record.mSourceWindowId;
- mSourceViewId = record.mSourceViewId;
- mConnection = record.mConnection;
- }
-
- /**
* Sets the event source.
*
* @param source The source.
@@ -125,13 +115,12 @@ public class AccessibilityRecord {
/**
* Gets the {@link AccessibilityNodeInfo} of the event source.
* <p>
- * <strong>
- * It is a client responsibility to recycle the received info by
- * calling {@link AccessibilityNodeInfo#recycle()} to avoid creating
- * of multiple instances.
- * </strong>
+ * <strong>Note:</strong> It is a client responsibility to recycle the received info
+ * by calling {@link AccessibilityNodeInfo#recycle() AccessibilityNodeInfo#recycle()}
+ * to avoid creating of multiple instances.
+ *
* </p>
- * @return The info.
+ * @return The info of the source.
*/
public AccessibilityNodeInfo getSource() {
enforceSealed();
@@ -641,7 +630,7 @@ public class AccessibilityRecord {
/**
* Return an instance back to be reused.
* <p>
- * <b>Note: You must not touch the object after calling this function.</b>
+ * <strong>Note:</strong> You must not touch the object after calling this function.
*
* @throws IllegalStateException If the record is already recycled.
*/
@@ -661,6 +650,32 @@ public class AccessibilityRecord {
}
/**
+ * Initialize this record from another one.
+ *
+ * @param record The to initialize from.
+ */
+ void init(AccessibilityRecord record) {
+ mSealed = record.mSealed;
+ mBooleanProperties = record.mBooleanProperties;
+ mCurrentItemIndex = record.mCurrentItemIndex;
+ mItemCount = record.mItemCount;
+ mFromIndex = record.mFromIndex;
+ mToIndex = record.mToIndex;
+ mScrollX = record.mScrollX;
+ mScrollY = record.mScrollY;
+ mAddedCount = record.mAddedCount;
+ mRemovedCount = record.mRemovedCount;
+ mClassName = record.mClassName;
+ mContentDescription = record.mContentDescription;
+ mBeforeText = record.mBeforeText;
+ mParcelableData = record.mParcelableData;
+ mText.addAll(record.mText);
+ mSourceWindowId = record.mSourceWindowId;
+ mSourceViewId = record.mSourceViewId;
+ mConnection = record.mConnection;
+ }
+
+ /**
* Clears the state of this instance.
*/
void clear() {
diff --git a/core/java/android/view/accessibility/package.html b/core/java/android/view/accessibility/package.html
new file mode 100644
index 000000000000..4afafd3ca128
--- /dev/null
+++ b/core/java/android/view/accessibility/package.html
@@ -0,0 +1,39 @@
+<html>
+<body>
+<p>
+ The classes in this package are used to represent screen content and changes to it
+ as well as APIs for querying the global accessibility state of the system.
+</p>
+<p>
+ {@link android.view.accessibility.AccessibilityEvent}s are sent by the system when
+ something notable happens in the user interface. For example, when a
+ {@link android.widget.Button} is clicked, a {@link android.view.View} is focused, etc.
+</p>
+<p>
+ {@link android.view.accessibility.AccessibilityRecord} contains information
+ about state change of its source {@link android.view.View}. When a view fires
+ an accessibility event it requests from its parent to dispatch the
+ constructed event. The parent may optionally append a record for itself for
+ providing more context to {@link android.accessibilityservice.AccessibilityService}s.
+ Hence, accessibility services can facilitate additional accessibility records
+ to enhance feedback.
+</p>
+<p>
+ {@link android.view.accessibility.AccessibilityNodeInfo} represents a node of the
+ window content as well as actions that can be requested from its source. From the point
+ of view of an {@link android.accessibilityservice.AccessibilityService} a window content is
+ presented as tree of accessibility node info which may or may not map one-to-one
+ to the view hierarchy. In other words, a custom view is free to report itself as
+ a tree of accessibility node info.
+</p>
+<p>
+ {@link android.view.accessibility.AccessibilityManager} is a system level service that
+ serves as an event dispatch for {@link android.view.accessibility.AccessibilityEvent}s,
+ and provides facilities for querying the accessibility state of the system. Accessibility
+ events are generated when something notable happens in the user interface, for example an
+ {@link android.app.Activity} starts, the focus or selection of a {@link android.view.View}
+ changes etc. Parties interested in handling accessibility events implement and register an
+ accessibility service which extends {@link android.accessibilityservice.AccessibilityService}.
+</p>
+</body>
+</html>
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 47f5e4c4f9cb..a1a7281c7710 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1126,7 +1126,7 @@ public final class InputMethodManager {
if (mServedView == mNextServedView && !mNextServedNeedsStart) {
return;
}
-
+
InputConnection ic = null;
synchronized (mH) {
if (mServedView == mNextServedView && !mNextServedNeedsStart) {
@@ -1242,6 +1242,27 @@ public final class InputMethodManager {
}
/**
+ * Notify the event when the user tapped or clicked the text view.
+ */
+ public void viewClicked(View view) {
+ final boolean focusChanged = mServedView != mNextServedView;
+ checkFocus();
+ synchronized (mH) {
+ if ((mServedView != view && (mServedView == null
+ || !mServedView.checkInputConnectionProxy(view)))
+ || mCurrentTextBoxAttribute == null || mCurMethod == null) {
+ return;
+ }
+ try {
+ if (DEBUG) Log.v(TAG, "onViewClicked: " + focusChanged);
+ mCurMethod.viewClicked(focusChanged);
+ } catch (RemoteException e) {
+ Log.w(TAG, "IME died: " + mCurId, e);
+ }
+ }
+ }
+
+ /**
* Returns true if the current input method wants to watch the location
* of the input editor's cursor in its window.
*/
diff --git a/core/java/android/view/inputmethod/InputMethodSession.java b/core/java/android/view/inputmethod/InputMethodSession.java
index bb03afad56ae..ea6f5ee4a976 100644
--- a/core/java/android/view/inputmethod/InputMethodSession.java
+++ b/core/java/android/view/inputmethod/InputMethodSession.java
@@ -63,6 +63,15 @@ public interface InputMethodSession {
int candidatesStart, int candidatesEnd);
/**
+ * This method is called when the user tapped a text view.
+ * IMEs can't rely on this method being called because this was not part of the original IME
+ * protocol, so applications with custom text editing written before this method appeared will
+ * not call to inform the IME of this interaction.
+ * @param focusChanged true if the user changed the focused view by this click.
+ */
+ public void viewClicked(boolean focusChanged);
+
+ /**
* This method is called when cursor location of the target input field
* has changed within its window. This is not normally called, but will
* only be reported if requested by the input method.
diff --git a/core/java/android/webkit/CertTool.java b/core/java/android/webkit/CertTool.java
index 4c534f93cd26..a2325c328af5 100644
--- a/core/java/android/webkit/CertTool.java
+++ b/core/java/android/webkit/CertTool.java
@@ -21,31 +21,27 @@ import com.android.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import com.android.org.bouncycastle.jce.netscape.NetscapeCertRequest;
import com.android.org.bouncycastle.util.encoders.Base64;
-import android.content.ActivityNotFoundException;
import android.content.Context;
-import android.content.Intent;
import android.security.Credentials;
+import android.security.KeyChain;
import android.util.Log;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.util.HashMap;
-class CertTool {
+final class CertTool {
private static final String LOGTAG = "CertTool";
private static final AlgorithmIdentifier MD5_WITH_RSA =
new AlgorithmIdentifier(PKCSObjectIdentifiers.md5WithRSAEncryption);
- static final String CERT = Credentials.CERTIFICATE;
- static final String PKCS12 = Credentials.PKCS12;
-
private static HashMap<String, String> sCertificateTypeMap;
static {
sCertificateTypeMap = new HashMap<String, String>();
- sCertificateTypeMap.put("application/x-x509-ca-cert", CertTool.CERT);
- sCertificateTypeMap.put("application/x-x509-user-cert", CertTool.CERT);
- sCertificateTypeMap.put("application/x-pkcs12", CertTool.PKCS12);
+ sCertificateTypeMap.put("application/x-x509-ca-cert", KeyChain.EXTRA_CERTIFICATE);
+ sCertificateTypeMap.put("application/x-x509-user-cert", KeyChain.EXTRA_CERTIFICATE);
+ sCertificateTypeMap.put("application/x-pkcs12", KeyChain.EXTRA_PKCS12);
}
static String[] getKeyStrengthList() {
@@ -77,7 +73,7 @@ class CertTool {
static String getCertType(String mimeType) {
return sCertificateTypeMap.get(mimeType);
- }
+ }
private CertTool() {}
}
diff --git a/core/java/android/webkit/HTML5VideoFullScreen.java b/core/java/android/webkit/HTML5VideoFullScreen.java
index 4cae9d80d614..0ea27a0b9f5e 100644
--- a/core/java/android/webkit/HTML5VideoFullScreen.java
+++ b/core/java/android/webkit/HTML5VideoFullScreen.java
@@ -104,9 +104,14 @@ public class HTML5VideoFullScreen extends HTML5VideoView
public void surfaceDestroyed(SurfaceHolder holder)
{
- // after we return from this we can't use the surface any more
- mSurfaceHolder = null;
+ // After we return from this we can't use the surface any more.
// The current Video View will be destroy when we play a new video.
+ pauseAndDispatch(mProxy);
+ mPlayer.release();
+ mSurfaceHolder = null;
+ if (mMediaController != null) {
+ mMediaController.hide();
+ }
}
};
@@ -210,7 +215,6 @@ public class HTML5VideoFullScreen extends HTML5VideoView
// which happens when the video view is detached from its parent
// view. This happens in the WebChromeClient before this method
// is invoked.
- pauseAndDispatch(mProxy);
mProxy.dispatchOnStopFullScreen();
mLayout.removeView(getSurfaceView());
@@ -223,6 +227,10 @@ public class HTML5VideoFullScreen extends HTML5VideoView
mProxy.getWebView().getViewManager().showAll();
mProxy = null;
+
+ // Don't show the controller after exiting the full screen.
+ mMediaController = null;
+ mCurrentState = STATE_RELEASED;
}
};
diff --git a/core/java/android/webkit/HTML5VideoView.java b/core/java/android/webkit/HTML5VideoView.java
index 5983a4444e96..67660b86af02 100644
--- a/core/java/android/webkit/HTML5VideoView.java
+++ b/core/java/android/webkit/HTML5VideoView.java
@@ -34,6 +34,7 @@ public class HTML5VideoView implements MediaPlayer.OnPreparedListener {
static final int STATE_NOTPREPARED = 1;
static final int STATE_PREPARED = 2;
static final int STATE_PLAYING = 3;
+ static final int STATE_RELEASED = 4;
protected int mCurrentState;
protected HTML5VideoViewProxy mProxy;
@@ -84,7 +85,7 @@ public class HTML5VideoView implements MediaPlayer.OnPreparedListener {
}
public void pause() {
- if (mCurrentState == STATE_PREPARED && mPlayer.isPlaying()) {
+ if (isPlaying()) {
mPlayer.pause();
} else if (mCurrentState == STATE_NOTPREPARED) {
mPauseDuringPreparing = true;
@@ -120,11 +121,18 @@ public class HTML5VideoView implements MediaPlayer.OnPreparedListener {
}
public boolean isPlaying() {
- return mPlayer.isPlaying();
+ if (mCurrentState == STATE_PREPARED) {
+ return mPlayer.isPlaying();
+ } else {
+ return false;
+ }
}
public void release() {
- mPlayer.release();
+ if (mCurrentState != STATE_RELEASED) {
+ mPlayer.release();
+ }
+ mCurrentState = STATE_RELEASED;
}
public void stopPlayback() {
@@ -228,7 +236,7 @@ public class HTML5VideoView implements MediaPlayer.OnPreparedListener {
public int getCurrentState() {
- if (mPlayer.isPlaying()) {
+ if (isPlaying()) {
return STATE_PLAYING;
} else {
return mCurrentState;
diff --git a/core/java/android/webkit/L10nUtils.java b/core/java/android/webkit/L10nUtils.java
index 5b4fb1df72de..4c42cde5b693 100644
--- a/core/java/android/webkit/L10nUtils.java
+++ b/core/java/android/webkit/L10nUtils.java
@@ -70,7 +70,11 @@ public class L10nUtils {
com.android.internal.R.string.autofill_expiration_month_re, // IDS_AUTOFILL_EXPIRATION_MONTH_RE
com.android.internal.R.string.autofill_expiration_date_re, // IDS_AUTOFILL_EXPIRATION_DATE_RE
com.android.internal.R.string.autofill_card_ignored_re, // IDS_AUTOFILL_CARD_IGNORED_RE
- com.android.internal.R.string.autofill_fax_re // IDS_AUTOFILL_FAX_RE
+ com.android.internal.R.string.autofill_fax_re, // IDS_AUTOFILL_FAX_RE
+ com.android.internal.R.string.autofill_country_code_re, // IDS_AUTOFILL_COUNTRY_CODE_RE
+ com.android.internal.R.string.autofill_area_code_notext_re, // IDS_AUTOFILL_AREA_CODE_NOTEXT_RE
+ com.android.internal.R.string.autofill_phone_prefix_separator_re, // IDS_AUTOFILL_PHONE_PREFIX_SEPARATOR_RE
+ com.android.internal.R.string.autofill_phone_suffix_separator_re // IDS_AUTOFILL_PHONE_SUFFIX_SEPARATOR_RE
};
private static Context mApplicationContext;
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 7e41d36eee65..4f97066aa381 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -1950,6 +1950,7 @@ public final class WebViewCore {
// mInitialViewState is set by didFirstLayout() and then reset in the
// next webkitDraw after passing the state to the UI thread.
private ViewState mInitialViewState = null;
+ private boolean mFirstLayoutForNonStandardLoad;
static class ViewState {
float mMinScale;
@@ -1977,6 +1978,7 @@ public final class WebViewCore {
int mMinPrefWidth;
// only non-null if it is for the first picture set after the first layout
ViewState mViewState;
+ boolean mFirstLayoutForNonStandardLoad;
boolean mFocusSizeChanged;
}
@@ -2026,6 +2028,10 @@ public final class WebViewCore {
draw.mViewState = mInitialViewState;
mInitialViewState = null;
}
+ if (mFirstLayoutForNonStandardLoad) {
+ draw.mFirstLayoutForNonStandardLoad = true;
+ mFirstLayoutForNonStandardLoad = false;
+ }
if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "webkitDraw NEW_PICTURE_MSG_ID");
Message.obtain(mWebView.mPrivateHandler,
WebView.NEW_PICTURE_MSG_ID, draw).sendToTarget();
@@ -2312,6 +2318,8 @@ public final class WebViewCore {
// if mViewportWidth is 0, it means device-width, always update.
if (mViewportWidth != 0 && !updateViewState) {
+ // For non standard load, since updateViewState will be false.
+ mFirstLayoutForNonStandardLoad = true;
ViewState viewState = new ViewState();
viewState.mMinScale = mViewportMinimumScale / 100.0f;
viewState.mMaxScale = mViewportMaximumScale / 100.0f;
@@ -2471,9 +2479,10 @@ public final class WebViewCore {
// called by JNI
private void restoreScale(float scale, float textWrapScale) {
if (mBrowserFrame.firstLayoutDone() == false) {
- mRestoredScale = scale;
+ final float defaultScale = mWebView.getDefaultZoomScale();
+ mRestoredScale = (scale <= 0.0) ? defaultScale : scale;
if (mSettings.getUseWideViewPort()) {
- mRestoredTextWrapScale = textWrapScale;
+ mRestoredTextWrapScale = (textWrapScale <= 0.0) ? defaultScale : textWrapScale;
}
}
}
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index 883656bd6fae..7d43e94ff695 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -1024,6 +1024,11 @@ class ZoomManager {
} else {
mInZoomOverview = !scaleHasDiff;
}
+ if (drawData.mFirstLayoutForNonStandardLoad && settings.getLoadWithOverviewMode()) {
+ // Set mInitialZoomOverview in case this is the first picture for non standard load,
+ // so next new picture could be forced into overview mode if it's true.
+ mInitialZoomOverview = mInZoomOverview;
+ }
}
/**
@@ -1107,7 +1112,8 @@ class ZoomManager {
}
reflowText = exceedsMinScaleIncrement(mTextWrapScale, scale);
}
- mInitialZoomOverview = !exceedsMinScaleIncrement(scale, overviewScale);
+ mInitialZoomOverview = settings.getLoadWithOverviewMode() &&
+ !exceedsMinScaleIncrement(scale, overviewScale);
setZoomScale(scale, reflowText);
// update the zoom buttons as the scale can be changed
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 15702244596f..7c0470e17434 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -24,6 +24,7 @@ import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.Pair;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
@@ -33,7 +34,6 @@ import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
-import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -67,7 +67,7 @@ import static java.lang.Math.min;
*
* <h4>Default Cell Assignment</h4>
*
- * If no child specifies the row and column indices of the cell it
+ * If a child does not specify the row and column indices of the cell it
* wishes to occupy, GridLayout assigns cell locations automatically using its:
* {@link GridLayout#setOrientation(int) orientation},
* {@link GridLayout#setRowCount(int) rowCount} and
@@ -94,8 +94,8 @@ import static java.lang.Math.min;
*
* Like {@link LinearLayout}, a child's ability to stretch is controlled
* using <em>weights</em>, which are specified using the
- * {@link GridLayout.LayoutParams#rowWeight rowWeight} and
- * {@link GridLayout.LayoutParams#columnWeight columnWeight} layout parameters.
+ * {@link GridLayout.LayoutParams#widthSpec widthSpec} and
+ * {@link GridLayout.LayoutParams#heightSpec heightSpec} layout parameters.
* <p>
* <p>
* See {@link GridLayout.LayoutParams} for a full description of the
@@ -171,9 +171,7 @@ public class GridLayout extends ViewGroup {
private static final String TAG = GridLayout.class.getName();
private static final boolean DEBUG = false;
private static final double GOLDEN_RATIO = (1 + Math.sqrt(5)) / 2;
- private static final int MIN = 0;
private static final int PRF = 1;
- private static final int MAX = 2;
// Defaults
@@ -184,6 +182,7 @@ public class GridLayout extends ViewGroup {
private static final int DEFAULT_ALIGNMENT_MODE = ALIGN_MARGINS;
// todo remove this
private static final int DEFAULT_CONTAINER_MARGIN = 20;
+ private static final int MAX_SIZE = 100000;
// TypedArray indices
@@ -205,36 +204,16 @@ public class GridLayout extends ViewGroup {
private int mAlignmentMode = DEFAULT_ALIGNMENT_MODE;
private int mDefaultGravity = Gravity.NO_GRAVITY;
- /* package */ boolean accommodateBothMinAndMax = false;
-
// Constructors
/**
* {@inheritDoc}
*/
- public GridLayout(Context context) {
- this(context, null, 0);
- }
-
- /**
- * {@inheritDoc}
- */
public GridLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
if (DEBUG) {
setWillNotDraw(false);
}
- processAttributes(context, attrs);
- }
-
- /**
- * {@inheritDoc}
- */
- public GridLayout(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- private void processAttributes(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(attrs, styleable.GridLayout);
try {
setRowCount(a.getInt(ROW_COUNT, DEFAULT_COUNT));
@@ -249,6 +228,20 @@ public class GridLayout extends ViewGroup {
}
}
+ /**
+ * {@inheritDoc}
+ */
+ public GridLayout(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public GridLayout(Context context) {
+ this(context, null);
+ }
+
// Implementation
/**
@@ -527,11 +520,10 @@ public class GridLayout extends ViewGroup {
return result;
}
- private static int sum(float[] a) {
- int result = 0;
- for (int i = 0, length = a.length; i < length; i++) {
- result += a[i];
- }
+ private static <T> T[] append(T[] a, T[] b) {
+ T[] result = (T[]) Array.newInstance(a.getClass().getComponentType(), a.length + b.length);
+ System.arraycopy(a, 0, result, 0, a.length);
+ System.arraycopy(b, 0, result, a.length, b.length);
return result;
}
@@ -603,13 +595,13 @@ public class GridLayout extends ViewGroup {
if (isGone(c)) continue;
LayoutParams lp = getLayoutParams1(c);
- Group colGroup = lp.columnGroup;
- Interval cols = colGroup.span;
- int colSpan = cols.size();
+ final Group colGroup = lp.columnGroup;
+ final Interval cols = colGroup.span;
+ final int colSpan = cols.size();
- Group rowGroup = lp.rowGroup;
- Interval rows = rowGroup.span;
- int rowSpan = rows.size();
+ final Group rowGroup = lp.rowGroup;
+ final Interval rows = rowGroup.span;
+ final int rowSpan = rows.size();
if (horizontal) {
row = valueIfDefined2(rows.min, row);
@@ -700,8 +692,8 @@ public class GridLayout extends ViewGroup {
}
private void drawRectangle(Canvas graphics, int x1, int y1, int x2, int y2, Paint paint) {
- // x2 = x2 - 1;
- // y2 = y2 - 1;
+ x2 = x2 - 1;
+ y2 = y2 - 1;
graphics.drawLine(x1, y1, x1, y2, paint);
graphics.drawLine(x1, y1, x2, y1, paint);
graphics.drawLine(x1, y2, x2, y2, paint);
@@ -734,9 +726,9 @@ public class GridLayout extends ViewGroup {
drawLine(canvas, 0, y, width - 1, y, paint);
}
}
+
// Draw bounds
paint.setColor(Color.BLUE);
-
for (int i = 0; i < getChildCount(); i++) {
View c = getChildAt(i);
drawRectangle(canvas,
@@ -748,7 +740,6 @@ public class GridLayout extends ViewGroup {
// Draw margins
paint.setColor(Color.YELLOW);
-
for (int i = 0; i < getChildCount(); i++) {
View c = getChildAt(i);
drawRectangle(canvas,
@@ -819,11 +810,11 @@ public class GridLayout extends ViewGroup {
protected void onMeasure(int widthSpec, int heightSpec) {
measureChildrenWithMargins(widthSpec, heightSpec);
- int computedWidth = getPaddingLeft() + mHorizontalAxis.getMin() + getPaddingRight();
- int computedHeight = getPaddingTop() + mVerticalAxis.getMin() + getPaddingBottom();
+ int width = getPaddingLeft() + mHorizontalAxis.getMeasure(widthSpec) + getPaddingRight();
+ int height = getPaddingTop() + mVerticalAxis.getMeasure(heightSpec) + getPaddingBottom();
- int measuredWidth = Math.max(computedWidth, getSuggestedMinimumWidth());
- int measuredHeight = Math.max(computedHeight, getSuggestedMinimumHeight());
+ int measuredWidth = Math.max(width, getSuggestedMinimumWidth());
+ int measuredHeight = Math.max(height, getSuggestedMinimumHeight());
setMeasuredDimension(
resolveSizeAndState(measuredWidth, widthSpec, 0),
@@ -834,12 +825,12 @@ public class GridLayout extends ViewGroup {
return (alignment == UNDEFINED) ? 0 : alignment;
}
- private int getMeasurement(View c, boolean horizontal, int measurementType) {
+ private int getMeasurement(View c, boolean horizontal) {
return horizontal ? c.getMeasuredWidth() : c.getMeasuredHeight();
}
- private int getMeasurementIncludingMargin(View c, boolean horizontal, int measurementType) {
- int result = getMeasurement(c, horizontal, measurementType);
+ private int getMeasurementIncludingMargin(View c, boolean horizontal) {
+ int result = getMeasurement(c, horizontal);
if (mAlignmentMode == ALIGN_MARGINS) {
return result + getTotalMargin(c, horizontal);
}
@@ -889,17 +880,17 @@ public class GridLayout extends ViewGroup {
Interval colSpan = columnGroup.span;
Interval rowSpan = rowGroup.span;
- int x1 = mHorizontalAxis.getLocationIncludingMargin(c, true, colSpan.min);
- int y1 = mVerticalAxis.getLocationIncludingMargin(c, true, rowSpan.min);
+ int x1 = mHorizontalAxis.getLocationIncludingMargin(true, colSpan.min);
+ int y1 = mVerticalAxis.getLocationIncludingMargin(true, rowSpan.min);
- int x2 = mHorizontalAxis.getLocationIncludingMargin(c, false, colSpan.max);
- int y2 = mVerticalAxis.getLocationIncludingMargin(c, false, rowSpan.max);
+ int x2 = mHorizontalAxis.getLocationIncludingMargin(false, colSpan.max);
+ int y2 = mVerticalAxis.getLocationIncludingMargin(false, rowSpan.max);
int cellWidth = x2 - x1;
int cellHeight = y2 - y1;
- int pWidth = getMeasurement(c, true, PRF);
- int pHeight = getMeasurement(c, false, PRF);
+ int pWidth = getMeasurement(c, true);
+ int pHeight = getMeasurement(c, false);
Alignment hAlign = columnGroup.alignment;
Alignment vAlign = rowGroup.alignment;
@@ -910,9 +901,8 @@ public class GridLayout extends ViewGroup {
Bounds rowBounds = mVerticalAxis.getGroupBounds().getValue(i);
// Gravity offsets: the location of the alignment group relative to its cell group.
- int type = PRF;
- int c2ax = protect(hAlign.getAlignmentValue(null, cellWidth - colBounds.size(), type));
- int c2ay = protect(vAlign.getAlignmentValue(null, cellHeight - rowBounds.size(), type));
+ int c2ax = protect(hAlign.getAlignmentValue(null, cellWidth - colBounds.size(true)));
+ int c2ay = protect(vAlign.getAlignmentValue(null, cellHeight - rowBounds.size(true)));
if (mAlignmentMode == ALIGN_MARGINS) {
int leftMargin = getMargin(c, true, true);
@@ -925,8 +915,8 @@ public class GridLayout extends ViewGroup {
int mHeight = topMargin + pHeight + bottomMargin;
// Alignment offsets: the location of the view relative to its alignment group.
- int a2vx = colBounds.getOffset(c, hAlign, type, mWidth);
- int a2vy = rowBounds.getOffset(c, vAlign, type, mHeight);
+ int a2vx = colBounds.getOffset(c, hAlign, mWidth);
+ int a2vy = rowBounds.getOffset(c, vAlign, mHeight);
dx = c2ax + a2vx + leftMargin;
dy = c2ay + a2vy + topMargin;
@@ -935,13 +925,14 @@ public class GridLayout extends ViewGroup {
cellHeight -= topMargin + bottomMargin;
} else {
// Alignment offsets: the location of the view relative to its alignment group.
- int a2vx = colBounds.getOffset(c, hAlign, type, pWidth);
- int a2vy = rowBounds.getOffset(c, vAlign, type, pHeight);
+ int a2vx = colBounds.getOffset(c, hAlign, pWidth);
+ int a2vy = rowBounds.getOffset(c, vAlign, pHeight);
dx = c2ax + a2vx;
dy = c2ay + a2vy;
}
+ int type = PRF;
int width = hAlign.getSizeInCell(c, pWidth, cellWidth, type);
int height = vAlign.getSizeInCell(c, pHeight, cellHeight, type);
@@ -962,7 +953,7 @@ public class GridLayout extends ViewGroup {
private class Axis {
private static final int MIN_VALUE = -1000000;
- private static final int UNVISITED = 0;
+ private static final int NEW = 0;
private static final int PENDING = 1;
private static final int COMPLETE = 2;
@@ -975,8 +966,11 @@ public class GridLayout extends ViewGroup {
PackedMap<Group, Bounds> groupBounds;
public boolean groupBoundsValid = false;
- PackedMap<Interval, MutableInt> spanSizes;
- public boolean spanSizesValid = false;
+ PackedMap<Interval, MutableInt> forwardLinks;
+ public boolean forwardLinksValid = false;
+
+ PackedMap<Interval, MutableInt> backwardLinks;
+ public boolean backwardLinksValid = false;
public int[] leadingMargins;
public boolean leadingMarginsValid = false;
@@ -987,14 +981,14 @@ public class GridLayout extends ViewGroup {
public Arc[] arcs;
public boolean arcsValid = false;
- public int[] minima;
- public boolean minimaValid = false;
-
- public float[] weights;
public int[] locations;
+ public boolean locationsValid = false;
private boolean mOrderPreserved = DEFAULT_ORDER_PRESERVED;
+ private MutableInt parentMin = new MutableInt(0);
+ private MutableInt parentMax = new MutableInt(-MAX_SIZE);
+
private Axis(boolean horizontal) {
this.horizontal = horizontal;
}
@@ -1036,22 +1030,19 @@ public class GridLayout extends ViewGroup {
}
private PackedMap<Group, Bounds> createGroupBounds() {
- int N = getChildCount();
- Group[] groups = new Group[N];
- Arrays.fill(groups, Group.GONE);
- Bounds[] bounds = new Bounds[N];
- Arrays.fill(bounds, Bounds.GONE);
- for (int i = 0; i < N; i++) {
+ Assoc<Group, Bounds> assoc = Assoc.of(Group.class, Bounds.class);
+ for (int i = 0, N = getChildCount(); i < N; i++) {
View c = getChildAt(i);
- if (isGone(c)) continue;
- LayoutParams lp = getLayoutParams(c);
- Group group = horizontal ? lp.columnGroup : lp.rowGroup;
-
- groups[i] = group;
- bounds[i] = group.alignment.getBounds();
+ if (isGone(c)) {
+ assoc.put(Group.GONE, Bounds.GONE);
+ } else {
+ LayoutParams lp = getLayoutParams(c);
+ Group group = horizontal ? lp.columnGroup : lp.rowGroup;
+ Bounds bounds = group.alignment.getBounds();
+ assoc.put(group, bounds);
+ }
}
-
- return new PackedMap<Group, Bounds>(groups, bounds);
+ return assoc.pack();
}
private void computeGroupBounds() {
@@ -1064,13 +1055,7 @@ public class GridLayout extends ViewGroup {
if (isGone(c)) continue;
LayoutParams lp = getLayoutParams(c);
Group g = horizontal ? lp.columnGroup : lp.rowGroup;
-
- Bounds bounds = groupBounds.getValue(i);
-
- int size = getMeasurementIncludingMargin(c, horizontal, PRF);
- // todo test this works correctly when the returned value is UNDEFINED
- int before = g.alignment.getAlignmentValue(c, size, PRF);
- bounds.include(before, size - before);
+ groupBounds.getValue(i).include(c, g, GridLayout.this, this, lp);
}
}
@@ -1086,80 +1071,91 @@ public class GridLayout extends ViewGroup {
}
// Add values computed by alignment - taking the max of all alignments in each span
- private PackedMap<Interval, MutableInt> createSpanSizes() {
- PackedMap<Group, Bounds> groupBounds = getGroupBounds();
- int N = groupBounds.keys.length;
- Interval[] spans = new Interval[N];
- MutableInt[] values = new MutableInt[N];
- for (int i = 0; i < N; i++) {
- Interval key = groupBounds.keys[i].span;
-
- spans[i] = key;
- values[i] = new MutableInt();
+ private PackedMap<Interval, MutableInt> createLinks(boolean min) {
+ Assoc<Interval, MutableInt> result = Assoc.of(Interval.class, MutableInt.class);
+ Group[] keys = getGroupBounds().keys;
+ for (int i = 0, N = keys.length; i < N; i++) {
+ Interval span = min ? keys[i].span : keys[i].span.inverse();
+ result.put(span, new MutableInt());
}
- return new PackedMap<Interval, MutableInt>(spans, values);
+ return result.pack();
}
- private void computeSpanSizes() {
- MutableInt[] spans = spanSizes.values;
+ private void computeLinks(PackedMap<Interval, MutableInt> links, boolean min) {
+ MutableInt[] spans = links.values;
for (int i = 0; i < spans.length; i++) {
spans[i].reset();
}
- Bounds[] bounds = getGroupBounds().values; // use getter to trigger a re-evaluation
+ // use getter to trigger a re-evaluation
+ Bounds[] bounds = getGroupBounds().values;
for (int i = 0; i < bounds.length; i++) {
- int value = bounds[i].size();
-
- MutableInt valueHolder = spanSizes.getValue(i);
+ int size = bounds[i].size(min);
+ int value = min ? size : -size;
+ MutableInt valueHolder = links.getValue(i);
valueHolder.value = max(valueHolder.value, value);
}
}
- private PackedMap<Interval, MutableInt> getSpanSizes() {
- if (spanSizes == null) {
- spanSizes = createSpanSizes();
+ private PackedMap<Interval, MutableInt> getForwardLinks() {
+ if (forwardLinks == null) {
+ forwardLinks = createLinks(true);
}
- if (!spanSizesValid) {
- computeSpanSizes();
- spanSizesValid = true;
+ if (!forwardLinksValid) {
+ computeLinks(forwardLinks, true);
+ forwardLinksValid = true;
}
- return spanSizes;
+ return forwardLinks;
}
- private void include(List<Arc> arcs, Interval key, MutableInt size) {
- // this bit below should really be computed outside here -
- // its just to stop default (col>0) constraints obliterating valid entries
- for (Arc arc : arcs) {
- Interval span = arc.span;
- if (span.equals(key)) {
- return;
- }
+ private PackedMap<Interval, MutableInt> getBackwardLinks() {
+ if (backwardLinks == null) {
+ backwardLinks = createLinks(false);
}
- arcs.add(new Arc(key, size));
+ if (!backwardLinksValid) {
+ computeLinks(backwardLinks, false);
+ backwardLinksValid = true;
+ }
+ return backwardLinks;
}
- private void include2(List<Arc> arcs, Interval span, MutableInt min, MutableInt max,
- boolean both) {
- include(arcs, span, min);
- if (both) {
- // todo
-// include(arcs, span.inverse(), max.neg());
+ private void include(List<Arc> arcs, Interval key, MutableInt size,
+ boolean ignoreIfAlreadyPresent) {
+ /*
+ Remove self referential links.
+ These appear:
+ . as parental constraints when GridLayout has no children
+ . when components have been marked as GONE
+ */
+ if (key.size() == 0) {
+ return;
}
+ // this bit below should really be computed outside here -
+ // its just to stop default (row/col > 0) constraints obliterating valid entries
+ if (ignoreIfAlreadyPresent) {
+ for (Arc arc : arcs) {
+ Interval span = arc.span;
+ if (span.equals(key)) {
+ return;
+ }
+ }
+ }
+ arcs.add(new Arc(key, size));
}
- private void include2(List<Arc> arcs, Interval span, int min, int max, boolean both) {
- include2(arcs, span, new MutableInt(min), new MutableInt(max), both);
+ private void include(List<Arc> arcs, Interval key, MutableInt size) {
+ include(arcs, key, size, true);
}
// Group arcs by their first vertex, returning an array of arrays.
// This is linear in the number of arcs.
private Arc[][] groupArcsByFirstVertex(Arc[] arcs) {
- int N = getCount() + 1;// the number of vertices
+ int N = getCount() + 1; // the number of vertices
Arc[][] result = new Arc[N][];
int[] sizes = new int[N];
for (Arc arc : arcs) {
sizes[arc.span.min]++;
- }
+ }
for (int i = 0; i < sizes.length; i++) {
result[i] = new Arc[sizes[i]];
}
@@ -1173,38 +1169,46 @@ public class GridLayout extends ViewGroup {
return result;
}
- private Arc[] topologicalSort(final Arc[] arcs, int start) {
- // todo ensure the <start> vertex is added in edge cases
- final List<Arc> result = new ArrayList<Arc>();
- new Object() {
- Arc[][] arcsByFirstVertex = groupArcsByFirstVertex(arcs);
+ private Arc[] topologicalSort(final Arc[] arcs) {
+ return new Object() {
+ Arc[] result = new Arc[arcs.length];
+ int cursor = result.length - 1;
+ Arc[][] arcsByVertex = groupArcsByFirstVertex(arcs);
int[] visited = new int[getCount() + 1];
- boolean completesCycle(int loc) {
- int state = visited[loc];
- if (state == UNVISITED) {
- visited[loc] = PENDING;
- for (Arc arc : arcsByFirstVertex[loc]) {
- Interval span = arc.span;
- // the recursive call
- if (completesCycle(span.max)) {
- // which arcs get set here is dependent on the order
- // in which we explore nodes
- arc.completesCycle = true;
+ void walk(int loc) {
+ switch (visited[loc]) {
+ case NEW: {
+ visited[loc] = PENDING;
+ for (Arc arc : arcsByVertex[loc]) {
+ walk(arc.span.max);
+ result[cursor--] = arc;
}
- result.add(arc);
+ visited[loc] = COMPLETE;
+ break;
+ }
+ case PENDING: {
+ assert false;
+ break;
+ }
+ case COMPLETE: {
+ break;
}
- visited[loc] = COMPLETE;
- } else if (state == PENDING) {
- return true;
- } else if (state == COMPLETE) {
}
- return false;
}
- }.completesCycle(start);
- Collections.reverse(result);
- assert arcs.length == result.size();
- return result.toArray(new Arc[result.size()]);
+
+ Arc[] sort() {
+ for (int loc = 0, N = arcsByVertex.length; loc < N; loc++) {
+ walk(loc);
+ }
+ assert cursor == -1;
+ return result;
+ }
+ }.sort();
+ }
+
+ private Arc[] topologicalSort(List<Arc> arcs) {
+ return topologicalSort(arcs.toArray(new Arc[arcs.size()]));
}
private boolean[] findUsed(Collection<Arc> arcs) {
@@ -1254,43 +1258,64 @@ public class GridLayout extends ViewGroup {
return result;
}
+ private void addComponentSizes(List<Arc> result, PackedMap<Interval, MutableInt> links) {
+ for (int i = 0; i < links.keys.length; i++) {
+ Interval key = links.keys[i];
+ include(result, key, links.values[i], false);
+ }
+ }
+
private Arc[] createArcs() {
- List<Arc> result = new ArrayList<Arc>();
+ List<Arc> mins = new ArrayList<Arc>();
+ List<Arc> maxs = new ArrayList<Arc>();
- // Add all the preferred elements that were not defined by the user.
- PackedMap<Interval, MutableInt> spanSizes = getSpanSizes();
- for (int i = 0; i < spanSizes.keys.length; i++) {
- Interval key = spanSizes.keys[i];
- if (key == Interval.GONE) continue;
- MutableInt value = spanSizes.values[i];
- // todo remove value duplicate
- include2(result, key, value, value, accommodateBothMinAndMax);
- }
+ // Add the minimum values from the components.
+ addComponentSizes(mins, getForwardLinks());
+ // Add the maximum values from the components.
+ addComponentSizes(maxs, getBackwardLinks());
// Find redundant rows/cols and glue them together with 0-length arcs to link the tree
- boolean[] used = findUsed(result);
+ boolean[] used = findUsed(mins);
for (int i = 0; i < getCount(); i++) {
if (!used[i]) {
Interval span = new Interval(i, i + 1);
- include(result, span, new MutableInt(0));
- include(result, span.inverse(), new MutableInt(0));
+ include(mins, span, new MutableInt(0));
+ include(maxs, span.inverse(), new MutableInt(0));
}
}
+ // Add ordering constraints to prevent row/col sizes from going negative
if (mOrderPreserved) {
- // Add preferred gaps
+ // Add a constraint for every row/col
for (int i = 0; i < getCount(); i++) {
if (used[i]) {
- include2(result, new Interval(i, i + 1), 0, 0, false);
+ include(mins, new Interval(i, i + 1), new MutableInt(0));
}
}
} else {
+ // Add a constraint for each row/col that separates opposing component edges
for (Interval gap : getSpacers()) {
- include2(result, gap, 0, 0, false);
+ include(mins, gap, new MutableInt(0));
}
}
- Arc[] arcs = result.toArray(new Arc[result.size()]);
- return topologicalSort(arcs, 0);
+
+ // Add the container constraints. Use the version of include that allows
+ // duplicate entries in case a child spans the entire grid.
+ int N = getCount();
+ include(mins, new Interval(0, N), parentMin, false);
+ include(maxs, new Interval(N, 0), parentMax, false);
+
+ // Sort
+ Arc[] sMins = topologicalSort(mins);
+ Arc[] sMaxs = topologicalSort(maxs);
+
+ return append(sMins, sMaxs);
+ }
+
+ private void computeArcs() {
+ // getting the links validates the values that are shared by the arc list
+ getForwardLinks();
+ getBackwardLinks();
}
public Arc[] getArcs() {
@@ -1298,13 +1323,16 @@ public class GridLayout extends ViewGroup {
arcs = createArcs();
}
if (!arcsValid) {
- getSpanSizes();
+ computeArcs();
arcsValid = true;
}
return arcs;
}
private boolean relax(int[] locations, Arc entry) {
+ if (!entry.valid) {
+ return false;
+ }
Interval span = entry.span;
int u = span.min;
int v = span.max;
@@ -1351,7 +1379,8 @@ public class GridLayout extends ViewGroup {
typical layout problems complete after the first iteration and the algorithm
completes in O(N) steps with very low constants.
*/
- private int[] solve(Arc[] arcs, int[] locations) {
+ private void solve(Arc[] arcs, int[] locations) {
+ String axis = horizontal ? "horizontal" : "vertical";
int N = getCount() + 1; // The number of vertices is the number of columns/rows + 1.
boolean changed = false;
@@ -1359,20 +1388,44 @@ public class GridLayout extends ViewGroup {
for (int i = 0; i < N; i++) {
changed = false;
for (int j = 0, length = arcs.length; j < length; j++) {
- changed = changed | relax(locations, arcs[j]);
+ changed |= relax(locations, arcs[j]);
}
if (!changed) {
if (DEBUG) {
- Log.d(TAG, "Iteration " +
- " completed after " + (1 + i) + " steps out of " + N);
+ Log.d(TAG, axis + " iteration completed in " + (1 + i) + " steps of " + N);
}
- break;
+ return;
}
}
- if (changed) {
- Log.d(TAG, "*** Algorithm failed to terminate ***");
+
+ Log.d(TAG, "The " + axis + " constraints contained a contradiction. Resolving... ");
+ Log.d(TAG, Arrays.toString(arcs));
+
+ boolean[] culprits = new boolean[arcs.length];
+ for (int i = 0; i < N; i++) {
+ for (int j = 0, length = arcs.length; j < length; j++) {
+ culprits[j] |= relax(locations, arcs[j]);
+ }
}
- return locations;
+ for (int i = 0; i < culprits.length; i++) {
+ if (culprits[i]) {
+ Arc arc = arcs[i];
+ // Only remove max values, min values alone cannot be inconsistent
+ if (arc.span.min < arc.span.max) {
+ continue;
+ }
+ Log.d(TAG, "Removing: " + arc);
+ arc.valid = false;
+ break;
+ }
+ }
+ solve1(arcs, locations);
+ }
+
+ private void solve1(Arc[] arcs, int[] a) {
+ Arrays.fill(a, MIN_VALUE);
+ a[0] = 0;
+ solve(arcs, a);
}
private void computeMargins(boolean leading) {
@@ -1418,11 +1471,11 @@ public class GridLayout extends ViewGroup {
for (int i = 0, N = getCount(); i < N; i++) {
int margins = leadingMargins[i] + trailingMargins[i + 1];
delta += margins;
- minima[i + 1] += delta;
+ locations[i + 1] += delta;
}
}
- private int getLocationIncludingMargin(View view, boolean leading, int index) {
+ private int getLocationIncludingMargin(boolean leading, int index) {
int location = locations[index];
int margin;
if (mAlignmentMode != ALIGN_MARGINS) {
@@ -1433,53 +1486,22 @@ public class GridLayout extends ViewGroup {
return leading ? (location + margin) : (location - margin);
}
- private void computeMinima(int[] a) {
- Arrays.fill(a, MIN_VALUE);
- a[0] = 0;
- solve(getArcs(), a);
+ private void computeLocations(int[] a) {
+ solve1(getArcs(), a);
if (mAlignmentMode != ALIGN_MARGINS) {
addMargins();
}
}
- private int[] getMinima() {
- if (minima == null) {
- int N = getCount() + 1;
- minima = new int[N];
- }
- if (!minimaValid) {
- computeMinima(minima);
- minimaValid = true;
- }
- return minima;
- }
-
- private void computeWeights() {
- for (int i = 0, N = getChildCount(); i < N; i++) {
- View c = getChildAt(i);
- if (isGone(c)) continue;
- LayoutParams lp = getLayoutParams(c);
- Group g = horizontal ? lp.columnGroup : lp.rowGroup;
- Interval span = g.span;
- int penultimateIndex = span.max - 1;
- weights[penultimateIndex] += horizontal ? lp.columnWeight : lp.rowWeight;
- }
- }
-
- private float[] getWeights() {
- if (weights == null) {
- int N = getCount();
- weights = new float[N];
- }
- computeWeights();
- return weights;
- }
-
private int[] getLocations() {
if (locations == null) {
int N = getCount() + 1;
locations = new int[N];
}
+ if (!locationsValid) {
+ computeLocations(locations);
+ locationsValid = true;
+ }
return locations;
}
@@ -1489,48 +1511,53 @@ public class GridLayout extends ViewGroup {
return max2(locations, 0) - locations[0];
}
- private int getMin() {
- return size(getMinima());
+ private void setParentConstraints(int min, int max) {
+ parentMin.value = min;
+ parentMax.value = -max;
+ locationsValid = false;
}
- private void layout(int targetSize) {
- int[] mins = getMinima();
-
- int totalDelta = max(0, targetSize - size(mins)); // confine to expansion
-
- float[] weights = getWeights();
- float totalWeight = sum(weights);
+ private int getMeasure(int min, int max) {
+ setParentConstraints(min, max);
+ return size(getLocations());
+ }
- if (totalWeight == 0f && weights.length > 0) {
- weights[weights.length - 1] = 1;
- totalWeight = 1;
+ private int getMeasure(int measureSpec) {
+ int mode = MeasureSpec.getMode(measureSpec);
+ int size = MeasureSpec.getSize(measureSpec);
+ switch (mode) {
+ case MeasureSpec.UNSPECIFIED: {
+ return getMeasure(0, MAX_SIZE);
+ }
+ case MeasureSpec.EXACTLY: {
+ return getMeasure(size, size);
+ }
+ case MeasureSpec.AT_MOST: {
+ return getMeasure(0, size);
+ }
+ default: {
+ assert false;
+ return 0;
+ }
}
+ }
- int[] locations = getLocations();
- int cumulativeDelta = 0;
-
- // note |weights| = |locations| - 1
- for (int i = 0; i < weights.length; i++) {
- float weight = weights[i];
- int delta = (int) (totalDelta * weight / totalWeight);
- cumulativeDelta += delta;
- locations[i + 1] = mins[i + 1] + cumulativeDelta;
-
- totalDelta -= delta;
- totalWeight -= weight;
- }
+ private void layout(int size) {
+ setParentConstraints(size, size);
+ getLocations();
}
private void invalidateStructure() {
countValid = false;
groupBounds = null;
- spanSizes = null;
+ forwardLinks = null;
+ backwardLinks = null;
+
leadingMargins = null;
trailingMargins = null;
arcs = null;
- minima = null;
- weights = null;
+
locations = null;
invalidateValues();
@@ -1538,11 +1565,14 @@ public class GridLayout extends ViewGroup {
private void invalidateValues() {
groupBoundsValid = false;
- spanSizesValid = false;
- arcsValid = false;
+ forwardLinksValid = false;
+ backwardLinksValid = false;
+
leadingMarginsValid = false;
trailingMarginsValid = false;
- minimaValid = false;
+ arcsValid = false;
+
+ locationsValid = false;
}
}
@@ -1592,16 +1622,16 @@ public class GridLayout extends ViewGroup {
* <li>{@link #rowGroup}{@code .alignment} = {@link #BASELINE} </li>
* <li>{@link #columnGroup}{@code .span} = {@code [0, 1]} </li>
* <li>{@link #columnGroup}{@code .alignment} = {@link #LEFT} </li>
- * <li>{@link #rowWeight} = {@code 0f} </li>
- * <li>{@link #columnWeight} = {@code 0f} </li>
+ * <li>{@link #widthSpec} = {@link #FIXED} </li>
+ * <li>{@link #heightSpec} = {@link #FIXED} </li>
* </ul>
*
* @attr ref android.R.styleable#GridLayout_Layout_layout_row
* @attr ref android.R.styleable#GridLayout_Layout_layout_rowSpan
- * @attr ref android.R.styleable#GridLayout_Layout_layout_rowWeight
+ * @attr ref android.R.styleable#GridLayout_Layout_layout_heightSpec
* @attr ref android.R.styleable#GridLayout_Layout_layout_column
* @attr ref android.R.styleable#GridLayout_Layout_layout_columnSpan
- * @attr ref android.R.styleable#GridLayout_Layout_layout_columnWeight
+ * @attr ref android.R.styleable#GridLayout_Layout_layout_widthSpec
* @attr ref android.R.styleable#GridLayout_Layout_layout_gravity
*/
public static class LayoutParams extends MarginLayoutParams {
@@ -1621,14 +1651,15 @@ public class GridLayout extends ViewGroup {
new Group(DEFAULT_SPAN, DEFAULT_COLUMN_ALIGNMENT);
private static final Group DEFAULT_ROW_GROUP =
new Group(DEFAULT_SPAN, DEFAULT_ROW_ALIGNMENT);
- private static final int DEFAULT_WEIGHT_0 = 0;
- private static final int DEFAULT_WEIGHT_1 = 1;
+ private static final Spec DEFAULT_SPEC = FIXED;
+ private static final int DEFAULT_SPEC_INDEX = 0;
// Misc
private static final Rect CONTAINER_BOUNDS = new Rect(0, 0, 2, 2);
private static final Alignment[] COLUMN_ALIGNMENTS = { LEFT, CENTER, RIGHT };
private static final Alignment[] ROW_ALIGNMENTS = { TOP, CENTER, BOTTOM };
+ private static final Spec[] SPECS = { FIXED, CAN_SHRINK, CAN_STRETCH };
// TypedArray indices
@@ -1641,10 +1672,10 @@ public class GridLayout extends ViewGroup {
private static final int COLUMN = styleable.GridLayout_Layout_layout_column;
private static final int COLUMN_SPAN = styleable.GridLayout_Layout_layout_columnSpan;
- private static final int COLUMN_WEIGHT = styleable.GridLayout_Layout_layout_columnWeight;
+ private static final int WIDTH_SPEC = styleable.GridLayout_Layout_layout_widthSpec;
private static final int ROW = styleable.GridLayout_Layout_layout_row;
private static final int ROW_SPAN = styleable.GridLayout_Layout_layout_rowSpan;
- private static final int ROW_WEIGHT = styleable.GridLayout_Layout_layout_rowWeight;
+ private static final int HEIGHT_SPEC = styleable.GridLayout_Layout_layout_heightSpec;
private static final int GRAVITY = styleable.GridLayout_Layout_layout_gravity;
// Instance variables
@@ -1660,28 +1691,29 @@ public class GridLayout extends ViewGroup {
*/
public Group columnGroup;
/**
- * The proportional space that should be taken by the associated row group
+ * The proportional space that should be taken by the associated column group
* during excess space distribution.
*/
- public float rowWeight;
+ public Spec widthSpec;
/**
- * The proportional space that should be taken by the associated column group
+ * The proportional space that should be taken by the associated row group
* during excess space distribution.
*/
- public float columnWeight;
+ public Spec heightSpec;
// Constructors
private LayoutParams(
int width, int height,
int left, int top, int right, int bottom,
- Group rowGroup, Group columnGroup, float rowWeight, float columnWeight) {
+ Group rowGroup, Group columnGroup,
+ Spec widthSpec, Spec heightSpec) {
super(width, height);
setMargins(left, top, right, bottom);
this.rowGroup = rowGroup;
this.columnGroup = columnGroup;
- this.rowWeight = rowWeight;
- this.columnWeight = columnWeight;
+ this.heightSpec = heightSpec;
+ this.widthSpec = widthSpec;
}
/**
@@ -1695,7 +1727,7 @@ public class GridLayout extends ViewGroup {
public LayoutParams(Group rowGroup, Group columnGroup) {
this(DEFAULT_WIDTH, DEFAULT_HEIGHT,
DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN, DEFAULT_MARGIN,
- rowGroup, columnGroup, DEFAULT_WEIGHT_0, DEFAULT_WEIGHT_0);
+ rowGroup, columnGroup, DEFAULT_SPEC, DEFAULT_SPEC);
}
/**
@@ -1728,8 +1760,8 @@ public class GridLayout extends ViewGroup {
super(that);
this.columnGroup = that.columnGroup;
this.rowGroup = that.rowGroup;
- this.columnWeight = that.columnWeight;
- this.rowWeight = that.rowWeight;
+ this.widthSpec = that.widthSpec;
+ this.heightSpec = that.heightSpec;
}
// AttributeSet constructors
@@ -1813,11 +1845,6 @@ public class GridLayout extends ViewGroup {
!definesVertical(gravity), defaultAlignment);
}
- private int getDefaultWeight(int size) {
- //return (size == MATCH_PARENT) ? DEFAULT_WEIGHT_1 : DEFAULT_WEIGHT_0;
- return DEFAULT_WEIGHT_0;
- }
-
private void init(Context context, AttributeSet attrs, int defaultGravity) {
TypedArray a = context.obtainStyledAttributes(attrs, styleable.GridLayout_Layout);
try {
@@ -1827,13 +1854,13 @@ public class GridLayout extends ViewGroup {
int columnSpan = a.getInt(COLUMN_SPAN, DEFAULT_SPAN_SIZE);
Interval hSpan = new Interval(column, column + columnSpan);
this.columnGroup = new Group(hSpan, getColumnAlignment(gravity, width));
- this.columnWeight = a.getFloat(COLUMN_WEIGHT, getDefaultWeight(width));
+ this.widthSpec = SPECS[a.getInt(WIDTH_SPEC, DEFAULT_SPEC_INDEX)];
int row = a.getInt(ROW, DEFAULT_ROW);
int rowSpan = a.getInt(ROW_SPAN, DEFAULT_SPAN_SIZE);
Interval vSpan = new Interval(row, row + rowSpan);
this.rowGroup = new Group(vSpan, getRowAlignment(gravity, height));
- this.rowWeight = a.getFloat(ROW_WEIGHT, getDefaultWeight(height));
+ this.heightSpec = SPECS[a.getInt(HEIGHT_SPEC, DEFAULT_SPEC_INDEX)];
} finally {
a.recycle();
}
@@ -1874,7 +1901,7 @@ public class GridLayout extends ViewGroup {
private static class Arc {
public final Interval span;
public final MutableInt value;
- public boolean completesCycle;
+ public boolean valid = true;
public Arc(Interval span, MutableInt value) {
this.span = span;
@@ -1883,7 +1910,7 @@ public class GridLayout extends ViewGroup {
@Override
public String toString() {
- return span + " " + (completesCycle ? "+>" : "->") + " " + value;
+ return span + " " + (!valid ? "+>" : "->") + " " + value;
}
}
@@ -1903,6 +1930,41 @@ public class GridLayout extends ViewGroup {
private void reset() {
value = Integer.MIN_VALUE;
}
+
+ @Override
+ public String toString() {
+ return Integer.toString(value);
+ }
+ }
+
+ private static class Assoc<K, V> extends ArrayList<Pair<K, V>> {
+ private final Class<K> keyType;
+ private final Class<V> valueType;
+
+ private Assoc(Class<K> keyType, Class<V> valueType) {
+ this.keyType = keyType;
+ this.valueType = valueType;
+ }
+
+ private static <K, V> Assoc<K, V> of(Class<K> keyType, Class<V> valueType) {
+ return new Assoc<K, V>(keyType, valueType);
+ }
+
+ public void put(K key, V value) {
+ add(Pair.create(key, value));
+ }
+
+ @SuppressWarnings(value = "unchecked")
+ public PackedMap<K, V> pack() {
+ int N = size();
+ K[] keys = (K[]) Array.newInstance(keyType, N);
+ V[] values = (V[]) Array.newInstance(valueType, N);
+ for (int i = 0; i < N; i++) {
+ keys[i] = get(i).first;
+ values[i] = get(i).second;
+ }
+ return new PackedMap<K, V>(keys, values);
+ }
}
/*
@@ -1989,6 +2051,7 @@ public class GridLayout extends ViewGroup {
public int before;
public int after;
+ public boolean canStretch;
private Bounds() {
reset();
@@ -1997,6 +2060,7 @@ public class GridLayout extends ViewGroup {
protected void reset() {
before = Integer.MIN_VALUE;
after = Integer.MIN_VALUE;
+ canStretch = false;
}
protected void include(int before, int after) {
@@ -2004,12 +2068,26 @@ public class GridLayout extends ViewGroup {
this.after = max(this.after, after);
}
- protected int size() {
+ protected int size(boolean min) {
+ if (!min && canStretch) {
+ return MAX_SIZE;
+ }
return before + after;
}
- protected int getOffset(View c, Alignment alignment, int type, int size) {
- return before - alignment.getAlignmentValue(c, size, type);
+ protected int getOffset(View c, Alignment alignment, int size) {
+ return before - alignment.getAlignmentValue(c, size);
+ }
+
+ protected void include(View c, Group g, GridLayout gridLayout, Axis axis, LayoutParams lp) {
+ Spec spec = axis.horizontal ? lp.widthSpec : lp.heightSpec;
+ if (spec == CAN_STRETCH) {
+ canStretch = true;
+ }
+ int size = gridLayout.getMeasurementIncludingMargin(c, axis.horizontal);
+ // todo test this works correctly when the returned value is UNDEFINED
+ int before = g.alignment.getAlignmentValue(c, size);
+ include(before, size - before);
}
@Override
@@ -2032,7 +2110,7 @@ public class GridLayout extends ViewGroup {
* Intervals are often written as {@code [min, max]} and represent the set of values
* {@code x} such that {@code min <= x < max}.
*/
- /* package */ static class Interval {
+ static class Interval {
private static final Interval GONE = new Interval(UNDEFINED, UNDEFINED);
/**
@@ -2129,7 +2207,7 @@ public class GridLayout extends ViewGroup {
* See {@link GridLayout} for a description of the conventions used by GridLayout
* for grid indices.
*/
- /* package */ final Interval span;
+ final Interval span;
/**
* Specifies how cells should be aligned in this group.
* For row groups, this specifies the vertical alignment.
@@ -2147,7 +2225,7 @@ public class GridLayout extends ViewGroup {
* @param span the span
* @param alignment the alignment
*/
- /* package */ Group(Interval span, Alignment alignment) {
+ Group(Interval span, Alignment alignment) {
this.span = span;
this.alignment = alignment;
}
@@ -2248,17 +2326,16 @@ public class GridLayout extends ViewGroup {
* so that the locations defined by the alignment values
* are the same for all of the views in a group.
* <p>
-
*/
public static abstract class Alignment {
private static final Alignment GONE = new Alignment() {
- public int getAlignmentValue(View view, int viewSize, int measurementType) {
+ public int getAlignmentValue(View view, int viewSize) {
assert false;
return 0;
}
};
- /*pp*/ Alignment() {
+ Alignment() {
}
/**
@@ -2269,12 +2346,9 @@ public class GridLayout extends ViewGroup {
*
* @param view the view to which this alignment should be applied
* @param viewSize the measured size of the view
- * @param measurementType This parameter is currently unused as GridLayout only supports
- * one type of measurement: {@link View#measure(int, int)}.
- *
* @return the alignment value
*/
- /*pp*/ abstract int getAlignmentValue(View view, int viewSize, int measurementType);
+ abstract int getAlignmentValue(View view, int viewSize);
/**
* Returns the size of the view specified by this alignment.
@@ -2291,24 +2365,24 @@ public class GridLayout extends ViewGroup {
*
* @return the aligned size
*/
- /*pp*/ int getSizeInCell(View view, int viewSize, int cellSize, int measurementType) {
+ int getSizeInCell(View view, int viewSize, int cellSize, int measurementType) {
return viewSize;
}
- /*pp*/ Bounds getBounds() {
+ Bounds getBounds() {
return new Bounds();
}
}
private static final Alignment LEADING = new Alignment() {
- public int getAlignmentValue(View view, int viewSize, int measurementType) {
+ public int getAlignmentValue(View view, int viewSize) {
return 0;
}
};
private static final Alignment TRAILING = new Alignment() {
- public int getAlignmentValue(View view, int viewSize, int measurementType) {
+ public int getAlignmentValue(View view, int viewSize) {
return viewSize;
}
};
@@ -2343,7 +2417,7 @@ public class GridLayout extends ViewGroup {
* LayoutParams#columnGroup columnGroups}.
*/
public static final Alignment CENTER = new Alignment() {
- public int getAlignmentValue(View view, int viewSize, int measurementType) {
+ public int getAlignmentValue(View view, int viewSize) {
return viewSize >> 1;
}
};
@@ -2356,7 +2430,7 @@ public class GridLayout extends ViewGroup {
* @see View#getBaseline()
*/
public static final Alignment BASELINE = new Alignment() {
- public int getAlignmentValue(View view, int viewSize, int measurementType) {
+ public int getAlignmentValue(View view, int viewSize) {
if (view == null) {
return UNDEFINED;
}
@@ -2378,7 +2452,7 @@ public class GridLayout extends ViewGroup {
@Override
protected void reset() {
super.reset();
- size = 0;
+ size = Integer.MIN_VALUE;
}
@Override
@@ -2388,13 +2462,13 @@ public class GridLayout extends ViewGroup {
}
@Override
- protected int size() {
- return max(super.size(), size);
+ protected int size(boolean min) {
+ return max(super.size(min), size);
}
@Override
- protected int getOffset(View c, Alignment alignment, int type, int size) {
- return max(0, super.getOffset(c, alignment, type, size));
+ protected int getOffset(View c, Alignment alignment, int size) {
+ return max(0, super.getOffset(c, alignment, size));
}
};
}
@@ -2406,7 +2480,7 @@ public class GridLayout extends ViewGroup {
* {@link LayoutParams#columnGroup columnGroups}.
*/
public static final Alignment FILL = new Alignment() {
- public int getAlignmentValue(View view, int viewSize, int measurementType) {
+ public int getAlignmentValue(View view, int viewSize) {
return UNDEFINED;
}
@@ -2415,4 +2489,41 @@ public class GridLayout extends ViewGroup {
return cellSize;
}
};
+
+ /**
+ * Spec's tell GridLayout how to derive minimum and maximum size values for a
+ * component. Specifications are made with respect to a child's 'measured size'.
+ * A child's measured size is, in turn, controlled by its height and width
+ * layout parameters which either specify a size or, in the case of
+ * WRAP_CONTENT, defer to the computed size of the component.
+ */
+ public static abstract class Spec {
+ }
+
+ /**
+ * Indicates that a view requests precisely the size specified by its layout parameters.
+ *
+ * @see Spec
+ */
+ public static final Spec FIXED = new Spec() {
+ };
+
+ /**
+ * Indicates that a view's size should lie between its minimum and the size specified by
+ * its layout parameters.
+ *
+ * @see Spec
+ */
+ public static final Spec CAN_SHRINK = new Spec() {
+ };
+
+ /**
+ * Indicates that a view's size should be greater than or equal to the size specified by
+ * its layout parameters.
+ *
+ * @see Spec
+ */
+ public static final Spec CAN_STRETCH = new Spec() {
+ };
+
}
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 2947ebeb1d4b..aa23ad0f6fa4 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -1201,18 +1201,15 @@ public class NumberPicker extends LinearLayout {
private void initializeScrollWheel() {
if (mInitialScrollOffset != Integer.MIN_VALUE) {
return;
-
}
int[] selectorIndices = getSelectorIndices();
int totalTextHeight = selectorIndices.length * mTextSize;
- int totalTextGapHeight = (mBottom - mTop) - totalTextHeight;
- int textGapCount = selectorIndices.length - 1;
- int selectorTextGapHeight = totalTextGapHeight / textGapCount;
- // compensate for integer division loss of the components used to
- // calculate the text gap
- int integerDivisionLoss = (mTextSize + mBottom - mTop) % textGapCount;
- mInitialScrollOffset = mCurrentScrollOffset = mTextSize - integerDivisionLoss / 2;
+ float totalTextGapHeight = (mBottom - mTop) - totalTextHeight;
+ float textGapCount = selectorIndices.length - 1;
+ int selectorTextGapHeight = (int) (totalTextGapHeight / textGapCount + 0.5f);
mSelectorElementHeight = mTextSize + selectorTextGapHeight;
+ mInitialScrollOffset = mTextSize - 3 * (mSelectorElementHeight % 2);
+ mCurrentScrollOffset = mInitialScrollOffset;
updateInputTextView();
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index f6b71f8b9415..c91f1a61306d 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -340,6 +340,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
private WordIterator mWordIterator;
+ // The alignment to pass to Layout, or null if not resolved.
+ private Layout.Alignment mLayoutAlignment;
+
+ // The default value for mTextAlign.
+ private TextAlign mTextAlign = TextAlign.INHERIT;
+
+ private static enum TextAlign {
+ INHERIT, GRAVITY, TEXT_START, TEXT_END, CENTER, VIEW_START, VIEW_END;
+ }
+
/*
* Kick-start the font cache for the zygote process (to pay the cost of
* initializing freetype for our default font only once).
@@ -4948,7 +4958,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (mMovement != null && mText instanceof Editable
&& mLayout != null && onCheckIsTextEditor()) {
InputMethodManager imm = InputMethodManager.peekInstance();
- if (imm != null) imm.showSoftInput(this, 0);
+ if (imm != null) {
+ imm.viewClicked(this);
+ imm.showSoftInput(this, 0);
+ }
}
}
}
@@ -5529,6 +5542,73 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
physicalWidth, false);
}
+ @Override
+ protected void resetLayoutDirectionResolution() {
+ super.resetLayoutDirectionResolution();
+
+ if (mLayoutAlignment != null &&
+ (mTextAlign == TextAlign.VIEW_START ||
+ mTextAlign == TextAlign.VIEW_END)) {
+ mLayoutAlignment = null;
+ }
+ }
+
+ private Layout.Alignment getLayoutAlignment() {
+ if (mLayoutAlignment == null) {
+ Layout.Alignment alignment;
+ TextAlign textAlign = mTextAlign;
+ switch (textAlign) {
+ case INHERIT:
+ // fall through to gravity temporarily
+ // intention is to inherit value through view hierarchy.
+ case GRAVITY:
+ switch (mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) {
+ case Gravity.START:
+ alignment = Layout.Alignment.ALIGN_NORMAL;
+ break;
+ case Gravity.END:
+ alignment = Layout.Alignment.ALIGN_OPPOSITE;
+ break;
+ case Gravity.LEFT:
+ alignment = Layout.Alignment.ALIGN_LEFT;
+ break;
+ case Gravity.RIGHT:
+ alignment = Layout.Alignment.ALIGN_RIGHT;
+ break;
+ case Gravity.CENTER_HORIZONTAL:
+ alignment = Layout.Alignment.ALIGN_CENTER;
+ break;
+ default:
+ alignment = Layout.Alignment.ALIGN_NORMAL;
+ break;
+ }
+ break;
+ case TEXT_START:
+ alignment = Layout.Alignment.ALIGN_NORMAL;
+ break;
+ case TEXT_END:
+ alignment = Layout.Alignment.ALIGN_OPPOSITE;
+ break;
+ case CENTER:
+ alignment = Layout.Alignment.ALIGN_CENTER;
+ break;
+ case VIEW_START:
+ alignment = (getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) ?
+ Layout.Alignment.ALIGN_RIGHT : Layout.Alignment.ALIGN_LEFT;
+ break;
+ case VIEW_END:
+ alignment = (getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL) ?
+ Layout.Alignment.ALIGN_LEFT : Layout.Alignment.ALIGN_RIGHT;
+ break;
+ default:
+ alignment = Layout.Alignment.ALIGN_NORMAL;
+ break;
+ }
+ mLayoutAlignment = alignment;
+ }
+ return mLayoutAlignment;
+ }
+
/**
* The width passed in is now the desired layout width,
* not the full view width with padding.
@@ -5549,25 +5629,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
hintWidth = 0;
}
- final int layoutDirection = getResolvedLayoutDirection();
- final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
-
- Layout.Alignment alignment;
- switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
- case Gravity.CENTER_HORIZONTAL:
- alignment = Layout.Alignment.ALIGN_CENTER;
- break;
-
- case Gravity.RIGHT:
- // Note, Layout resolves ALIGN_OPPOSITE to left or
- // right based on the paragraph direction.
- alignment = Layout.Alignment.ALIGN_OPPOSITE;
- break;
-
- default:
- alignment = Layout.Alignment.ALIGN_NORMAL;
- }
-
+ Layout.Alignment alignment = getLayoutAlignment();
boolean shouldEllipsize = mEllipsize != null && mInput == null;
if (mText instanceof Spannable) {
@@ -7398,8 +7460,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if ((isTextEditable() || mTextIsSelectable) && touchIsFinished) {
// Show the IME, except when selecting in read-only text.
+ final InputMethodManager imm = InputMethodManager.peekInstance();
+ if (imm != null) {
+ imm.viewClicked(this);
+ }
if (!mTextIsSelectable) {
- final InputMethodManager imm = InputMethodManager.peekInstance();
handled |= imm != null && imm.showSoftInput(this, 0);
}
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/ActionBarImpl.java
index 8d5df6f96714..519acf5d3eca 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/ActionBarImpl.java
@@ -16,7 +16,6 @@
package com.android.internal.app;
-import com.android.internal.R;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.view.menu.MenuPopupHelper;
import com.android.internal.view.menu.SubMenuBuilder;
@@ -36,7 +35,6 @@ import android.app.Dialog;
import android.app.FragmentTransaction;
import android.content.Context;
import android.content.res.Configuration;
-import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.view.ActionMode;
@@ -580,6 +578,9 @@ public class ActionBarImpl extends ActionBar {
mActionView.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE);
mContextView.animateToVisibility(toActionMode ? View.VISIBLE : View.GONE);
+ if (mTabScrollView != null && !mActionView.hasEmbeddedTabs() && mActionView.isCollapsed()) {
+ mTabScrollView.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE);
+ }
}
/**
@@ -620,6 +621,7 @@ public class ActionBarImpl extends ActionBar {
// Clear out the context mode views after the animation finishes
mContextView.closeMode();
+
mActionMode = null;
if (mWasHiddenBeforeMode) {
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index b57046c39b2c..ec64552051d4 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -135,6 +135,16 @@ public class PackageHelper {
return null;
}
+ public static String getSdFilesystem(String cid) {
+ try {
+ return getMountService().getSecureContainerFilesystemPath(cid);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to get container path for " + cid +
+ " with exception " + e);
+ }
+ return null;
+ }
+
public static boolean finalizeSdDir(String cid) {
try {
int rc = getMountService().finalizeSecureContainer(cid);
diff --git a/core/java/com/android/internal/net/VpnConfig.java b/core/java/com/android/internal/net/VpnConfig.java
index 773be5bc2b21..572a1d761d65 100644
--- a/core/java/com/android/internal/net/VpnConfig.java
+++ b/core/java/com/android/internal/net/VpnConfig.java
@@ -23,6 +23,8 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
+import java.util.List;
+
/**
* A simple container used to carry information in VpnBuilder, VpnDialogs,
* and com.android.server.connectivity.Vpn. Internal use only.
@@ -33,12 +35,6 @@ public class VpnConfig implements Parcelable {
public static final String ACTION_VPN_REVOKED = "android.net.vpn.action.REVOKED";
- public static void enforceCallingPackage(String packageName) {
- if (!"com.android.vpndialogs".equals(packageName)) {
- throw new SecurityException("Unauthorized Caller");
- }
- }
-
public static Intent getIntentForConfirmation() {
Intent intent = new Intent();
intent.setClassName("com.android.vpndialogs", "com.android.vpndialogs.ConfirmDialog");
@@ -58,11 +54,12 @@ public class VpnConfig implements Parcelable {
public String packageName;
public String sessionName;
public String interfaceName;
- public String configureActivity;
+ public PendingIntent configureIntent;
public int mtu = -1;
public String addresses;
public String routes;
- public String dnsServers;
+ public List<String> dnsServers;
+ public List<String> searchDomains;
public long startTime = -1;
@Override
@@ -75,11 +72,12 @@ public class VpnConfig implements Parcelable {
out.writeString(packageName);
out.writeString(sessionName);
out.writeString(interfaceName);
- out.writeString(configureActivity);
+ out.writeParcelable(configureIntent, flags);
out.writeInt(mtu);
out.writeString(addresses);
out.writeString(routes);
- out.writeString(dnsServers);
+ out.writeStringList(dnsServers);
+ out.writeStringList(searchDomains);
out.writeLong(startTime);
}
@@ -91,11 +89,12 @@ public class VpnConfig implements Parcelable {
config.packageName = in.readString();
config.sessionName = in.readString();
config.interfaceName = in.readString();
- config.configureActivity = in.readString();
+ config.configureIntent = in.readParcelable(null);
config.mtu = in.readInt();
config.addresses = in.readString();
config.routes = in.readString();
- config.dnsServers = in.readString();
+ config.dnsServers = in.createStringArrayList();
+ config.searchDomains = in.createStringArrayList();
config.startTime = in.readLong();
return config;
}
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index 5e9cd23a82cd..f13e77067d5b 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -25,16 +25,13 @@ import android.os.Process;
import android.os.SystemProperties;
import android.util.Log;
import android.util.Slog;
-
import com.android.internal.logging.AndroidConfig;
-
+import com.android.server.NetworkManagementSocketTagger;
import dalvik.system.VMRuntime;
-
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
-import java.util.logging.LogManager;
import java.util.TimeZone;
-
+import java.util.logging.LogManager;
import org.apache.harmony.luni.internal.util.TimezoneGetter;
/**
@@ -129,6 +126,11 @@ public class RuntimeInit {
System.setProperty("http.agent", userAgent);
/*
+ * Wire socket tagging to traffic stats.
+ */
+ NetworkManagementSocketTagger.install();
+
+ /*
* If we're running in an emulator launched with "-trace", put the
* VM into emulator trace profiling mode so that the user can hit
* F9/F10 at any time to capture traces. This has performance
diff --git a/core/java/com/android/internal/view/IInputMethodSession.aidl b/core/java/com/android/internal/view/IInputMethodSession.aidl
index 338dcaa7db96..f875cbd95a07 100644
--- a/core/java/com/android/internal/view/IInputMethodSession.aidl
+++ b/core/java/com/android/internal/view/IInputMethodSession.aidl
@@ -36,7 +36,9 @@ oneway interface IInputMethodSession {
void updateSelection(int oldSelStart, int oldSelEnd,
int newSelStart, int newSelEnd,
int candidatesStart, int candidatesEnd);
-
+
+ void viewClicked(boolean focusChanged);
+
void updateCursor(in Rect newCursor);
void displayCompletions(in CompletionInfo[] completions);
diff --git a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
index 322a8545d559..2fec9cd09f5b 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuPresenter.java
@@ -26,6 +26,7 @@ import android.view.MenuItem;
import android.view.SoundEffectConstants;
import android.view.View;
import android.view.View.MeasureSpec;
+import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.ImageButton;
@@ -69,9 +70,7 @@ public class ActionMenuPresenter extends BaseMenuPresenter {
final Resources res = context.getResources();
if (!mReserveOverflowSet) {
- // TODO Use the no-buttons specifier instead here
- mReserveOverflow = res.getConfiguration()
- .isLayoutSizeAtLeast(Configuration.SCREENLAYOUT_SIZE_LARGE);
+ mReserveOverflow = !ViewConfiguration.get(context).hasPermanentMenuKey();
}
if (!mWidthLimitSet) {
diff --git a/core/java/com/android/internal/widget/ActionBarContainer.java b/core/java/com/android/internal/widget/ActionBarContainer.java
index d710cfae56f3..953328c03ddd 100644
--- a/core/java/com/android/internal/widget/ActionBarContainer.java
+++ b/core/java/com/android/internal/widget/ActionBarContainer.java
@@ -105,24 +105,19 @@ public class ActionBarContainer extends FrameLayout {
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- int nonTabHeight = 0;
- final int count = getChildCount();
- for (int i = 0; i < count; i++) {
- final View child = getChildAt(i);
+ if (mActionBarView == null) return;
- if (child == mTabContainer) continue;
-
- final LayoutParams lp = (LayoutParams) child.getLayoutParams();
- nonTabHeight = Math.max(nonTabHeight,
- child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
- }
+ final LayoutParams lp = (LayoutParams) mActionBarView.getLayoutParams();
+ final int actionBarViewHeight = mActionBarView.isCollapsed() ? 0 :
+ mActionBarView.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
if (mTabContainer != null && mTabContainer.getVisibility() != GONE) {
final int mode = MeasureSpec.getMode(heightMeasureSpec);
if (mode == MeasureSpec.AT_MOST) {
final int maxHeight = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(getMeasuredWidth(),
- Math.min(nonTabHeight + mTabContainer.getMeasuredHeight(), maxHeight));
+ Math.min(actionBarViewHeight + mTabContainer.getMeasuredHeight(),
+ maxHeight));
}
}
}
@@ -137,12 +132,14 @@ public class ActionBarContainer extends FrameLayout {
if ((mActionBarView.getDisplayOptions() & ActionBar.DISPLAY_SHOW_HOME) == 0) {
// Not showing home, put tabs on top.
final int count = getChildCount();
- for (int i = 0; i < count; i++){
+ for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child == mTabContainer) continue;
- child.offsetTopAndBottom(tabHeight);
+ if (!mActionBarView.isCollapsed()) {
+ child.offsetTopAndBottom(tabHeight);
+ }
}
mTabContainer.layout(l, 0, r, tabHeight);
} else {
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index fc439944f518..3e3eeab4cbed 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -287,7 +287,7 @@ public class ActionBarContextView extends AbsActionBarView implements AnimatorLi
availableWidth = measureChildView(mClose, availableWidth, childSpecHeight, 0);
}
- if (mMenuView != null) {
+ if (mMenuView != null && mMenuView.getParent() == this) {
availableWidth = measureChildView(mMenuView, availableWidth,
childSpecHeight, 0);
}
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 8eb046ebd94d..09bc1fc3cf7f 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -117,6 +117,7 @@ public class ActionBarView extends AbsActionBarView {
private boolean mUserTitle;
private boolean mIncludeTabs;
private boolean mIsCollapsable;
+ private boolean mIsCollapsed;
private MenuBuilder mOptionsMenu;
@@ -692,6 +693,10 @@ public class ActionBarView extends AbsActionBarView {
mIsCollapsable = collapsable;
}
+ public boolean isCollapsed() {
+ return mIsCollapsed;
+ }
+
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int childCount = getChildCount();
@@ -708,9 +713,11 @@ public class ActionBarView extends AbsActionBarView {
if (visibleChildren == 0) {
// No size for an empty action bar when collapsable.
setMeasuredDimension(0, 0);
+ mIsCollapsed = true;
return;
}
}
+ mIsCollapsed = false;
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
if (widthMode != MeasureSpec.EXACTLY) {
diff --git a/core/java/com/android/internal/widget/ScrollingTabContainerView.java b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
index 5b4d7ab143fa..2f7adf0c0b46 100644
--- a/core/java/com/android/internal/widget/ScrollingTabContainerView.java
+++ b/core/java/com/android/internal/widget/ScrollingTabContainerView.java
@@ -15,6 +15,9 @@
*/
package com.android.internal.widget;
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
import android.app.ActionBar;
import android.content.Context;
import android.graphics.drawable.Drawable;
@@ -22,6 +25,7 @@ import android.text.TextUtils.TruncateAt;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
+import android.view.animation.DecelerateInterpolator;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -35,6 +39,13 @@ public class ScrollingTabContainerView extends HorizontalScrollView {
int mMaxTabWidth;
+ protected Animator mVisibilityAnim;
+ protected final VisibilityAnimListener mVisAnimListener = new VisibilityAnimListener();
+
+ private static final TimeInterpolator sAlphaInterpolator = new DecelerateInterpolator();
+
+ private static final int FADE_DURATION = 200;
+
public ScrollingTabContainerView(Context context) {
super(context);
setHorizontalScrollBarEnabled(false);
@@ -76,6 +87,30 @@ public class ScrollingTabContainerView extends HorizontalScrollView {
}
}
+ public void animateToVisibility(int visibility) {
+ if (mVisibilityAnim != null) {
+ mVisibilityAnim.cancel();
+ }
+ if (visibility == VISIBLE) {
+ if (getVisibility() != VISIBLE) {
+ setAlpha(0);
+ }
+ ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 1);
+ anim.setDuration(FADE_DURATION);
+ anim.setInterpolator(sAlphaInterpolator);
+
+ anim.addListener(mVisAnimListener.withFinalVisibility(visibility));
+ anim.start();
+ } else {
+ ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 0);
+ anim.setDuration(FADE_DURATION);
+ anim.setInterpolator(sAlphaInterpolator);
+
+ anim.addListener(mVisAnimListener.withFinalVisibility(visibility));
+ anim.start();
+ }
+ }
+
public void animateToTab(int position) {
final View tabView = mTabLayout.getChildAt(position);
if (mTabSelector != null) {
@@ -259,4 +294,38 @@ public class ScrollingTabContainerView extends HorizontalScrollView {
}
}
}
+
+ protected class VisibilityAnimListener implements Animator.AnimatorListener {
+ private boolean mCanceled = false;
+ private int mFinalVisibility;
+
+ public VisibilityAnimListener withFinalVisibility(int visibility) {
+ mFinalVisibility = visibility;
+ return this;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ setVisibility(VISIBLE);
+ mVisibilityAnim = animation;
+ mCanceled = false;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (mCanceled) return;
+
+ mVisibilityAnim = null;
+ setVisibility(mFinalVisibility);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mCanceled = true;
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ }
+ }
}
diff --git a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
index 5b3510428f7b..04bb6892c1ae 100644
--- a/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
+++ b/core/java/com/android/internal/widget/multiwaveview/MultiWaveView.java
@@ -20,7 +20,7 @@ import java.util.ArrayList;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
-import android.animation.ObjectAnimator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
@@ -43,9 +43,9 @@ import com.android.internal.R;
* A special widget containing a center and outer ring. Moving the center ring to the outer ring
* causes an event that can be caught by implementing OnTriggerListener.
*/
-public class MultiWaveView extends View implements AnimatorUpdateListener {
+public class MultiWaveView extends View {
private static final String TAG = "MultiWaveView";
- private static final boolean DEBUG = false;
+ private static final boolean DEBUG = true;
// Wave state machine
private static final int STATE_IDLE = 0;
@@ -67,14 +67,15 @@ public class MultiWaveView extends View implements AnimatorUpdateListener {
}
// Tune-able parameters
- private static final int CHEVRON_INCREMENTAL_DELAY = 50;
- private static final int CHEVRON_ANIMATION_DURATION = 1000;
- private static final int RETURN_TO_HOME_DURATION = 150;
- private static final int HIDE_ANIMATION_DELAY = 500;
- private static final int HIDE_ANIMATION_DURACTION = 2000;
+ private static final int CHEVRON_INCREMENTAL_DELAY = 160;
+ private static final int CHEVRON_ANIMATION_DURATION = 650;
+ private static final int RETURN_TO_HOME_DELAY = 1200;
+ private static final int RETURN_TO_HOME_DURATION = 300;
+ private static final int HIDE_ANIMATION_DELAY = 200;
+ private static final int HIDE_ANIMATION_DURATION = RETURN_TO_HOME_DELAY;
private static final int SHOW_ANIMATION_DURATION = 0;
private static final int SHOW_ANIMATION_DELAY = 0;
- private TimeInterpolator mChevronAnimationInterpolator = Ease.Quint.easeOut;
+ private TimeInterpolator mChevronAnimationInterpolator = Ease.Quad.easeOut;
private ArrayList<TargetDrawable> mTargetDrawables = new ArrayList<TargetDrawable>();
private ArrayList<TargetDrawable> mChevronDrawables = new ArrayList<TargetDrawable>();
@@ -99,14 +100,31 @@ public class MultiWaveView extends View implements AnimatorUpdateListener {
private float mHitRadius = 0.0f;
private float mSnapMargin = 0.0f;
private boolean mDragging;
+ private int mNewTargetResources;
- private AnimatorListener mResetListener = new Animator.AnimatorListener() {
- public void onAnimationStart(Animator animation) { }
- public void onAnimationRepeat(Animator animation) { }
- public void onAnimationEnd(Animator animation) {
+ private AnimatorListener mResetListener = new AnimatorListenerAdapter() {
+ public void onAnimationEnd(Animator animator) {
switchToState(STATE_IDLE, mWaveCenterX, mWaveCenterY);
}
- public void onAnimationCancel(Animator animation) { }
+ };
+
+ private AnimatorUpdateListener mUpdateListener = new AnimatorUpdateListener() {
+ public void onAnimationUpdate(ValueAnimator animation) {
+ invalidateGlobalRegion(mHandleDrawable);
+ invalidate();
+ }
+ };
+
+ private boolean mAnimatingTargets;
+ private AnimatorListener mTargetUpdateListener = new AnimatorListenerAdapter() {
+ public void onAnimationEnd(Animator animator) {
+ if (mNewTargetResources != 0) {
+ internalSetTargetResources(mNewTargetResources);
+ mNewTargetResources = 0;
+ hideTargets(false);
+ }
+ mAnimatingTargets = false;
+ }
};
public MultiWaveView(Context context) {
@@ -135,31 +153,23 @@ public class MultiWaveView extends View implements AnimatorUpdateListener {
mOuterRing = new TargetDrawable(res, a.getDrawable(R.styleable.MultiWaveView_waveDrawable));
// Read chevron animation drawables
- Drawable leftChevron = a.getDrawable(R.styleable.MultiWaveView_leftChevronDrawable);
- for (int i = 0; i < mFeedbackCount; i++) {
- mChevronDrawables.add(
- leftChevron != null ? new TargetDrawable(res, leftChevron) : null);
- }
- Drawable rightChevron = a.getDrawable(R.styleable.MultiWaveView_rightChevronDrawable);
- for (int i = 0; i < mFeedbackCount; i++) {
- mChevronDrawables.add(
- rightChevron != null ? new TargetDrawable(res, rightChevron) : null);
- }
- Drawable topChevron = a.getDrawable(R.styleable.MultiWaveView_topChevronDrawable);
- for (int i = 0; i < mFeedbackCount; i++) {
- mChevronDrawables.add(
- topChevron != null ? new TargetDrawable(res, topChevron) : null);
- }
- Drawable bottomChevron = a.getDrawable(R.styleable.MultiWaveView_bottomChevronDrawable);
- for (int i = 0; i < mFeedbackCount; i++) {
- mChevronDrawables.add(
- bottomChevron != null ? new TargetDrawable(res, bottomChevron) : null);
+ final int chevrons[] = { R.styleable.MultiWaveView_leftChevronDrawable,
+ R.styleable.MultiWaveView_rightChevronDrawable,
+ R.styleable.MultiWaveView_topChevronDrawable,
+ R.styleable.MultiWaveView_bottomChevronDrawable
+ };
+ for (int chevron : chevrons) {
+ Drawable chevronDrawable = a.getDrawable(chevron);
+ for (int i = 0; i < mFeedbackCount; i++) {
+ mChevronDrawables.add(
+ chevronDrawable != null ? new TargetDrawable(res, chevronDrawable) : null);
+ }
}
// Read array of target drawables
TypedValue outValue = new TypedValue();
if (a.getValue(R.styleable.MultiWaveView_targetDrawables, outValue)) {
- setTargetResources(outValue.resourceId);
+ internalSetTargetResources(outValue.resourceId);
}
if (mTargetDrawables == null || mTargetDrawables.size() == 0) {
throw new IllegalStateException("Must specify at least one target drawable");
@@ -205,7 +215,7 @@ public class MultiWaveView extends View implements AnimatorUpdateListener {
case STATE_FIRST_TOUCH:
stopHandleAnimation();
deactivateTargets();
- showTargets();
+ showTargets(true);
mHandleDrawable.setState(TargetDrawable.STATE_ACTIVE);
setGrabbedState(OnTriggerListener.CENTER_HANDLE);
break;
@@ -228,17 +238,18 @@ public class MultiWaveView extends View implements AnimatorUpdateListener {
* mFeedbackCount items in the order: left, right, top, bottom.
*/
private void startChevronAnimation() {
- final float r = mHandleDrawable.getWidth() / 2;
+ final float r = mHandleDrawable.getWidth() * 0.4f;
+ final float chevronAnimationDistance = mOuterRadius * 0.8f;
final float from[][] = {
{mWaveCenterX - r, mWaveCenterY}, // left
{mWaveCenterX + r, mWaveCenterY}, // right
{mWaveCenterX, mWaveCenterY - r}, // top
{mWaveCenterX, mWaveCenterY + r} }; // bottom
final float to[][] = {
- {mWaveCenterX - mOuterRadius, mWaveCenterY}, // left
- {mWaveCenterX + mOuterRadius, mWaveCenterY}, // right
- {mWaveCenterX, mWaveCenterY - mOuterRadius}, // top
- {mWaveCenterX, mWaveCenterY + mOuterRadius} }; // bottom
+ {mWaveCenterX - chevronAnimationDistance, mWaveCenterY}, // left
+ {mWaveCenterX + chevronAnimationDistance, mWaveCenterY}, // right
+ {mWaveCenterX, mWaveCenterY - chevronAnimationDistance}, // top
+ {mWaveCenterX, mWaveCenterY + chevronAnimationDistance} }; // bottom
mChevronAnimations.clear();
for (int direction = 0; direction < 4; direction++) {
@@ -254,7 +265,7 @@ public class MultiWaveView extends View implements AnimatorUpdateListener {
"x", new float[] { from[direction][0], to[direction][0] },
"y", new float[] { from[direction][1], to[direction][1] },
"alpha", new float[] {1.0f, 0.0f},
- "onUpdate", this));
+ "onUpdate", mUpdateListener));
}
}
}
@@ -308,70 +319,109 @@ public class MultiWaveView extends View implements AnimatorUpdateListener {
}
private void doFinish() {
- // Inform listener of any active targets. Typically only one will be active.
final int activeTarget = mActiveTarget;
boolean targetHit = activeTarget != -1;
- if (targetHit) {
- Log.v(TAG, "Finish with target hit = " + targetHit);
- dispatchTriggerEvent(mActiveTarget);
- }
-
- setGrabbedState(OnTriggerListener.NO_HANDLE);
-
- // Animate finger outline back to home position
- mHandleDrawable.setAlpha(targetHit ? 0.0f : 1.0f);
- mHandleAnimation = Tweener.to(mHandleDrawable, RETURN_TO_HOME_DURATION,
- "ease", Ease.Quart.easeOut,
- "delay", targetHit ? HIDE_ANIMATION_DELAY : 0,
- "alpha", 1.0f,
- "x", mWaveCenterX,
- "y", mWaveCenterY,
- "onUpdate", this,
- "onComplete", mResetListener);
// Hide unselected targets
hideTargets(true);
// Highlight the selected one
+ mHandleDrawable.setAlpha(targetHit ? 0.0f : 1.0f);
if (targetHit) {
mTargetDrawables.get(activeTarget).setState(TargetDrawable.STATE_ACTIVE);
+
+ hideUnselected(activeTarget);
+
+ // Inform listener of any active targets. Typically only one will be active.
+ if (DEBUG) Log.v(TAG, "Finish with target hit = " + targetHit);
+ dispatchTriggerEvent(mActiveTarget);
+ mHandleAnimation = Tweener.to(mHandleDrawable, 0,
+ "ease", Ease.Quart.easeOut,
+ "delay", RETURN_TO_HOME_DELAY,
+ "alpha", 1.0f,
+ "x", mWaveCenterX,
+ "y", mWaveCenterY,
+ "onUpdate", mUpdateListener,
+ "onComplete", mResetListener);
+ } else {
+ // Animate finger outline back to home position
+ mHandleAnimation = Tweener.to(mHandleDrawable, RETURN_TO_HOME_DURATION,
+ "ease", Ease.Quart.easeOut,
+ "delay", 0,
+ "alpha", 1.0f,
+ "x", mWaveCenterX,
+ "y", mWaveCenterY,
+ "onUpdate", mUpdateListener,
+ "onComplete", mResetListener);
}
+
+ setGrabbedState(OnTriggerListener.NO_HANDLE);
+ }
+
+ private void hideUnselected(int active) {
+ for (int i = 0; i < mTargetDrawables.size(); i++) {
+ if (i != active) {
+ mTargetDrawables.get(i).setAlpha(0.0f);
+ }
+ }
+ mOuterRing.setAlpha(0.0f);
}
private void hideTargets(boolean animate) {
if (mTargetAnimations.size() > 0) {
stopTargetAnimation();
}
- for (TargetDrawable target : mTargetDrawables) {
- target.setState(TargetDrawable.STATE_INACTIVE);
- mTargetAnimations.add(Tweener.to(target,
- animate ? HIDE_ANIMATION_DURACTION : 0,
+ // Note: these animations should complete at the same time so that we can swap out
+ // the target assets asynchronously from the setTargetResources() call.
+ mAnimatingTargets = animate;
+ if (animate) {
+ final int duration = animate ? HIDE_ANIMATION_DURATION : 0;
+ for (TargetDrawable target : mTargetDrawables) {
+ target.setState(TargetDrawable.STATE_INACTIVE);
+ mTargetAnimations.add(Tweener.to(target, duration,
+ "alpha", 0.0f,
+ "delay", HIDE_ANIMATION_DELAY,
+ "onUpdate", mUpdateListener));
+ }
+ mTargetAnimations.add(Tweener.to(mOuterRing, duration,
"alpha", 0.0f,
"delay", HIDE_ANIMATION_DELAY,
- "onUpdate", this));
+ "onUpdate", mUpdateListener,
+ "onComplete", mTargetUpdateListener));
+ } else {
+ for (TargetDrawable target : mTargetDrawables) {
+ target.setState(TargetDrawable.STATE_INACTIVE);
+ target.setAlpha(0.0f);
+ }
+ mOuterRing.setAlpha(0.0f);
}
- mTargetAnimations.add(Tweener.to(mOuterRing,
- animate ? HIDE_ANIMATION_DURACTION : 0,
- "alpha", 0.0f,
- "delay", HIDE_ANIMATION_DELAY,
- "onUpdate", this));
}
- private void showTargets() {
+ private void showTargets(boolean animate) {
if (mTargetAnimations.size() > 0) {
stopTargetAnimation();
}
- for (TargetDrawable target : mTargetDrawables) {
- target.setState(TargetDrawable.STATE_INACTIVE);
- mTargetAnimations.add(Tweener.to(target, SHOW_ANIMATION_DURATION,
+ mAnimatingTargets = animate;
+ if (animate) {
+ for (TargetDrawable target : mTargetDrawables) {
+ target.setState(TargetDrawable.STATE_INACTIVE);
+ mTargetAnimations.add(Tweener.to(target, SHOW_ANIMATION_DURATION,
+ "alpha", 1.0f,
+ "delay", SHOW_ANIMATION_DELAY,
+ "onUpdate", mUpdateListener));
+ }
+ mTargetAnimations.add(Tweener.to(mOuterRing, SHOW_ANIMATION_DURATION,
"alpha", 1.0f,
"delay", SHOW_ANIMATION_DELAY,
- "onUpdate", this));
+ "onUpdate", mUpdateListener,
+ "onComplete", mTargetUpdateListener));
+ } else {
+ for (TargetDrawable target : mTargetDrawables) {
+ target.setState(TargetDrawable.STATE_INACTIVE);
+ target.setAlpha(1.0f);
+ }
+ mOuterRing.setAlpha(1.0f);
}
- mTargetAnimations.add(Tweener.to(mOuterRing, SHOW_ANIMATION_DURATION,
- "alpha", 1.0f,
- "delay", SHOW_ANIMATION_DELAY,
- "onUpdate", this));
}
private void stopTargetAnimation() {
@@ -387,12 +437,7 @@ public class MultiWaveView extends View implements AnimatorUpdateListener {
}
}
- /**
- * Loads an array of drawables from the given resourceId.
- *
- * @param resourceId
- */
- public void setTargetResources(int resourceId) {
+ private void internalSetTargetResources(int resourceId) {
Resources res = getContext().getResources();
TypedArray array = res.obtainTypedArray(resourceId);
int count = array.length();
@@ -402,6 +447,21 @@ public class MultiWaveView extends View implements AnimatorUpdateListener {
targetDrawables.add(new TargetDrawable(res, drawable));
}
mTargetDrawables = targetDrawables;
+ updateTargetPositions();
+ }
+
+ /**
+ * Loads an array of drawables from the given resourceId.
+ *
+ * @param resourceId
+ */
+ public void setTargetResources(int resourceId) {
+ if (mAnimatingTargets) {
+ // postpone this change until we return to the initial state
+ mNewTargetResources = resourceId;
+ } else {
+ internalSetTargetResources(resourceId);
+ }
}
/**
@@ -590,20 +650,9 @@ public class MultiWaveView extends View implements AnimatorUpdateListener {
}
}
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- final int width = right - left;
- final int height = bottom - top;
-
- mWaveCenterX = mHorizontalOffset + Math.max(width, mOuterRing.getWidth() ) / 2;
- mWaveCenterY = mVerticalOffset + Math.max(height, mOuterRing.getHeight()) / 2;
- moveHandleTo(mWaveCenterX, mWaveCenterY, false);
- mOuterRing.setX(mWaveCenterX);
- mOuterRing.setY(Math.max(mWaveCenterY, mWaveCenterY));
- mOuterRing.setAlpha(0.0f);
+ private void performInitialLayout(float centerX, float centerY) {
if (mOuterRadius == 0.0f) {
- mOuterRadius = 0.5f*(float) Math.sqrt(dist2(mWaveCenterX, mWaveCenterY));
+ mOuterRadius = 0.5f*(float) Math.sqrt(dist2(centerX, centerY));
}
if (mHitRadius == 0.0f) {
// Use the radius of inscribed circle of the first target.
@@ -613,6 +662,35 @@ public class MultiWaveView extends View implements AnimatorUpdateListener {
mSnapMargin = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
SNAP_MARGIN_DEFAULT, getContext().getResources().getDisplayMetrics());
}
+ hideChevrons();
+ hideTargets(false);
+ moveHandleTo(centerX, centerY, false);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ final int width = right - left;
+ final int height = bottom - top;
+ float newWaveCenterX = mHorizontalOffset + Math.max(width, mOuterRing.getWidth() ) / 2;
+ float newWaveCenterY = mVerticalOffset + Math.max(height, mOuterRing.getHeight()) / 2;
+ if (newWaveCenterX != mWaveCenterX || newWaveCenterY != mWaveCenterY) {
+ if (mWaveCenterX == 0 && mWaveCenterY == 0) {
+ performInitialLayout(newWaveCenterX, newWaveCenterY);
+ }
+ mWaveCenterX = newWaveCenterX;
+ mWaveCenterY = newWaveCenterY;
+
+ mOuterRing.setX(mWaveCenterX);
+ mOuterRing.setY(Math.max(mWaveCenterY, mWaveCenterY));
+
+ updateTargetPositions();
+ }
+ if (DEBUG) dump();
+ }
+
+ private void updateTargetPositions() {
+ // Reposition the target drawables if the view changed.
for (int i = 0; i < mTargetDrawables.size(); i++) {
final TargetDrawable targetIcon = mTargetDrawables.get(i);
double angle = -2.0f * Math.PI * i / mTargetDrawables.size();
@@ -620,11 +698,7 @@ public class MultiWaveView extends View implements AnimatorUpdateListener {
float yPosition = mWaveCenterY + mOuterRadius * (float) Math.sin(angle);
targetIcon.setX(xPosition);
targetIcon.setY(yPosition);
- targetIcon.setAlpha(0.0f);
}
- hideChevrons();
- hideTargets(false);
- if (DEBUG) dump();
}
private void hideChevrons() {
@@ -655,11 +729,6 @@ public class MultiWaveView extends View implements AnimatorUpdateListener {
mOnTriggerListener = listener;
}
- public void onAnimationUpdate(ValueAnimator animation) {
- invalidateGlobalRegion(mHandleDrawable);
- invalidate();
- }
-
private float square(float d) {
return d * d;
}
diff --git a/core/java/com/android/server/NetworkManagementSocketTagger.java b/core/java/com/android/server/NetworkManagementSocketTagger.java
new file mode 100644
index 000000000000..306d2236693a
--- /dev/null
+++ b/core/java/com/android/server/NetworkManagementSocketTagger.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import dalvik.system.SocketTagger;
+import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.SocketException;
+import java.nio.charset.Charsets;
+
+/**
+ * Assigns tags to sockets for traffic stats.
+ */
+public final class NetworkManagementSocketTagger extends SocketTagger {
+
+ private static final boolean LOGI = false;
+
+ private static ThreadLocal<SocketTags> threadSocketTags = new ThreadLocal<SocketTags>() {
+ @Override protected SocketTags initialValue() {
+ return new SocketTags();
+ }
+ };
+
+ public static void install() {
+ SocketTagger.set(new NetworkManagementSocketTagger());
+ }
+
+ public static void setThreadSocketStatsTag(int tag) {
+ threadSocketTags.get().statsTag = tag;
+ }
+
+ public static void setThreadSocketStatsUid(int uid) {
+ threadSocketTags.get().statsUid = uid;
+ }
+
+ @Override public void tag(FileDescriptor fd) throws SocketException {
+ final SocketTags options = threadSocketTags.get();
+ if (LOGI) {
+ System.logI("tagSocket(" + fd.getInt$() + ") with statsTag="
+ + options.statsTag + ", statsUid=" + options.statsUid);
+ }
+ try {
+ // TODO: skip tagging when options would be no-op
+ tagSocketFd(fd, options.statsTag, options.statsUid);
+ } catch (IOException e) {
+ throw new SocketException("Problem tagging socket", e);
+ }
+ }
+
+ private void tagSocketFd(FileDescriptor fd, int tag, int uid) throws IOException {
+ final int fdNum = fd.getInt$();
+ if (fdNum == -1 || (tag == -1 && uid == -1)) return;
+
+ String cmd = "t " + fdNum;
+ if (tag == -1) {
+ // Case where just the uid needs adjusting. But probably the caller
+ // will want to track his own name here, just in case.
+ cmd += " 0";
+ } else {
+ cmd += " " + tagToKernel(tag);
+ }
+ if (uid != -1) {
+ cmd += " " + uid;
+ }
+ internalModuleCtrl(cmd);
+ }
+
+ @Override public void untag(FileDescriptor fd) throws SocketException {
+ if (LOGI) {
+ System.logI("untagSocket(" + fd.getInt$() + ")");
+ }
+ try {
+ unTagSocketFd(fd);
+ } catch (IOException e) {
+ throw new SocketException("Problem untagging socket", e);
+ }
+ }
+
+ private void unTagSocketFd(FileDescriptor fd) throws IOException {
+ int fdNum = fd.getInt$();
+ if (fdNum == -1) return;
+ String cmd = "u " + fdNum;
+ internalModuleCtrl(cmd);
+ }
+
+ public static class SocketTags {
+ public int statsTag = -1;
+ public int statsUid = -1;
+ }
+
+ /**
+ * Sends commands to the kernel netfilter module.
+ *
+ * @param cmd command string for the qtaguid netfilter module. May not be null.
+ * <p>Supports:
+ * <ul><li>tag a socket:<br>
+ * <code>t <i>sock_fd</i> <i>acct_tag</i> [<i>uid_in_case_caller_is_acting_on_behalf_of</i>]</code><br>
+ * <code>*_tag</code> defaults to default_policy_tag_from_uid(uid_of_caller)<br>
+ * <code>acct_tag</code> is either 0 or greater that 2^32.<br>
+ * <code>uid_*</code> is only settable by privileged UIDs (DownloadManager,...)
+ * </li>
+ * <li>untag a socket, preserving counters:<br>
+ * <code>u <i>sock_fd</i></code>
+ * </li></ul>
+ * <p>Notes:<br>
+ * <ul><li><i>sock_fd</i> is withing the callers process space.</li>
+ * <li><i>*_tag</i> are 64bit values</li></ul>
+ *
+ */
+ private void internalModuleCtrl(String cmd) throws IOException {
+ final FileOutputStream procOut;
+ // TODO: Use something like
+ // android.os.SystemProperties.getInt("persist.bandwidth.enable", 0)
+ // to see if tagging should happen or not.
+ try {
+ procOut = new FileOutputStream("/proc/net/xt_qtaguid/ctrl");
+ } catch (FileNotFoundException e) {
+ if (LOGI) {
+ System.logI("Can't talk to kernel module:" + e);
+ }
+ return;
+ }
+ try {
+ procOut.write(cmd.getBytes(Charsets.US_ASCII));
+ } finally {
+ procOut.close();
+ }
+ }
+
+ /**
+ * Convert {@link Integer} tag to {@code /proc/} format. Assumes unsigned
+ * base-10 format like {@code 2147483647}. Currently strips signed bit to
+ * avoid using {@link java.math.BigInteger}.
+ */
+ public static String tagToKernel(int tag) {
+ // TODO: eventually write in hex, since that's what proc exports
+ // TODO: migrate to direct integer instead of odd shifting
+ return Long.toString((((long) tag) << 32) & 0x7FFFFFFF00000000L);
+ }
+
+ /**
+ * Convert {@code /proc/} tag format to {@link Integer}. Assumes incoming
+ * format like {@code 0x7fffffff00000000}.
+ */
+ public static int kernelToTag(String string) {
+ // TODO: migrate to direct integer instead of odd shifting
+ return (int) (Long.decode(string) >> 32);
+ }
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 47902a8bc2ac..1a320608efae 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1384,7 +1384,7 @@
<permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY"
android:label="@string/permlab_readNetworkUsageHistory"
android:description="@string/permdesc_readNetworkUsageHistory"
- android:protectionLevel="signature" />
+ android:protectionLevel="signatureOrSystem" />
<!-- Allows an application to manage network policies (such as warning and disable
limits) and to define application-specific rules. @hide -->
@@ -1393,6 +1393,14 @@
android:description="@string/permdesc_manageNetworkPolicy"
android:protectionLevel="signature" />
+ <!-- Allows an application to account its network traffic against other UIDs. Used
+ by system services like download manager and media server. Not for use by
+ third party apps. @hide -->
+ <permission android:name="android.permission.MODIFY_NETWORK_ACCOUNTING"
+ android:label="@string/permlab_modifyNetworkAccounting"
+ android:description="@string/permdesc_modifyNetworkAccounting"
+ android:protectionLevel="signatureOrSystem" />
+
<!-- C2DM permission.
@hide Used internally.
-->
diff --git a/core/res/res/drawable-hdpi/spinner_black_16.png b/core/res/res/drawable-hdpi/spinner_black_16.png
index eb348679c24e..ef5ca352a754 100644
--- a/core/res/res/drawable-hdpi/spinner_black_16.png
+++ b/core/res/res/drawable-hdpi/spinner_black_16.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_black_20.png b/core/res/res/drawable-hdpi/spinner_black_20.png
index dac06d73be26..d938931d6348 100644
--- a/core/res/res/drawable-hdpi/spinner_black_20.png
+++ b/core/res/res/drawable-hdpi/spinner_black_20.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_black_48.png b/core/res/res/drawable-hdpi/spinner_black_48.png
index 337f72a9cfda..9d1efb7eb623 100644
--- a/core/res/res/drawable-hdpi/spinner_black_48.png
+++ b/core/res/res/drawable-hdpi/spinner_black_48.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_black_76.png b/core/res/res/drawable-hdpi/spinner_black_76.png
index 2edc3e7b9afd..0d90881110d7 100644
--- a/core/res/res/drawable-hdpi/spinner_black_76.png
+++ b/core/res/res/drawable-hdpi/spinner_black_76.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_white_16.png b/core/res/res/drawable-hdpi/spinner_white_16.png
index 7914a689de3e..32fa447b3bf6 100644
--- a/core/res/res/drawable-hdpi/spinner_white_16.png
+++ b/core/res/res/drawable-hdpi/spinner_white_16.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_white_48.png b/core/res/res/drawable-hdpi/spinner_white_48.png
index faee8caedfbc..31fa267f4ab1 100644
--- a/core/res/res/drawable-hdpi/spinner_white_48.png
+++ b/core/res/res/drawable-hdpi/spinner_white_48.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/spinner_white_76.png b/core/res/res/drawable-hdpi/spinner_white_76.png
index cd26379587e8..9f63292046e2 100644
--- a/core/res/res/drawable-hdpi/spinner_white_76.png
+++ b/core/res/res/drawable-hdpi/spinner_white_76.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_default.9.png b/core/res/res/drawable-hdpi/textfield_default.9.png
index 4c20179281b1..f7b6e9974324 100644..100755
--- a/core/res/res/drawable-hdpi/textfield_default.9.png
+++ b/core/res/res/drawable-hdpi/textfield_default.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_disabled.9.png b/core/res/res/drawable-hdpi/textfield_disabled.9.png
index 81569d1b54b8..30115027bf53 100644..100755
--- a/core/res/res/drawable-hdpi/textfield_disabled.9.png
+++ b/core/res/res/drawable-hdpi/textfield_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_disabled_selected.9.png b/core/res/res/drawable-hdpi/textfield_disabled_selected.9.png
index 2591490045a0..e0f82eb06d4b 100644..100755
--- a/core/res/res/drawable-hdpi/textfield_disabled_selected.9.png
+++ b/core/res/res/drawable-hdpi/textfield_disabled_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/textfield_selected.9.png b/core/res/res/drawable-hdpi/textfield_selected.9.png
index a36ed72f487a..cf2cae30bf42 100644..100755
--- a/core/res/res/drawable-hdpi/textfield_selected.9.png
+++ b/core/res/res/drawable-hdpi/textfield_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_black_16.png b/core/res/res/drawable-mdpi/spinner_black_16.png
index 5ee33cea6fa7..4b7fdfe09358 100644
--- a/core/res/res/drawable-mdpi/spinner_black_16.png
+++ b/core/res/res/drawable-mdpi/spinner_black_16.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_black_20.png b/core/res/res/drawable-mdpi/spinner_black_20.png
index e55b60dc6cce..86d7a205e867 100755
--- a/core/res/res/drawable-mdpi/spinner_black_20.png
+++ b/core/res/res/drawable-mdpi/spinner_black_20.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_black_48.png b/core/res/res/drawable-mdpi/spinner_black_48.png
index 3a681926b537..f1571f980f04 100644
--- a/core/res/res/drawable-mdpi/spinner_black_48.png
+++ b/core/res/res/drawable-mdpi/spinner_black_48.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_black_76.png b/core/res/res/drawable-mdpi/spinner_black_76.png
index ec57460277a6..e9f6e8f11ce4 100644
--- a/core/res/res/drawable-mdpi/spinner_black_76.png
+++ b/core/res/res/drawable-mdpi/spinner_black_76.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_white_16.png b/core/res/res/drawable-mdpi/spinner_white_16.png
index dd2e1fd7da16..650e315c7c60 100644
--- a/core/res/res/drawable-mdpi/spinner_white_16.png
+++ b/core/res/res/drawable-mdpi/spinner_white_16.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_white_48.png b/core/res/res/drawable-mdpi/spinner_white_48.png
index d25a33e24534..11eacf8a9a26 100644
--- a/core/res/res/drawable-mdpi/spinner_white_48.png
+++ b/core/res/res/drawable-mdpi/spinner_white_48.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/spinner_white_76.png b/core/res/res/drawable-mdpi/spinner_white_76.png
index f53e8ffdb193..6c31bc39f942 100644
--- a/core/res/res/drawable-mdpi/spinner_white_76.png
+++ b/core/res/res/drawable-mdpi/spinner_white_76.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_default.9.png b/core/res/res/drawable-mdpi/textfield_default.9.png
index cc78e6c92a97..1a59bb2ffe54 100644
--- a/core/res/res/drawable-mdpi/textfield_default.9.png
+++ b/core/res/res/drawable-mdpi/textfield_default.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_disabled.9.png b/core/res/res/drawable-mdpi/textfield_disabled.9.png
index 9c77149beaca..800205af7ebd 100644
--- a/core/res/res/drawable-mdpi/textfield_disabled.9.png
+++ b/core/res/res/drawable-mdpi/textfield_disabled.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_disabled_selected.9.png b/core/res/res/drawable-mdpi/textfield_disabled_selected.9.png
index 6d47708ec9bf..59e1536c9c4e 100644
--- a/core/res/res/drawable-mdpi/textfield_disabled_selected.9.png
+++ b/core/res/res/drawable-mdpi/textfield_disabled_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/textfield_selected.9.png b/core/res/res/drawable-mdpi/textfield_selected.9.png
index 0c1b4461fe07..faadace85cf9 100644
--- a/core/res/res/drawable-mdpi/textfield_selected.9.png
+++ b/core/res/res/drawable-mdpi/textfield_selected.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/popup_bottom_bright.9.png b/core/res/res/drawable-xhdpi/popup_bottom_bright.9.png
new file mode 100644
index 000000000000..cdc0afb4c30e
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/popup_bottom_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/popup_bottom_dark.9.png b/core/res/res/drawable-xhdpi/popup_bottom_dark.9.png
new file mode 100644
index 000000000000..36b044822278
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/popup_bottom_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/popup_bottom_medium.9.png b/core/res/res/drawable-xhdpi/popup_bottom_medium.9.png
new file mode 100644
index 000000000000..3a7a8b347105
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/popup_bottom_medium.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/popup_center_bright.9.png b/core/res/res/drawable-xhdpi/popup_center_bright.9.png
new file mode 100644
index 000000000000..b1a8e3e182a1
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/popup_center_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/popup_center_dark.9.png b/core/res/res/drawable-xhdpi/popup_center_dark.9.png
new file mode 100644
index 000000000000..87378e153330
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/popup_center_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/popup_center_medium.9.png b/core/res/res/drawable-xhdpi/popup_center_medium.9.png
new file mode 100644
index 000000000000..ea29ed48f4ff
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/popup_center_medium.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/popup_full_bright.9.png b/core/res/res/drawable-xhdpi/popup_full_bright.9.png
new file mode 100644
index 000000000000..114faa0e1b8c
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/popup_full_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/popup_full_dark.9.png b/core/res/res/drawable-xhdpi/popup_full_dark.9.png
new file mode 100644
index 000000000000..996beaa6e94b
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/popup_full_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/popup_top_bright.9.png b/core/res/res/drawable-xhdpi/popup_top_bright.9.png
new file mode 100644
index 000000000000..64e41394201c
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/popup_top_bright.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/popup_top_dark.9.png b/core/res/res/drawable-xhdpi/popup_top_dark.9.png
new file mode 100644
index 000000000000..902bc291319e
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/popup_top_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_black_16.png b/core/res/res/drawable-xhdpi/spinner_black_16.png
new file mode 100644
index 000000000000..5b1422ccf45b
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/spinner_black_16.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_black_20.png b/core/res/res/drawable-xhdpi/spinner_black_20.png
new file mode 100644
index 000000000000..5f53e38226af
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/spinner_black_20.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_black_48.png b/core/res/res/drawable-xhdpi/spinner_black_48.png
new file mode 100644
index 000000000000..3aab620dc048
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/spinner_black_48.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_black_76.png b/core/res/res/drawable-xhdpi/spinner_black_76.png
new file mode 100644
index 000000000000..2968d8c376c7
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/spinner_black_76.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_white_16.png b/core/res/res/drawable-xhdpi/spinner_white_16.png
new file mode 100644
index 000000000000..69be75229c28
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/spinner_white_16.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_white_48.png b/core/res/res/drawable-xhdpi/spinner_white_48.png
new file mode 100644
index 000000000000..7b196bce06ae
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/spinner_white_48.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/spinner_white_76.png b/core/res/res/drawable-xhdpi/spinner_white_76.png
new file mode 100644
index 000000000000..ba470057bb0c
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/spinner_white_76.png
Binary files differ
diff --git a/core/res/res/layout-land/ssl_certificate.xml b/core/res/res/layout-land/ssl_certificate.xml
index 56e4e70ca033..c3e6deb832e3 100644
--- a/core/res/res/layout-land/ssl_certificate.xml
+++ b/core/res/res/layout-land/ssl_certificate.xml
@@ -20,6 +20,7 @@
android:layout_height="wrap_content" >
<LinearLayout
+ android:id="@+id/body"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
diff --git a/core/res/res/layout-sw600dp/date_picker_dialog.xml b/core/res/res/layout-sw600dp/date_picker_dialog.xml
new file mode 100644
index 000000000000..004d52a6593b
--- /dev/null
+++ b/core/res/res/layout-sw600dp/date_picker_dialog.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<DatePicker xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/datePicker"
+ android:layout_gravity="center_horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ />
diff --git a/core/res/res/layout-sw600dp/number_picker.xml b/core/res/res/layout-sw600dp/number_picker.xml
new file mode 100644
index 000000000000..807daf2b2dae
--- /dev/null
+++ b/core/res/res/layout-sw600dp/number_picker.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 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.
+*/
+-->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <ImageButton android:id="@+id/increment"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ style="?android:attr/numberPickerUpButtonStyle"
+ android:contentDescription="@string/number_picker_increment_button" />
+
+ <EditText android:id="@+id/numberpicker_input"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ style="?android:attr/numberPickerInputTextStyle" />
+
+ <ImageButton android:id="@+id/decrement"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ style="?android:attr/numberPickerDownButtonStyle"
+ android:contentDescription="@string/number_picker_decrement_button" />
+
+</merge>
diff --git a/core/res/res/layout/date_picker_dialog.xml b/core/res/res/layout/date_picker_dialog.xml
index 004d52a6593b..db8f311c99c7 100644
--- a/core/res/res/layout/date_picker_dialog.xml
+++ b/core/res/res/layout/date_picker_dialog.xml
@@ -22,4 +22,6 @@
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:spinnersShown="true"
+ android:calendarViewShown="false"
/>
diff --git a/core/res/res/layout/date_picker_holo.xml b/core/res/res/layout/date_picker_holo.xml
index 026cbfb8bca1..8627637b3b96 100644
--- a/core/res/res/layout/date_picker_holo.xml
+++ b/core/res/res/layout/date_picker_holo.xml
@@ -77,7 +77,8 @@
android:id="@+id/calendar_view"
android:layout_width="245dip"
android:layout_height="280dip"
- android:layout_marginLeft="22dip"
+ android:layout_marginLeft="16dip"
+ android:layout_marginRight="16dip"
android:layout_weight="1"
android:focusable="true"
android:focusableInTouchMode="true"
diff --git a/core/res/res/layout/keyguard_screen_password_landscape.xml b/core/res/res/layout/keyguard_screen_password_landscape.xml
index 8ba08f68f17f..30df91b24450 100644
--- a/core/res/res/layout/keyguard_screen_password_landscape.xml
+++ b/core/res/res/layout/keyguard_screen_password_landscape.xml
@@ -156,7 +156,7 @@
/>
<!-- Column 1 -->
- <Space android:layout_columnWeight="1" android:layout_rowSpan="11" />
+ <Space android:layout_widthSpec="canStretch" android:layout_rowSpan="11" />
<!-- Column 2 - password entry field and PIN keyboard -->
<LinearLayout
diff --git a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
index 5588adc88a81..c8597209e763 100644
--- a/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
+++ b/core/res/res/layout/keyguard_screen_tab_unlock_land.xml
@@ -169,7 +169,10 @@
</LinearLayout>
<!-- Column 1 -->
- <Space android:width="20dip" android:layout_columnWeight="1" android:layout_rowSpan="10" />
+ <Space
+ android:width="20dip"
+ android:layout_heightSpec="canStretch"
+ android:layout_rowSpan="10" />
<!-- Column 2 -->
<com.android.internal.widget.multiwaveview.MultiWaveView
diff --git a/core/res/res/layout/keyguard_screen_unlock_landscape.xml b/core/res/res/layout/keyguard_screen_unlock_landscape.xml
index d0538dd09b63..0070ed0ec87b 100644
--- a/core/res/res/layout/keyguard_screen_unlock_landscape.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_landscape.xml
@@ -100,9 +100,11 @@
<!-- TODO: remove hard coded height since layout_rowWeight doesn't seem to be working -->
<Space
- android:layout_height="43dip"
- android:layout_gravity="fill"
- android:layout_rowWeight="1" android:layout_columnWeight="1" />
+ android:layout_height="43dip"
+ android:layout_gravity="fill"
+ android:layout_heightSpec="canStretch"
+ android:layout_widthSpec="canStretch"
+ />
<TextView android:id="@+id/carrier"
android:layout_gravity="right"
diff --git a/core/res/res/layout/keyguard_screen_unlock_portrait.xml b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
index 774f830925f5..28c530291bcd 100644
--- a/core/res/res/layout/keyguard_screen_unlock_portrait.xml
+++ b/core/res/res/layout/keyguard_screen_unlock_portrait.xml
@@ -125,7 +125,7 @@
android:layout_marginBottom="4dip"
android:layout_marginLeft="8dip"
android:layout_gravity="center|bottom"
- android:layout_rowWeight="1"
+ android:layout_heightSpec="canStretch"
/>
<TextView
diff --git a/core/res/res/layout/number_picker.xml b/core/res/res/layout/number_picker.xml
index 807daf2b2dae..f2f524caf813 100644
--- a/core/res/res/layout/number_picker.xml
+++ b/core/res/res/layout/number_picker.xml
@@ -23,6 +23,8 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
style="?android:attr/numberPickerUpButtonStyle"
+ android:paddingTop="22dip"
+ android:paddingBottom="22dip"
android:contentDescription="@string/number_picker_increment_button" />
<EditText android:id="@+id/numberpicker_input"
@@ -34,6 +36,8 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
style="?android:attr/numberPickerDownButtonStyle"
+ android:paddingTop="22dip"
+ android:paddingBottom="22dip"
android:contentDescription="@string/number_picker_decrement_button" />
</merge>
diff --git a/core/res/res/layout/search_view.xml b/core/res/res/layout/search_view.xml
index 475aa5922f89..fee27ebe67c3 100644
--- a/core/res/res/layout/search_view.xml
+++ b/core/res/res/layout/search_view.xml
@@ -54,8 +54,8 @@
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"
- android:layout_marginLeft="16dip"
- android:layout_marginRight="16dip"
+ android:layout_marginLeft="8dip"
+ android:layout_marginRight="8dip"
android:layout_marginTop="4dip"
android:layout_marginBottom="4dip"
android:orientation="horizontal">
@@ -87,7 +87,6 @@
android:layout_gravity="bottom"
android:paddingLeft="8dip"
android:paddingRight="6dip"
- android:drawablePadding="2dip"
android:singleLine="true"
android:ellipsize="end"
android:background="@null"
diff --git a/core/res/res/layout/ssl_certificate.xml b/core/res/res/layout/ssl_certificate.xml
index 7206077ce6f5..ae661ce8ef67 100644
--- a/core/res/res/layout/ssl_certificate.xml
+++ b/core/res/res/layout/ssl_certificate.xml
@@ -20,6 +20,7 @@
android:layout_height="wrap_content" >
<LinearLayout
+ android:id="@+id/body"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 4ff8fafdfccd..c84a591097db 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2212,7 +2212,8 @@
<!-- The event types this serivce would like to receive as specified in
{@link android.view.accessibility.AccessibilityEvent}. This setting
can be changed at runtime by calling
- {@link android.accessibilityservice.AccessibilityService#setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)}. -->
+ {@link android.accessibilityservice.AccessibilityService#setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)
+ android.accessibilityservice.AccessibilityService.setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)}. -->
<attr name="accessibilityEventTypes">
<!-- Receives {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_CLICKED} events.-->
<flag name="typeViewClicked" value="0x00000001" />
@@ -2236,17 +2237,24 @@
<flag name="typeTouchExplorationGestureStart" value="0x00000200" />
<!-- Receives {@link android.view.accessibility.AccessibilityEvent#TYPE_TOUCH_EXPLORATION_GESTURE_END} events. -->
<flag name="typeTouchExplorationGestureEnd" value="0x00000400" />
+ <!-- Receives {@link android.view.accessibility.AccessibilityEvent#TYPE_WINDOW_CONTENT_CHANGED} events. -->
+ <flag name="typeWindowContentChanged" value="0x00000800" />
+ <!-- Receives {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_SCROLLED} events. -->
+ <flag name="typeViewScrolled" value="0x000001000" />
+ <!-- Receives {@link android.view.accessibility.AccessibilityEvent#TYPE_VIEW_TEXT_SELECTION_CHANGED} events. -->
+ <flag name="typeViewTextSelectionChanged" value="0x000002000" />
<!-- Receives {@link android.view.accessibility.AccessibilityEvent#TYPES_ALL_MASK} i.e. all events. -->
<flag name="typeAllMask" value="0xffffffff" />
</attr>
<!-- Comma separated package names from which this serivce would like to receive events (leave out for all packages).
- This setting can be changed at runtime by calling
- {@link android.accessibilityservice.AccessibilityService#setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)}. -->
+ {@link android.accessibilityservice.AccessibilityService#setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)
+ android.accessibilityservice.AccessibilityService.setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)}. -->
<attr name="packageNames" format="string" />
<!-- The feedback types this serivce provides as specified in
{@link android.accessibilityservice.AccessibilityServiceInfo}. This setting
can be changed at runtime by calling
- {@link android.accessibilityservice.AccessibilityService#setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)}. -->
+ {@link android.accessibilityservice.AccessibilityService#setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)
+ android.accessibilityservice.AccessibilityService.setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)}. -->
<attr name="accessibilityFeedbackType">
<!-- Provides {@link android.accessibilityservice.AccessibilityServiceInfo#FEEDBACK_SPOKEN} feedback. -->
<flag name="feedbackSpoken" value="0x00000001" />
@@ -2259,14 +2267,16 @@
<!-- Provides {@link android.accessibilityservice.AccessibilityServiceInfo#FEEDBACK_GENERIC} feedback. -->
<flag name="feedbackGeneric" value="0x00000010" />
</attr>
- <!-- The minimal period in milliseconds between two accessibility events are sent
- to this serivce. This setting can be changed at runtime by calling
- {@link android.accessibilityservice.AccessibilityService#setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)}. -->
+ <!-- The minimal period in milliseconds between two accessibility events of the same type
+ are sent to this serivce. This setting can be changed at runtime by calling
+ {@link android.accessibilityservice.AccessibilityService#setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)
+ android.accessibilityservice.AccessibilityService.setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)}. -->>
<attr name="notificationTimeout" format="integer" />
<!-- Additional flags as specified in
{@link android.accessibilityservice.AccessibilityServiceInfo}.
This setting can be changed at runtime by calling
- {@link android.accessibilityservice.AccessibilityService#setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)}. -->
+ {@link android.accessibilityservice.AccessibilityService#setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)
+ android.accessibilityservice.AccessibilityService.setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo)}. -->
<attr name="accessibilityFlags">
<!-- Has flag {@link android.accessibilityservice.AccessibilityServiceInfo#DEFAULT} -->
<flag name="flagDefault" value="0x00000001" />
@@ -2275,7 +2285,7 @@
the settings for this service. This setting cannot be changed at runtime. -->
<attr name="settingsActivity" />
<!-- Flag whether the accessibility service wants to be able to retrieve the
- focused window content. This setting cannot be changed at runtime. -->
+ active window content. This setting cannot be changed at runtime. -->
<attr name="canRetrieveWindowContent" format="boolean" />
</declare-styleable>
@@ -3318,11 +3328,6 @@
The default is one.
See {@link android.widget.GridLayout.Group}. -->
<attr name="layout_rowSpan" format="integer" min="1" />
- <!-- A number indicating the relative proportion of available space that
- should be taken by this group of cells.
- The default is zero.
- See {@link android.widget.GridLayout.LayoutParams#columnWeight}. -->
- <attr name="layout_rowWeight" format="float" />
<!-- The column boundary delimiting the left of the group of cells
occupied by this view. -->
<attr name="layout_column" />
@@ -3331,15 +3336,38 @@
The default is one.
See {@link android.widget.GridLayout.Group}. -->
<attr name="layout_columnSpan" format="integer" min="1" />
- <!-- A number indicating the relative proportion of available space that
- should be taken by this group of cells.
- The default is zero.
- See {@link android.widget.GridLayout.LayoutParams#columnWeight}.-->
- <attr name="layout_columnWeight" format="float" />
<!-- Gravity specifies how a component should be placed in its group of cells.
The default is LEFT | BASELINE.
See {@link android.widget.GridLayout.LayoutParams#setGravity(int)}. -->
<attr name="layout_gravity" />
+ <!-- A value specifying how much deficit or excess width this component can accomodate.
+ The default is FIXED.
+ See {@link android.widget.GridLayout.LayoutParams#widthSpec}.-->
+ <attr name="layout_widthSpec" >
+ <!-- If possible, width should be exactly as specified.
+ See {@link android.widget.GridLayout#FIXED}. -->
+ <enum name="fixed" value="0" />
+ <!-- If possible, width should be less than or equal to the specified width.
+ See {@link android.widget.GridLayout#CAN_SHRINK}. -->
+ <enum name="canShrink" value="1" />
+ <!-- If possible, width should be greater than or equal to the specified width.
+ See {@link android.widget.GridLayout#CAN_STRETCH}. -->
+ <enum name="canStretch" value="2" />
+ </attr>
+ <!-- A value specifying how much deficit or excess height this component can accomodate.
+ The default is FIXED.
+ See {@link android.widget.GridLayout.LayoutParams#heightSpec}.-->
+ <attr name="layout_heightSpec" >
+ <!-- If possible, height should be exactly as specified.
+ See {@link android.widget.GridLayout#FIXED}. -->
+ <enum name="fixed" value="0" />
+ <!-- If possible, height should be less than or equal to the specified height.
+ See {@link android.widget.GridLayout#CAN_SHRINK}. -->
+ <enum name="canShrink" value="1" />
+ <!-- If possible, height should be greater than or equal to the specified height.
+ See {@link android.widget.GridLayout#CAN_STRETCH}. -->
+ <enum name="canStretch" value="2" />
+ </attr>
</declare-styleable>
<declare-styleable name="FrameLayout_Layout">
<attr name="layout_gravity" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 827153e7243e..2c10b3dabe8f 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -658,4 +658,8 @@
This is intended to allow packaging drivers or tools for installation on a PC. -->
<string translatable="false" name="config_isoImagePath"></string>
+ <!-- Whether a software navigation bar should be shown. NOTE: in the future this may be
+ autodetected from the Configuration. -->
+ <bool name="config_showNavigationBar">false</bool>
+
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index db6f98fa3400..945e0c483fad 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1738,9 +1738,11 @@
<public type="attr" name="layout_row" />
<public type="attr" name="layout_rowSpan" />
- <public type="attr" name="layout_rowWeight" />
<public type="attr" name="layout_columnSpan" />
- <public type="attr" name="layout_columnWeight" />
+
+ <public type="attr" name="layout_widthSpec" />
+ <public type="attr" name="layout_heightSpec" />
+
<public type="attr" name="actionModeSelectAllDrawable" />
<public type="attr" name="isAuxiliary" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index cd52a5aea219..c8b3b4fbfa81 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1443,6 +1443,11 @@
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_manageNetworkPolicy">Allows an application to manage network policies and define application-specific rules.</string>
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_modifyNetworkAccounting">modify network usage accounting</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_modifyNetworkAccounting">Allows modification of how network usage is accounted against applications. Not for use by normal applications.</string>
+
<!-- Policy administration -->
<!-- Title of policy access to limiting the user's password choices -->
@@ -2068,6 +2073,18 @@
<!-- Do not translate. Regex used by AutoFill. -->
<string name="autofill_fax_re">fax<!-- fr-FR -->|télécopie|telecopie<!-- ja-JP -->|ファックス<!-- ru -->|факс<!-- zh-CN -->|传真<!-- zh-TW -->|傳真</string>
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_country_code_re">country.*code|ccode|_cc</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_area_code_notext_re">^\($</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_phone_prefix_separator_re">^-$|^\)$</string>
+
+ <!-- Do not translate. Regex used by AutoFill. -->
+ <string name="autofill_phone_suffix_separator_re">^-$</string>
+
<!-- Title of an application permission, listed so the user can choose whether
they want to allow the application to do this. -->
<string name="permlab_readHistoryBookmarks">read Browser\'s history and bookmarks</string>
@@ -2608,10 +2625,14 @@
<!-- USB_STORAGE_ERROR dialog ok button-->
<string name="dlg_ok">OK</string>
- <!-- USB_PREFERENCES: When the user connects the phone to a computer via USB, we show a notification asking if he wants to share files across. This is the title -->
- <string name="usb_preferences_notification_title">USB connected</string>
+ <!-- USB_PREFERENCES: Notification for wehen the user connects the phone to a computer via USB in MTP mode. This is the title -->
+ <string name="usb_mtp_notification_title">Connected as a media device</string>
+ <!-- USB_PREFERENCES: Notification for wehen the user connects the phone to a computer via USB in PTP mode. This is the title -->
+ <string name="usb_ptp_notification_title">Connected as a camera</string>
+ <!-- USB_PREFERENCES: Notification for wehen the user connects the phone to a computer via USB in mass storage mode (for installer CD image). This is the title -->
+ <string name="usb_cd_installer_notification_title">Connected as an installer</string>
<!-- See USB_PREFERENCES. This is the message. -->
- <string name="usb_preferece_notification_message">Select to configure USB file transfer.</string>
+ <string name="usb_notification_message">Touch for other USB options</string>
<!-- External media format dialog strings -->
<!-- This is the label for the activity, and should never be visible to the user. -->
@@ -2783,10 +2804,10 @@
<string name="l2tp_ipsec_psk_vpn_description">Pre-shared key based L2TP/IPSec VPN</string>
<string name="l2tp_ipsec_crt_vpn_description">Certificate based L2TP/IPSec VPN</string>
- <!-- Ticker text to show when VPN is active. -->
- <string name="vpn_ticker"><xliff:g id="app" example="FooVPN client">%s</xliff:g> is activating VPN...</string>
<!-- The title of the notification when VPN is active. -->
- <string name="vpn_title">VPN is activated by <xliff:g id="app" example="FooVPN client">%s</xliff:g></string>
+ <string name="vpn_title">VPN is activated.</string>
+ <!-- The title of the notification when VPN is active with an application name. -->
+ <string name="vpn_title_long">VPN is activated by <xliff:g id="app" example="FooVPN client">%s</xliff:g></string>
<!-- The text of the notification when VPN is active. -->
<string name="vpn_text">Tap to manage the network.</string>
<!-- The text of the notification when VPN is active with a session name. -->
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index b9c0d80ce25d..0b8d40f5d97c 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -84,6 +84,16 @@
<group gid="diag" />
</permission>
+ <!-- Group that can read detailed network usage statistics -->
+ <permission name="android.permission.READ_NETWORK_USAGE_HISTORY">
+ <group gid="net_bw_stats" />
+ </permission>
+
+ <!-- Group that can modify how network statistics are accounted -->
+ <permission name="android.permission.MODIFY_NETWORK_ACCOUNTING">
+ <group gid="net_bw_acct" />
+ </permission>
+
<!-- ================================================================== -->
<!-- ================================================================== -->
<!-- ================================================================== -->
diff --git a/data/fonts/DroidSansHebrew-Bold.ttf b/data/fonts/DroidSansHebrew-Bold.ttf
new file mode 100644
index 000000000000..c1acb38df569
--- /dev/null
+++ b/data/fonts/DroidSansHebrew-Bold.ttf
Binary files differ
diff --git a/data/fonts/DroidSansHebrew-Regular.ttf b/data/fonts/DroidSansHebrew-Regular.ttf
new file mode 100644
index 000000000000..af6a58d8a500
--- /dev/null
+++ b/data/fonts/DroidSansHebrew-Regular.ttf
Binary files differ
diff --git a/data/fonts/DroidSansHebrew.ttf b/data/fonts/DroidSansHebrew.ttf
deleted file mode 100644
index 8d77e3e4cfaf..000000000000
--- a/data/fonts/DroidSansHebrew.ttf
+++ /dev/null
Binary files differ
diff --git a/data/fonts/fonts.mk b/data/fonts/fonts.mk
index 692ce3425d1e..d222c0b4d20e 100644
--- a/data/fonts/fonts.mk
+++ b/data/fonts/fonts.mk
@@ -18,7 +18,8 @@ PRODUCT_COPY_FILES := \
frameworks/base/data/fonts/DroidSans.ttf:system/fonts/DroidSans.ttf \
frameworks/base/data/fonts/DroidSans-Bold.ttf:system/fonts/DroidSans-Bold.ttf \
frameworks/base/data/fonts/DroidSansArabic.ttf:system/fonts/DroidSansArabic.ttf \
- frameworks/base/data/fonts/DroidSansHebrew.ttf:system/fonts/DroidSansHebrew.ttf \
+ frameworks/base/data/fonts/DroidSansHebrew-Regular.ttf:system/fonts/DroidSansHebrew-Regular.ttf \
+ frameworks/base/data/fonts/DroidSansHebrew-Bold.ttf:system/fonts/DroidSansHebrew-Bold.ttf \
frameworks/base/data/fonts/DroidSansThai.ttf:system/fonts/DroidSansThai.ttf \
frameworks/base/data/fonts/DroidSerif-Regular.ttf:system/fonts/DroidSerif-Regular.ttf \
frameworks/base/data/fonts/DroidSerif-Bold.ttf:system/fonts/DroidSerif-Bold.ttf \
diff --git a/docs/html/sdk/android-3.1-highlights.jd b/docs/html/sdk/android-3.1-highlights.jd
index 3d132a3e8802..88bc1eec0c55 100644
--- a/docs/html/sdk/android-3.1-highlights.jd
+++ b/docs/html/sdk/android-3.1-highlights.jd
@@ -143,8 +143,8 @@ point, select, drag, scroll, hover, and other standard actions.</p>
<p>To make the platform even better for gaming, Android 3.1 adds support for
most PC joysticks and gamepads that are connected over USB or Bluetooth HID.</p>
-<p>For example, users can connect Sony Playstation&trade; 3 and XBox 360&trade; game
-controllers over USB (but not Bluetooth), Logitech Dual Action&trade; gamepads and
+<p>For example, users can connect PlayStation<sup>&reg;</sup>3 and Xbox 360<sup>&reg;</sup>
+game controllers over USB (but not Bluetooth), Logitech Dual Action&trade; gamepads and
flight sticks, or a car racing controller. Game controllers that use proprietary
networking or pairing are not supported by default, but in general, the platform
supports most PC-connectible joysticks and gamepads.</p>
diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java
index 90a7ac22335b..1647ff3481a1 100644
--- a/graphics/java/android/graphics/SurfaceTexture.java
+++ b/graphics/java/android/graphics/SurfaceTexture.java
@@ -174,12 +174,15 @@ public class SurfaceTexture {
* Retrieve the timestamp associated with the texture image set by the most recent call to
* updateTexImage.
*
- * This timestamp is in nanoseconds, and is guaranteed to be monotonically increasing. The
+ * This timestamp is in nanoseconds, and is normally monotonically increasing. The timestamp
+ * should be unaffected by time-of-day adjustments, and for a camera should be strictly
+ * monotonic but for a MediaPlayer may be reset when the position is set. The
* specific meaning and zero point of the timestamp depends on the source providing images to
* the SurfaceTexture. Unless otherwise specified by the image source, timestamps cannot
* generally be compared across SurfaceTexture instances, or across multiple program
* invocations. It is mostly useful for determining time offsets between subsequent frames.
*/
+
public long getTimestamp() {
return nativeGetTimestamp();
}
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index c82fb9b77ed4..e36360c167a8 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -139,7 +139,7 @@ public:
// setFrameAvailableListener sets the listener object that will be notified
// when a new frame becomes available.
- void setFrameAvailableListener(const sp<FrameAvailableListener>& l);
+ void setFrameAvailableListener(const sp<FrameAvailableListener>& listener);
// getAllocator retrieves the binder object that must be referenced as long
// as the GraphicBuffers dequeued from this SurfaceTexture are referenced.
@@ -343,7 +343,7 @@ private:
uint32_t mNextTransform;
// mTexName is the name of the OpenGL texture to which streamed images will
- // be bound when updateTexImage is called. It is set at construction time
+ // be bound when updateTexImage is called. It is set at construction time
// changed with a call to setTexName.
const GLuint mTexName;
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 18e8a5f39254..4328d3cc6d74 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -103,6 +103,10 @@ public:
virtual status_t initCheck() = 0;
virtual bool hardwareOutput() = 0;
+ virtual status_t setUID(uid_t uid) {
+ return INVALID_OPERATION;
+ }
+
virtual status_t setDataSource(
const char *url,
const KeyedVector<String8, String8> *headers = NULL) = 0;
diff --git a/include/media/stagefright/MediaSource.h b/include/media/stagefright/MediaSource.h
index a31395ed9509..37dbcd8eae84 100644
--- a/include/media/stagefright/MediaSource.h
+++ b/include/media/stagefright/MediaSource.h
@@ -22,6 +22,7 @@
#include <media/stagefright/MediaErrors.h>
#include <utils/RefBase.h>
+#include <utils/Vector.h>
namespace android {
@@ -99,6 +100,15 @@ struct MediaSource : public RefBase {
return ERROR_UNSUPPORTED;
}
+ // The consumer of this media source requests that the given buffers
+ // are to be returned exclusively in response to read calls.
+ // This will be called after a successful start() and before the
+ // first read() call.
+ // Callee assumes ownership of the buffers if no error is returned.
+ virtual status_t setBuffers(const Vector<MediaBuffer *> &buffers) {
+ return ERROR_UNSUPPORTED;
+ }
+
protected:
virtual ~MediaSource();
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 99b72ad86415..57f678c75512 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -121,6 +121,8 @@ enum {
// To store the timed text format data
kKeyTextFormatData = 'text', // raw data
+
+ kKeyRequiresSecureBuffers = 'secu', // bool (int32_t)
};
enum {
diff --git a/include/media/stagefright/MetadataBufferType.h b/include/media/stagefright/MetadataBufferType.h
new file mode 100644
index 000000000000..275c19f679d5
--- /dev/null
+++ b/include/media/stagefright/MetadataBufferType.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 METADATA_BUFFER_TYPE_H
+#define METADATA_BUFFER_TYPE_H
+
+namespace android {
+/*
+ * MetadataBufferType defines the type of the metadata buffers that
+ * can be passed to video encoder component for encoding, via Stagefright
+ * media recording framework. To see how to work with the metadata buffers
+ * in media recording framework, please consult HardwareAPI.h
+ *
+ * The creator of metadata buffers and video encoder share common knowledge
+ * on what is actually being stored in these metadata buffers, and
+ * how the information can be used by the video encoder component
+ * to locate the actual pixel data as the source input for video
+ * encoder, plus whatever other information that is necessary. Stagefright
+ * media recording framework does not need to know anything specific about the
+ * metadata buffers, except for receving each individual metadata buffer
+ * as the source input, making a copy of the metadata buffer, and passing the
+ * copy via OpenMAX API to the video encoder component.
+ *
+ * The creator of the metadata buffers must ensure that the first
+ * 4 bytes in every metadata buffer indicates its buffer type,
+ * and the rest of the metadata buffer contains the
+ * actual metadata information. When a video encoder component receives
+ * a metadata buffer, it uses the first 4 bytes in that buffer to find
+ * out the type of the metadata buffer, and takes action appropriate
+ * to that type of metadata buffers (for instance, locate the actual
+ * pixel data input and then encoding the input data to produce a
+ * compressed output buffer).
+ *
+ * The following shows the layout of a metadata buffer,
+ * where buffer type is a 4-byte field of MetadataBufferType,
+ * and the payload is the metadata information.
+ *
+ * --------------------------------------------------------------
+ * | buffer type | payload |
+ * --------------------------------------------------------------
+ *
+ */
+typedef enum {
+
+ /*
+ * kMetadataBufferTypeCameraSource is used to indicate that
+ * the source of the metadata buffer is the camera component.
+ */
+ kMetadataBufferTypeCameraSource = 0,
+
+ /*
+ * kMetadataBufferTypeGrallocSource is used to indicate that
+ * the payload of the metadata buffers can be interpreted as
+ * a buffer_handle_t.
+ */
+ kMetadataBufferTypeGrallocSource = 1,
+
+ // Add more here...
+
+} MetadataBufferType;
+
+} // namespace android
+
+#endif // METADATA_BUFFER_TYPE_H
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 92331a16f96a..7f3c497ecb32 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -53,6 +53,9 @@ struct OMXCodec : public MediaSource,
// Enable GRALLOC_USAGE_PROTECTED for output buffers from native window
kEnableGrallocUsageProtected = 128,
+
+ // Secure decoding mode
+ kUseSecureInputBuffers = 256,
};
static sp<MediaSource> Create(
const sp<IOMX> &omx,
@@ -164,6 +167,10 @@ private:
bool mOMXLivesLocally;
IOMX::node_id mNode;
uint32_t mQuirks;
+
+ // Flags specified in the creation of the codec.
+ uint32_t mFlags;
+
bool mIsEncoder;
char *mMIME;
char *mComponentName;
@@ -205,15 +212,12 @@ private:
List<size_t> mFilledBuffers;
Condition mBufferFilled;
- bool mIsMetaDataStoredInVideoBuffers;
- bool mOnlySubmitOneBufferAtOneTime;
- bool mEnableGrallocUsageProtected;
-
// Used to record the decoding time for an output picture from
// a video encoder.
List<int64_t> mDecodingTimeList;
- OMXCodec(const sp<IOMX> &omx, IOMX::node_id node, uint32_t quirks,
+ OMXCodec(const sp<IOMX> &omx, IOMX::node_id node,
+ uint32_t quirks, uint32_t flags,
bool isEncoder, const char *mime, const char *componentName,
const sp<MediaSource> &source,
const sp<ANativeWindow> &nativeWindow);
@@ -287,6 +291,10 @@ private:
void drainInputBuffers();
void fillOutputBuffers();
+ bool drainAnyInputBuffer();
+ BufferInfo *findInputBufferByDataPointer(void *ptr);
+ BufferInfo *findEmptyInputBuffer();
+
// Returns true iff a flush was initiated and a completion event is
// upcoming, false otherwise (A flush was not necessary as we own all
// the buffers on that port).
@@ -313,7 +321,7 @@ private:
void dumpPortStatus(OMX_U32 portIndex);
- status_t configureCodec(const sp<MetaData> &meta, uint32_t flags);
+ status_t configureCodec(const sp<MetaData> &meta);
static uint32_t getComponentQuirks(
const char *componentName, bool isEncoder);
diff --git a/include/private/surfaceflinger/LayerState.h b/include/private/surfaceflinger/LayerState.h
index d7fe572e954e..d2fed418f0d3 100644
--- a/include/private/surfaceflinger/LayerState.h
+++ b/include/private/surfaceflinger/LayerState.h
@@ -29,6 +29,7 @@
namespace android {
class Parcel;
+class ISurfaceComposerClient;
struct layer_state_t {
@@ -68,6 +69,13 @@ struct layer_state_t {
Region transparentRegion;
};
+struct ComposerState {
+ sp<ISurfaceComposerClient> client;
+ layer_state_t state;
+ status_t write(Parcel& output) const;
+ status_t read(const Parcel& input);
+};
+
}; // namespace android
#endif // ANDROID_SF_LAYER_STATE_H
diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h
index 03fd01b31850..dba98a32c325 100644
--- a/include/surfaceflinger/ISurfaceComposer.h
+++ b/include/surfaceflinger/ISurfaceComposer.h
@@ -34,6 +34,7 @@ namespace android {
// ----------------------------------------------------------------------------
class IMemoryHeap;
+class ComposerState;
class ISurfaceComposer : public IInterface
{
@@ -105,8 +106,7 @@ public:
virtual sp<IMemoryHeap> getCblk() const = 0;
/* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */
- virtual void openGlobalTransaction() = 0;
- virtual void closeGlobalTransaction() = 0;
+ virtual void setTransactionState(const Vector<ComposerState>& state) = 0;
/* [un]freeze display. requires ACCESS_SURFACE_FLINGER permission */
virtual status_t freezeDisplay(DisplayID dpy, uint32_t flags) = 0;
@@ -149,8 +149,7 @@ public:
CREATE_CONNECTION,
CREATE_GRAPHIC_BUFFER_ALLOC,
GET_CBLK,
- OPEN_GLOBAL_TRANSACTION,
- CLOSE_GLOBAL_TRANSACTION,
+ SET_TRANSACTION_STATE,
SET_ORIENTATION,
FREEZE_DISPLAY,
UNFREEZE_DISPLAY,
diff --git a/include/surfaceflinger/ISurfaceComposerClient.h b/include/surfaceflinger/ISurfaceComposerClient.h
index 2e75a0e4cfd9..6e9a654642c5 100644
--- a/include/surfaceflinger/ISurfaceComposerClient.h
+++ b/include/surfaceflinger/ISurfaceComposerClient.h
@@ -37,8 +37,6 @@ typedef int32_t DisplayID;
// ----------------------------------------------------------------------------
-class layer_state_t;
-
class ISurfaceComposerClient : public IInterface
{
public:
@@ -69,11 +67,6 @@ public:
* Requires ACCESS_SURFACE_FLINGER permission
*/
virtual status_t destroySurface(SurfaceID sid) = 0;
-
- /*
- * Requires ACCESS_SURFACE_FLINGER permission
- */
- virtual status_t setState(int32_t count, const layer_state_t* states) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/surfaceflinger/SurfaceComposerClient.h b/include/surfaceflinger/SurfaceComposerClient.h
index 140b9f860bfd..7fbbfb24f03a 100644
--- a/include/surfaceflinger/SurfaceComposerClient.h
+++ b/include/surfaceflinger/SurfaceComposerClient.h
@@ -37,10 +37,12 @@ namespace android {
// ---------------------------------------------------------------------------
class DisplayInfo;
+class Composer;
class IMemoryHeap;
class ISurfaceComposer;
class Region;
class surface_flinger_cblk_t;
+struct layer_state_t;
// ---------------------------------------------------------------------------
@@ -59,8 +61,11 @@ public:
// ---------------------------------------------------------------------------
+class Composer;
+
class SurfaceComposerClient : public RefBase
{
+ friend class Composer;
public:
SurfaceComposerClient();
virtual ~SurfaceComposerClient();
@@ -101,13 +106,7 @@ public:
// All composer parameters must be changed within a transaction
// several surfaces can be updated in one transaction, all changes are
// committed at once when the transaction is closed.
- // CloseTransaction() usually requires an IPC with the server.
-
- //! Open a composer transaction
- status_t openTransaction();
-
- //! commit the transaction
- status_t closeTransaction();
+ // closeGlobalTransaction() usually requires an IPC with the server.
//! Open a composer transaction on all active SurfaceComposerClients.
static void openGlobalTransaction();
@@ -152,19 +151,12 @@ public:
private:
virtual void onFirstRef();
- inline layer_state_t* get_state_l(SurfaceID id);
- layer_state_t* lockLayerState(SurfaceID id);
- inline void unlockLayerState();
-
- mutable Mutex mLock;
- SortedVector<layer_state_t> mStates;
- int32_t mTransactionOpen;
- layer_state_t* mPrebuiltLayerState;
+ Composer& getComposer();
- // these don't need to be protected because they never change
- // after assignment
+ mutable Mutex mLock;
status_t mStatus;
sp<ISurfaceComposerClient> mClient;
+ Composer& mComposer;
};
// ---------------------------------------------------------------------------
diff --git a/include/utils/LinearTransform.h b/include/utils/LinearTransform.h
new file mode 100644
index 000000000000..04cb355c7ff7
--- /dev/null
+++ b/include/utils/LinearTransform.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 _LIBS_UTILS_LINEAR_TRANSFORM_H
+#define _LIBS_UTILS_LINEAR_TRANSFORM_H
+
+#include <stdint.h>
+
+namespace android {
+
+// LinearTransform defines a structure which hold the definition of a
+// transformation from single dimensional coordinate system A into coordinate
+// system B (and back again). Values in A and in B are 64 bit, the linear
+// scale factor is expressed as a rational number using two 32 bit values.
+//
+// Specifically, let
+// f(a) = b
+// F(b) = f^-1(b) = a
+// then
+//
+// f(a) = (((a - a_zero) * a_to_b_numer) / a_to_b_denom) + b_zero;
+//
+// and
+//
+// F(b) = (((b - b_zero) * a_to_b_denom) / a_to_b_numer) + a_zero;
+//
+struct LinearTransform {
+ int64_t a_zero;
+ int64_t b_zero;
+ int32_t a_to_b_numer;
+ uint32_t a_to_b_denom;
+
+ // Transform from A->B
+ // Returns true on success, or false in the case of a singularity or an
+ // overflow.
+ bool doForwardTransform(int64_t a_in, int64_t* b_out) const;
+
+ // Transform from B->A
+ // Returns true on success, or false in the case of a singularity or an
+ // overflow.
+ bool doReverseTransform(int64_t b_in, int64_t* a_out) const;
+
+ // Helpers which will reduce the fraction N/D using Euclid's method.
+ template <class T> static void reduce(T* N, T* D);
+ static void reduce(int32_t* N, uint32_t* D);
+};
+
+
+}
+
+#endif // _LIBS_UTILS_LINEAR_TRANSFORM_H
diff --git a/include/utils/SortedVector.h b/include/utils/SortedVector.h
index 8beec573205e..0e98aeb05fd8 100644
--- a/include/utils/SortedVector.h
+++ b/include/utils/SortedVector.h
@@ -32,6 +32,8 @@ namespace android {
template <class TYPE>
class SortedVector : private SortedVectorImpl
{
+ friend class Vector<TYPE>;
+
public:
typedef TYPE value_type;
diff --git a/include/utils/Vector.h b/include/utils/Vector.h
index f1e87e60907e..b908e2ab2e2c 100644
--- a/include/utils/Vector.h
+++ b/include/utils/Vector.h
@@ -29,6 +29,9 @@
namespace android {
+template <typename TYPE>
+class SortedVector;
+
/*!
* The main templated vector class ensuring type safety
* while making use of VectorImpl.
@@ -47,13 +50,17 @@ public:
Vector();
Vector(const Vector<TYPE>& rhs);
+ explicit Vector(const SortedVector<TYPE>& rhs);
virtual ~Vector();
/*! copy operator */
const Vector<TYPE>& operator = (const Vector<TYPE>& rhs) const;
Vector<TYPE>& operator = (const Vector<TYPE>& rhs);
- /*
+ const Vector<TYPE>& operator = (const SortedVector<TYPE>& rhs) const;
+ Vector<TYPE>& operator = (const SortedVector<TYPE>& rhs);
+
+ /*
* empty the vector
*/
@@ -215,6 +222,11 @@ Vector<TYPE>::Vector(const Vector<TYPE>& rhs)
}
template<class TYPE> inline
+Vector<TYPE>::Vector(const SortedVector<TYPE>& rhs)
+ : VectorImpl(static_cast<const VectorImpl&>(rhs)) {
+}
+
+template<class TYPE> inline
Vector<TYPE>::~Vector() {
finish_vector();
}
@@ -227,6 +239,18 @@ Vector<TYPE>& Vector<TYPE>::operator = (const Vector<TYPE>& rhs) {
template<class TYPE> inline
const Vector<TYPE>& Vector<TYPE>::operator = (const Vector<TYPE>& rhs) const {
+ VectorImpl::operator = (static_cast<const VectorImpl&>(rhs));
+ return *this;
+}
+
+template<class TYPE> inline
+Vector<TYPE>& Vector<TYPE>::operator = (const SortedVector<TYPE>& rhs) {
+ VectorImpl::operator = (static_cast<const VectorImpl&>(rhs));
+ return *this;
+}
+
+template<class TYPE> inline
+const Vector<TYPE>& Vector<TYPE>::operator = (const SortedVector<TYPE>& rhs) const {
VectorImpl::operator = (rhs);
return *this;
}
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index ab4b9e04d671..f75208dfd0aa 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -60,16 +60,10 @@ public class Credentials {
public static final String WIFI = "WIFI_";
/** Data type for public keys. */
- public static final String PUBLIC_KEY = "KEY";
+ public static final String EXTRA_PUBLIC_KEY = "KEY";
/** Data type for private keys. */
- public static final String PRIVATE_KEY = "PKEY";
-
- /** Data type for certificates. */
- public static final String CERTIFICATE = "CERT";
-
- /** Data type for PKCS12. */
- public static final String PKCS12 = "PKCS12";
+ public static final String EXTRA_PRIVATE_KEY = "PKEY";
// historically used by Android
public static final String EXTENSION_CRT = ".crt";
@@ -130,16 +124,9 @@ public class Credentials {
}
}
- private Intent createInstallIntent() {
- Intent intent = new Intent(INSTALL_ACTION);
- intent.setClassName("com.android.certinstaller",
- "com.android.certinstaller.CertInstallerMain");
- return intent;
- }
-
public void install(Context context) {
try {
- Intent intent = createInstallIntent();
+ Intent intent = KeyChain.createInstallIntent();
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.w(LOGTAG, e.toString());
@@ -148,9 +135,9 @@ public class Credentials {
public void install(Context context, KeyPair pair) {
try {
- Intent intent = createInstallIntent();
- intent.putExtra(PRIVATE_KEY, pair.getPrivate().getEncoded());
- intent.putExtra(PUBLIC_KEY, pair.getPublic().getEncoded());
+ Intent intent = KeyChain.createInstallIntent();
+ intent.putExtra(EXTRA_PRIVATE_KEY, pair.getPrivate().getEncoded());
+ intent.putExtra(EXTRA_PUBLIC_KEY, pair.getPublic().getEncoded());
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.w(LOGTAG, e.toString());
@@ -159,7 +146,7 @@ public class Credentials {
public void install(Context context, String type, byte[] value) {
try {
- Intent intent = createInstallIntent();
+ Intent intent = KeyChain.createInstallIntent();
intent.putExtra(type, value);
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 18011e618f49..e91bcab55401 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -45,8 +45,12 @@ import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
+import libcore.util.Objects;
+import org.apache.harmony.xnet.provider.jsse.TrustedCertificateStore;
/**
* The {@code KeyChain} class provides access to private keys and
@@ -89,31 +93,117 @@ public final class KeyChain {
public static final String ACCOUNT_TYPE = "com.android.keychain";
/**
+ * Action to bring up the KeyChainActivity
+ */
+ private static final String ACTION_CHOOSER = "com.android.keychain.CHOOSER";
+
+ /**
+ * Extra for use with {@link #ACTION_CHOOSER}
* @hide Also used by KeyChainActivity implementation
*/
public static final String EXTRA_RESPONSE = "response";
/**
+ * Extra for use with {@link #ACTION_CHOOSER}
* @hide Also used by KeyChainActivity implementation
*/
public static final String EXTRA_HOST = "host";
/**
+ * Extra for use with {@link #ACTION_CHOOSER}
* @hide Also used by KeyChainActivity implementation
*/
public static final String EXTRA_PORT = "port";
/**
+ * Extra for use with {@link #ACTION_CHOOSER}
* @hide Also used by KeyChainActivity implementation
*/
public static final String EXTRA_ALIAS = "alias";
/**
+ * Extra for use with {@link #ACTION_CHOOSER}
* @hide Also used by KeyChainActivity implementation
*/
public static final String EXTRA_SENDER = "sender";
/**
+ * Action to bring up the CertInstaller
+ */
+ private static final String ACTION_INSTALL = "android.credentials.INSTALL";
+
+ /**
+ * Optional extra to specify a {@code String} credential name on
+ * the {@code Intent} returned by {@link #createInstallIntent}.
+ *
+ * @hide TODO make public
+ */
+ // Compatible with old com.android.certinstaller.CredentialHelper.CERT_NAME_KEY
+ public static final String EXTRA_NAME = "name";
+
+ /**
+ * Optional extra to specify an X.509 certificate to install on
+ * the {@code Intent} returned by {@link #createInstallIntent}.
+ * The extra value should be a PEM or ASN.1 DER encoded {@code
+ * byte[]}. An {@link X509Certificate} can be converted to DER
+ * encoded bytes with {@link X509Certificate#getEncoded}.
+ *
+ * <p>{@link #EXTRA_NAME} may be used to provide a default alias
+ * name for the installed certificate.
+ *
+ * @hide TODO make public
+ */
+ // Compatible with old android.security.Credentials.CERTIFICATE
+ public static final String EXTRA_CERTIFICATE = "CERT";
+
+ /**
+ * Optional extra for use with the {@code Intent} returned by
+ * {@link #createInstallIntent} to specify a PKCS#12 key store to
+ * install. The extra value should be a {@code byte[]}. The bytes
+ * may come from an external source or be generated with {@link
+ * KeyStore#store} on a "PKCS12" instance.
+ *
+ * <p>The user will be prompted for the password to load the key store.
+ *
+ * <p>The key store will be scanned for {@link
+ * java.security.KeyStore.PrivateKeyEntry} entries and both the
+ * private key and associated certificate chain will be installed.
+ *
+ * <p>{@link #EXTRA_NAME} may be used to provide a default alias
+ * name for the installed credentials.
+ *
+ * @hide TODO make public
+ */
+ // Compatible with old android.security.Credentials.PKCS12
+ public static final String EXTRA_PKCS12 = "PKCS12";
+
+ /**
+ * Returns an {@code Intent} that can be used for credential
+ * installation. The intent may be used without any extras, in
+ * which case the user will be able to install credentials from
+ * their own source.
+ *
+ * <p>Alternatively, {@link #EXTRA_CERTIFICATE} or {@link
+ * #EXTRA_PKCS12} maybe used to specify the bytes of an X.509
+ * certificate or a PKCS#12 key store for installation. These
+ * extras may be combined with {@link EXTRA_NAME} to provide a
+ * default alias name for credentials being installed.
+ *
+ * <p>When used with {@link Activity#startActivityForResult},
+ * {@link Activity#RESULT_OK} will be returned if a credential was
+ * successfully installed, otherwise {@link
+ * Activity#RESULT_CANCELED} will be returned.
+ *
+ * @hide TODO make public with createInstallIntent, EXTRA_NAME, EXTRA_CERTIFICATE, EXTRA_PKCS12
+ */
+ public static Intent createInstallIntent() {
+ Intent intent = new Intent(ACTION_INSTALL);
+ intent.setClassName("com.android.certinstaller",
+ "com.android.certinstaller.CertInstallerMain");
+ return intent;
+ }
+
+ /**
* Launches an {@code Activity} for the user to select the alias
* for a private key and certificate pair for authentication. The
* selected alias or null will be returned via the
@@ -176,7 +266,7 @@ public final class KeyChain {
if (response == null) {
throw new NullPointerException("response == null");
}
- Intent intent = new Intent("com.android.keychain.CHOOSER");
+ Intent intent = new Intent(ACTION_CHOOSER);
intent.putExtra(EXTRA_RESPONSE, new AliasResponse(activity, response));
intent.putExtra(EXTRA_HOST, host);
intent.putExtra(EXTRA_PORT, port);
@@ -299,7 +389,21 @@ public final class KeyChain {
}
IKeyChainService keyChainService = keyChainConnection.getService();
byte[] certificateBytes = keyChainService.getCertificate(alias, authToken);
- return new X509Certificate[] { toCertificate(certificateBytes) };
+ List<X509Certificate> chain = new ArrayList<X509Certificate>();
+ chain.add(toCertificate(certificateBytes));
+ TrustedCertificateStore store = new TrustedCertificateStore();
+ for (int i = 0; true; i++) {
+ X509Certificate cert = chain.get(i);
+ if (Objects.equal(cert.getSubjectX500Principal(), cert.getIssuerX500Principal())) {
+ break;
+ }
+ X509Certificate issuer = store.findIssuer(cert);
+ if (issuer == null) {
+ break;
+ }
+ chain.add(issuer);
+ }
+ return chain.toArray(new X509Certificate[chain.size()]);
} catch (RemoteException e) {
throw new KeyChainException(e);
} catch (RuntimeException e) {
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 40450a3d0750..c1156d5c86c5 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -25,6 +25,8 @@
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
+#include <private/surfaceflinger/LayerState.h>
+
#include <surfaceflinger/ISurfaceComposer.h>
#include <ui/DisplayInfo.h>
@@ -74,18 +76,17 @@ public:
return interface_cast<IMemoryHeap>(reply.readStrongBinder());
}
- virtual void openGlobalTransaction()
+ virtual void setTransactionState(const Vector<ComposerState>& state)
{
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- remote()->transact(BnSurfaceComposer::OPEN_GLOBAL_TRANSACTION, data, &reply);
- }
-
- virtual void closeGlobalTransaction()
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
- remote()->transact(BnSurfaceComposer::CLOSE_GLOBAL_TRANSACTION, data, &reply);
+ Vector<ComposerState>::const_iterator b(state.begin());
+ Vector<ComposerState>::const_iterator e(state.end());
+ data.writeInt32(state.size());
+ for ( ; b != e ; ++b ) {
+ b->write(data);
+ }
+ remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply);
}
virtual status_t freezeDisplay(DisplayID dpy, uint32_t flags)
@@ -218,13 +219,17 @@ status_t BnSurfaceComposer::onTransact(
sp<IBinder> b = createGraphicBufferAlloc()->asBinder();
reply->writeStrongBinder(b);
} break;
- case OPEN_GLOBAL_TRANSACTION: {
- CHECK_INTERFACE(ISurfaceComposer, data, reply);
- openGlobalTransaction();
- } break;
- case CLOSE_GLOBAL_TRANSACTION: {
+ case SET_TRANSACTION_STATE: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
- closeGlobalTransaction();
+ size_t count = data.readInt32();
+ ComposerState s;
+ Vector<ComposerState> state;
+ state.setCapacity(count);
+ for (size_t i=0 ; i<count ; i++) {
+ s.read(data);
+ state.add(s);
+ }
+ setTransactionState(state);
} break;
case SET_ORIENTATION: {
CHECK_INTERFACE(ISurfaceComposer, data, reply);
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index 8d8339258860..bc97cacbe0a3 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -51,8 +51,7 @@ namespace android {
enum {
CREATE_SURFACE = IBinder::FIRST_CALL_TRANSACTION,
- DESTROY_SURFACE,
- SET_STATE
+ DESTROY_SURFACE
};
class BpSurfaceComposerClient : public BpInterface<ISurfaceComposerClient>
@@ -92,17 +91,6 @@ public:
remote()->transact(DESTROY_SURFACE, data, &reply);
return reply.readInt32();
}
-
- virtual status_t setState(int32_t count, const layer_state_t* states)
- {
- Parcel data, reply;
- data.writeInterfaceToken(ISurfaceComposerClient::getInterfaceDescriptor());
- data.writeInt32(count);
- for (int i=0 ; i<count ; i++)
- states[i].write(data);
- remote()->transact(SET_STATE, data, &reply);
- return reply.readInt32();
- }
};
IMPLEMENT_META_INTERFACE(SurfaceComposerClient, "android.ui.ISurfaceComposerClient");
@@ -133,17 +121,6 @@ status_t BnSurfaceComposerClient::onTransact(
reply->writeInt32( destroySurface( data.readInt32() ) );
return NO_ERROR;
} break;
- case SET_STATE: {
- CHECK_INTERFACE(ISurfaceComposerClient, data, reply);
- int32_t count = data.readInt32();
- layer_state_t* states = new layer_state_t[count];
- for (int i=0 ; i<count ; i++)
- states[i].read(data);
- status_t err = setState(count, states);
- delete [] states;
- reply->writeInt32(err);
- return NO_ERROR;
- } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 01c4c7ebfe84..87901e87f706 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -17,6 +17,7 @@
#include <utils/Errors.h>
#include <binder/Parcel.h>
#include <private/surfaceflinger/LayerState.h>
+#include <surfaceflinger/ISurfaceComposerClient.h>
namespace android {
@@ -58,4 +59,14 @@ status_t layer_state_t::read(const Parcel& input)
return NO_ERROR;
}
+status_t ComposerState::write(Parcel& output) const {
+ output.writeStrongBinder(client->asBinder());
+ return state.write(output);
+}
+
+status_t ComposerState::read(const Parcel& input) {
+ client = interface_cast<ISurfaceComposerClient>(input.readStrongBinder());
+ return state.read(input);
+}
+
}; // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 1678711aaf42..8cead808a1b2 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -74,75 +74,52 @@ static inline surface_flinger_cblk_t const volatile * get_cblk() {
// ---------------------------------------------------------------------------
+// NOTE: this is NOT a member function (it's a friend defined with its
+// declaration).
+static inline
+int compare_type( const ComposerState& lhs, const ComposerState& rhs) {
+ if (lhs.client < rhs.client) return -1;
+ if (lhs.client > rhs.client) return 1;
+ if (lhs.state.surface < rhs.state.surface) return -1;
+ if (lhs.state.surface > rhs.state.surface) return 1;
+ return 0;
+}
+
class Composer : public Singleton<Composer>
{
- Mutex mLock;
- SortedVector< wp<SurfaceComposerClient> > mActiveConnections;
- SortedVector<sp<SurfaceComposerClient> > mOpenTransactions;
+ friend class Singleton<Composer>;
- Composer() : Singleton<Composer>() {
- }
+ mutable Mutex mLock;
+ SortedVector<ComposerState> mStates;
- void addClientImpl(const sp<SurfaceComposerClient>& client) {
- Mutex::Autolock _l(mLock);
- mActiveConnections.add(client);
- }
+ Composer() : Singleton<Composer>() { }
- void removeClientImpl(const sp<SurfaceComposerClient>& client) {
- Mutex::Autolock _l(mLock);
- mActiveConnections.remove(client);
- }
+ void closeGlobalTransactionImpl();
- void openGlobalTransactionImpl()
- {
- Mutex::Autolock _l(mLock);
- if (mOpenTransactions.size()) {
- LOGE("openGlobalTransaction() called more than once. skipping.");
- return;
- }
- const size_t N = mActiveConnections.size();
- for (size_t i=0; i<N; i++) {
- sp<SurfaceComposerClient> client(mActiveConnections[i].promote());
- if (client != 0 && mOpenTransactions.indexOf(client) < 0) {
- if (client->openTransaction() == NO_ERROR) {
- mOpenTransactions.add(client);
- } else {
- LOGE("openTransaction on client %p failed", client.get());
- // let it go, it'll fail later when the user
- // tries to do something with the transaction
- }
- }
- }
- }
+ layer_state_t* getLayerStateLocked(
+ const sp<SurfaceComposerClient>& client, SurfaceID id);
- void closeGlobalTransactionImpl()
- {
- mLock.lock();
- SortedVector< sp<SurfaceComposerClient> > clients(mOpenTransactions);
- mOpenTransactions.clear();
- mLock.unlock();
-
- sp<ISurfaceComposer> sm(getComposerService());
- sm->openGlobalTransaction();
- const size_t N = clients.size();
- for (size_t i=0; i<N; i++) {
- clients[i]->closeTransaction();
- }
- sm->closeGlobalTransaction();
- }
+public:
- friend class Singleton<Composer>;
+ status_t setPosition(const sp<SurfaceComposerClient>& client, SurfaceID id,
+ int32_t x, int32_t y);
+ status_t setSize(const sp<SurfaceComposerClient>& client, SurfaceID id,
+ uint32_t w, uint32_t h);
+ status_t setLayer(const sp<SurfaceComposerClient>& client, SurfaceID id,
+ int32_t z);
+ status_t setFlags(const sp<SurfaceComposerClient>& client, SurfaceID id,
+ uint32_t flags, uint32_t mask);
+ status_t setTransparentRegionHint(
+ const sp<SurfaceComposerClient>& client, SurfaceID id,
+ const Region& transparentRegion);
+ status_t setAlpha(const sp<SurfaceComposerClient>& client, SurfaceID id,
+ float alpha);
+ status_t setMatrix(const sp<SurfaceComposerClient>& client, SurfaceID id,
+ float dsdx, float dtdx, float dsdy, float dtdy);
+ status_t setFreezeTint(
+ const sp<SurfaceComposerClient>& client, SurfaceID id,
+ uint32_t tint);
-public:
- static void addClient(const sp<SurfaceComposerClient>& client) {
- Composer::getInstance().addClientImpl(client);
- }
- static void removeClient(const sp<SurfaceComposerClient>& client) {
- Composer::getInstance().removeClientImpl(client);
- }
- static void openGlobalTransaction() {
- Composer::getInstance().openGlobalTransactionImpl();
- }
static void closeGlobalTransaction() {
Composer::getInstance().closeGlobalTransactionImpl();
}
@@ -152,127 +129,185 @@ ANDROID_SINGLETON_STATIC_INSTANCE(Composer);
// ---------------------------------------------------------------------------
-static inline int compare_type( const layer_state_t& lhs,
- const layer_state_t& rhs) {
- if (lhs.surface < rhs.surface) return -1;
- if (lhs.surface > rhs.surface) return 1;
- return 0;
+void Composer::closeGlobalTransactionImpl() {
+ sp<ISurfaceComposer> sm(getComposerService());
+
+ Vector<ComposerState> transaction;
+
+ { // scope for the lock
+ Mutex::Autolock _l(mLock);
+ transaction = mStates;
+ mStates.clear();
+ }
+
+ sm->setTransactionState(transaction);
+}
+
+layer_state_t* Composer::getLayerStateLocked(
+ const sp<SurfaceComposerClient>& client, SurfaceID id) {
+
+ ComposerState s;
+ s.client = client->mClient;
+ s.state.surface = id;
+
+ ssize_t index = mStates.indexOf(s);
+ if (index < 0) {
+ // we don't have it, add an initialized layer_state to our list
+ index = mStates.add(s);
+ }
+
+ ComposerState* const out = mStates.editArray();
+ return &(out[index].state);
+}
+
+status_t Composer::setPosition(const sp<SurfaceComposerClient>& client,
+ SurfaceID id, int32_t x, int32_t y) {
+ Mutex::Autolock _l(mLock);
+ layer_state_t* s = getLayerStateLocked(client, id);
+ if (!s)
+ return BAD_INDEX;
+ s->what |= ISurfaceComposer::ePositionChanged;
+ s->x = x;
+ s->y = y;
+ return NO_ERROR;
+}
+
+status_t Composer::setSize(const sp<SurfaceComposerClient>& client,
+ SurfaceID id, uint32_t w, uint32_t h) {
+ Mutex::Autolock _l(mLock);
+ layer_state_t* s = getLayerStateLocked(client, id);
+ if (!s)
+ return BAD_INDEX;
+ s->what |= ISurfaceComposer::eSizeChanged;
+ s->w = w;
+ s->h = h;
+ return NO_ERROR;
+}
+
+status_t Composer::setLayer(const sp<SurfaceComposerClient>& client,
+ SurfaceID id, int32_t z) {
+ Mutex::Autolock _l(mLock);
+ layer_state_t* s = getLayerStateLocked(client, id);
+ if (!s)
+ return BAD_INDEX;
+ s->what |= ISurfaceComposer::eLayerChanged;
+ s->z = z;
+ return NO_ERROR;
+}
+
+status_t Composer::setFlags(const sp<SurfaceComposerClient>& client,
+ SurfaceID id, uint32_t flags,
+ uint32_t mask) {
+ Mutex::Autolock _l(mLock);
+ layer_state_t* s = getLayerStateLocked(client, id);
+ if (!s)
+ return BAD_INDEX;
+ s->what |= ISurfaceComposer::eVisibilityChanged;
+ s->flags &= ~mask;
+ s->flags |= (flags & mask);
+ s->mask |= mask;
+ return NO_ERROR;
+}
+
+status_t Composer::setTransparentRegionHint(
+ const sp<SurfaceComposerClient>& client, SurfaceID id,
+ const Region& transparentRegion) {
+ Mutex::Autolock _l(mLock);
+ layer_state_t* s = getLayerStateLocked(client, id);
+ if (!s)
+ return BAD_INDEX;
+ s->what |= ISurfaceComposer::eTransparentRegionChanged;
+ s->transparentRegion = transparentRegion;
+ return NO_ERROR;
+}
+
+status_t Composer::setAlpha(const sp<SurfaceComposerClient>& client,
+ SurfaceID id, float alpha) {
+ Mutex::Autolock _l(mLock);
+ layer_state_t* s = getLayerStateLocked(client, id);
+ if (!s)
+ return BAD_INDEX;
+ s->what |= ISurfaceComposer::eAlphaChanged;
+ s->alpha = alpha;
+ return NO_ERROR;
+}
+
+status_t Composer::setMatrix(const sp<SurfaceComposerClient>& client,
+ SurfaceID id, float dsdx, float dtdx,
+ float dsdy, float dtdy) {
+ Mutex::Autolock _l(mLock);
+ layer_state_t* s = getLayerStateLocked(client, id);
+ if (!s)
+ return BAD_INDEX;
+ s->what |= ISurfaceComposer::eMatrixChanged;
+ layer_state_t::matrix22_t matrix;
+ matrix.dsdx = dsdx;
+ matrix.dtdx = dtdx;
+ matrix.dsdy = dsdy;
+ matrix.dtdy = dtdy;
+ s->matrix = matrix;
+ return NO_ERROR;
}
+status_t Composer::setFreezeTint(const sp<SurfaceComposerClient>& client,
+ SurfaceID id, uint32_t tint) {
+ Mutex::Autolock _l(mLock);
+ layer_state_t* s = getLayerStateLocked(client, id);
+ if (!s)
+ return BAD_INDEX;
+ s->what |= ISurfaceComposer::eFreezeTintChanged;
+ s->tint = tint;
+ return NO_ERROR;
+}
+
+// ---------------------------------------------------------------------------
+
SurfaceComposerClient::SurfaceComposerClient()
- : mTransactionOpen(0), mPrebuiltLayerState(0), mStatus(NO_INIT)
+ : mStatus(NO_INIT), mComposer(Composer::getInstance())
{
}
-void SurfaceComposerClient::onFirstRef()
-{
+void SurfaceComposerClient::onFirstRef() {
sp<ISurfaceComposer> sm(getComposerService());
if (sm != 0) {
sp<ISurfaceComposerClient> conn = sm->createConnection();
if (conn != 0) {
mClient = conn;
- Composer::addClient(this);
- mPrebuiltLayerState = new layer_state_t;
mStatus = NO_ERROR;
}
}
}
-SurfaceComposerClient::~SurfaceComposerClient()
-{
- delete mPrebuiltLayerState;
+SurfaceComposerClient::~SurfaceComposerClient() {
dispose();
}
-status_t SurfaceComposerClient::initCheck() const
-{
+status_t SurfaceComposerClient::initCheck() const {
return mStatus;
}
-sp<IBinder> SurfaceComposerClient::connection() const
-{
+sp<IBinder> SurfaceComposerClient::connection() const {
return (mClient != 0) ? mClient->asBinder() : 0;
}
status_t SurfaceComposerClient::linkToComposerDeath(
const sp<IBinder::DeathRecipient>& recipient,
- void* cookie, uint32_t flags)
-{
+ void* cookie, uint32_t flags) {
sp<ISurfaceComposer> sm(getComposerService());
return sm->asBinder()->linkToDeath(recipient, cookie, flags);
}
-void SurfaceComposerClient::dispose()
-{
+void SurfaceComposerClient::dispose() {
// this can be called more than once.
sp<ISurfaceComposerClient> client;
Mutex::Autolock _lm(mLock);
if (mClient != 0) {
- Composer::removeClient(this);
client = mClient; // hold ref while lock is held
mClient.clear();
}
mStatus = NO_INIT;
}
-status_t SurfaceComposerClient::getDisplayInfo(
- DisplayID dpy, DisplayInfo* info)
-{
- if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
- return BAD_VALUE;
-
- volatile surface_flinger_cblk_t const * cblk = get_cblk();
- volatile display_cblk_t const * dcblk = cblk->displays + dpy;
-
- info->w = dcblk->w;
- info->h = dcblk->h;
- info->orientation = dcblk->orientation;
- info->xdpi = dcblk->xdpi;
- info->ydpi = dcblk->ydpi;
- info->fps = dcblk->fps;
- info->density = dcblk->density;
- return getPixelFormatInfo(dcblk->format, &(info->pixelFormatInfo));
-}
-
-ssize_t SurfaceComposerClient::getDisplayWidth(DisplayID dpy)
-{
- if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
- return BAD_VALUE;
- volatile surface_flinger_cblk_t const * cblk = get_cblk();
- volatile display_cblk_t const * dcblk = cblk->displays + dpy;
- return dcblk->w;
-}
-
-ssize_t SurfaceComposerClient::getDisplayHeight(DisplayID dpy)
-{
- if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
- return BAD_VALUE;
- volatile surface_flinger_cblk_t const * cblk = get_cblk();
- volatile display_cblk_t const * dcblk = cblk->displays + dpy;
- return dcblk->h;
-}
-
-ssize_t SurfaceComposerClient::getDisplayOrientation(DisplayID dpy)
-{
- if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
- return BAD_VALUE;
- volatile surface_flinger_cblk_t const * cblk = get_cblk();
- volatile display_cblk_t const * dcblk = cblk->displays + dpy;
- return dcblk->orientation;
-}
-
-ssize_t SurfaceComposerClient::getNumberOfDisplays()
-{
- volatile surface_flinger_cblk_t const * cblk = get_cblk();
- uint32_t connected = cblk->connected;
- int n = 0;
- while (connected) {
- if (connected&1) n++;
- connected >>= 1;
- }
- return n;
-}
-
sp<SurfaceControl> SurfaceComposerClient::createSurface(
DisplayID display,
uint32_t w,
@@ -310,237 +345,167 @@ sp<SurfaceControl> SurfaceComposerClient::createSurface(
return result;
}
-status_t SurfaceComposerClient::destroySurface(SurfaceID sid)
-{
+status_t SurfaceComposerClient::destroySurface(SurfaceID sid) {
if (mStatus != NO_ERROR)
return mStatus;
-
- // it's okay to destroy a surface while a transaction is open,
- // (transactions really are a client-side concept)
- // however, this indicates probably a misuse of the API or a bug
- // in the client code.
- LOGW_IF(mTransactionOpen,
- "Destroying surface while a transaction is open. "
- "Client %p: destroying surface %d, mTransactionOpen=%d",
- this, sid, mTransactionOpen);
-
status_t err = mClient->destroySurface(sid);
return err;
}
-void SurfaceComposerClient::openGlobalTransaction()
-{
- Composer::openGlobalTransaction();
+inline Composer& SurfaceComposerClient::getComposer() {
+ return mComposer;
}
-void SurfaceComposerClient::closeGlobalTransaction()
-{
- Composer::closeGlobalTransaction();
-}
+// ----------------------------------------------------------------------------
-status_t SurfaceComposerClient::freezeDisplay(DisplayID dpy, uint32_t flags)
-{
- sp<ISurfaceComposer> sm(getComposerService());
- return sm->freezeDisplay(dpy, flags);
+void SurfaceComposerClient::openGlobalTransaction() {
+ // Currently a no-op
}
-status_t SurfaceComposerClient::unfreezeDisplay(DisplayID dpy, uint32_t flags)
-{
- sp<ISurfaceComposer> sm(getComposerService());
- return sm->unfreezeDisplay(dpy, flags);
+void SurfaceComposerClient::closeGlobalTransaction() {
+ Composer::closeGlobalTransaction();
}
-int SurfaceComposerClient::setOrientation(DisplayID dpy,
- int orientation, uint32_t flags)
-{
- sp<ISurfaceComposer> sm(getComposerService());
- return sm->setOrientation(dpy, orientation, flags);
-}
+// ----------------------------------------------------------------------------
-status_t SurfaceComposerClient::openTransaction()
-{
- if (mStatus != NO_ERROR)
- return mStatus;
- Mutex::Autolock _l(mLock);
- mTransactionOpen++;
- return NO_ERROR;
+status_t SurfaceComposerClient::setFreezeTint(SurfaceID id, uint32_t tint) {
+ return getComposer().setFreezeTint(this, id, tint);
}
-status_t SurfaceComposerClient::closeTransaction()
-{
- if (mStatus != NO_ERROR)
- return mStatus;
-
- Mutex::Autolock _l(mLock);
- if (mTransactionOpen <= 0) {
- LOGE( "closeTransaction (client %p, mTransactionOpen=%d) "
- "called more times than openTransaction()",
- this, mTransactionOpen);
- return INVALID_OPERATION;
- }
+status_t SurfaceComposerClient::setPosition(SurfaceID id, int32_t x, int32_t y) {
+ return getComposer().setPosition(this, id, x, y);
+}
- if (mTransactionOpen >= 2) {
- mTransactionOpen--;
- return NO_ERROR;
- }
+status_t SurfaceComposerClient::setSize(SurfaceID id, uint32_t w, uint32_t h) {
+ return getComposer().setSize(this, id, w, h);
+}
- mTransactionOpen = 0;
- const ssize_t count = mStates.size();
- if (count) {
- mClient->setState(count, mStates.array());
- mStates.clear();
- }
- return NO_ERROR;
+status_t SurfaceComposerClient::setLayer(SurfaceID id, int32_t z) {
+ return getComposer().setLayer(this, id, z);
}
-layer_state_t* SurfaceComposerClient::get_state_l(SurfaceID index)
-{
- // API usage error, do nothing.
- if (mTransactionOpen<=0) {
- LOGE("Not in transaction (client=%p, SurfaceID=%d, mTransactionOpen=%d",
- this, int(index), mTransactionOpen);
- return 0;
- }
+status_t SurfaceComposerClient::hide(SurfaceID id) {
+ return getComposer().setFlags(this, id,
+ ISurfaceComposer::eLayerHidden,
+ ISurfaceComposer::eLayerHidden);
+}
- // use mPrebuiltLayerState just to find out if we already have it
- layer_state_t& dummy(*mPrebuiltLayerState);
- dummy.surface = index;
- ssize_t i = mStates.indexOf(dummy);
- if (i < 0) {
- // we don't have it, add an initialized layer_state to our list
- i = mStates.add(dummy);
- }
- return mStates.editArray() + i;
+status_t SurfaceComposerClient::show(SurfaceID id, int32_t) {
+ return getComposer().setFlags(this, id,
+ 0,
+ ISurfaceComposer::eLayerHidden);
}
-layer_state_t* SurfaceComposerClient::lockLayerState(SurfaceID id)
-{
- layer_state_t* s;
- mLock.lock();
- s = get_state_l(id);
- if (!s) mLock.unlock();
- return s;
+status_t SurfaceComposerClient::freeze(SurfaceID id) {
+ return getComposer().setFlags(this, id,
+ ISurfaceComposer::eLayerFrozen,
+ ISurfaceComposer::eLayerFrozen);
}
-void SurfaceComposerClient::unlockLayerState()
-{
- mLock.unlock();
+status_t SurfaceComposerClient::unfreeze(SurfaceID id) {
+ return getComposer().setFlags(this, id,
+ 0,
+ ISurfaceComposer::eLayerFrozen);
}
-status_t SurfaceComposerClient::setPosition(SurfaceID id, int32_t x, int32_t y)
-{
- layer_state_t* s = lockLayerState(id);
- if (!s) return BAD_INDEX;
- s->what |= ISurfaceComposer::ePositionChanged;
- s->x = x;
- s->y = y;
- unlockLayerState();
- return NO_ERROR;
+status_t SurfaceComposerClient::setFlags(SurfaceID id, uint32_t flags,
+ uint32_t mask) {
+ return getComposer().setFlags(this, id, flags, mask);
}
-status_t SurfaceComposerClient::setSize(SurfaceID id, uint32_t w, uint32_t h)
-{
- layer_state_t* s = lockLayerState(id);
- if (!s) return BAD_INDEX;
- s->what |= ISurfaceComposer::eSizeChanged;
- s->w = w;
- s->h = h;
- unlockLayerState();
- return NO_ERROR;
+status_t SurfaceComposerClient::setTransparentRegionHint(SurfaceID id,
+ const Region& transparentRegion) {
+ return getComposer().setTransparentRegionHint(this, id, transparentRegion);
}
-status_t SurfaceComposerClient::setLayer(SurfaceID id, int32_t z)
-{
- layer_state_t* s = lockLayerState(id);
- if (!s) return BAD_INDEX;
- s->what |= ISurfaceComposer::eLayerChanged;
- s->z = z;
- unlockLayerState();
- return NO_ERROR;
+status_t SurfaceComposerClient::setAlpha(SurfaceID id, float alpha) {
+ return getComposer().setAlpha(this, id, alpha);
}
-status_t SurfaceComposerClient::hide(SurfaceID id)
-{
- return setFlags(id, ISurfaceComposer::eLayerHidden,
- ISurfaceComposer::eLayerHidden);
+status_t SurfaceComposerClient::setMatrix(SurfaceID id, float dsdx, float dtdx,
+ float dsdy, float dtdy) {
+ return getComposer().setMatrix(this, id, dsdx, dtdx, dsdy, dtdy);
}
-status_t SurfaceComposerClient::show(SurfaceID id, int32_t)
+// ----------------------------------------------------------------------------
+
+status_t SurfaceComposerClient::getDisplayInfo(
+ DisplayID dpy, DisplayInfo* info)
{
- return setFlags(id, 0, ISurfaceComposer::eLayerHidden);
+ if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
+ return BAD_VALUE;
+
+ volatile surface_flinger_cblk_t const * cblk = get_cblk();
+ volatile display_cblk_t const * dcblk = cblk->displays + dpy;
+
+ info->w = dcblk->w;
+ info->h = dcblk->h;
+ info->orientation = dcblk->orientation;
+ info->xdpi = dcblk->xdpi;
+ info->ydpi = dcblk->ydpi;
+ info->fps = dcblk->fps;
+ info->density = dcblk->density;
+ return getPixelFormatInfo(dcblk->format, &(info->pixelFormatInfo));
}
-status_t SurfaceComposerClient::freeze(SurfaceID id)
+ssize_t SurfaceComposerClient::getDisplayWidth(DisplayID dpy)
{
- return setFlags(id, ISurfaceComposer::eLayerFrozen,
- ISurfaceComposer::eLayerFrozen);
+ if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
+ return BAD_VALUE;
+ volatile surface_flinger_cblk_t const * cblk = get_cblk();
+ volatile display_cblk_t const * dcblk = cblk->displays + dpy;
+ return dcblk->w;
}
-status_t SurfaceComposerClient::unfreeze(SurfaceID id)
+ssize_t SurfaceComposerClient::getDisplayHeight(DisplayID dpy)
{
- return setFlags(id, 0, ISurfaceComposer::eLayerFrozen);
+ if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
+ return BAD_VALUE;
+ volatile surface_flinger_cblk_t const * cblk = get_cblk();
+ volatile display_cblk_t const * dcblk = cblk->displays + dpy;
+ return dcblk->h;
}
-status_t SurfaceComposerClient::setFlags(SurfaceID id,
- uint32_t flags, uint32_t mask)
+ssize_t SurfaceComposerClient::getDisplayOrientation(DisplayID dpy)
{
- layer_state_t* s = lockLayerState(id);
- if (!s) return BAD_INDEX;
- s->what |= ISurfaceComposer::eVisibilityChanged;
- s->flags &= ~mask;
- s->flags |= (flags & mask);
- s->mask |= mask;
- unlockLayerState();
- return NO_ERROR;
+ if (uint32_t(dpy)>=NUM_DISPLAY_MAX)
+ return BAD_VALUE;
+ volatile surface_flinger_cblk_t const * cblk = get_cblk();
+ volatile display_cblk_t const * dcblk = cblk->displays + dpy;
+ return dcblk->orientation;
}
-status_t SurfaceComposerClient::setTransparentRegionHint(
- SurfaceID id, const Region& transparentRegion)
+ssize_t SurfaceComposerClient::getNumberOfDisplays()
{
- layer_state_t* s = lockLayerState(id);
- if (!s) return BAD_INDEX;
- s->what |= ISurfaceComposer::eTransparentRegionChanged;
- s->transparentRegion = transparentRegion;
- unlockLayerState();
- return NO_ERROR;
+ volatile surface_flinger_cblk_t const * cblk = get_cblk();
+ uint32_t connected = cblk->connected;
+ int n = 0;
+ while (connected) {
+ if (connected&1) n++;
+ connected >>= 1;
+ }
+ return n;
}
-status_t SurfaceComposerClient::setAlpha(SurfaceID id, float alpha)
+// ----------------------------------------------------------------------------
+
+status_t SurfaceComposerClient::freezeDisplay(DisplayID dpy, uint32_t flags)
{
- layer_state_t* s = lockLayerState(id);
- if (!s) return BAD_INDEX;
- s->what |= ISurfaceComposer::eAlphaChanged;
- s->alpha = alpha;
- unlockLayerState();
- return NO_ERROR;
+ sp<ISurfaceComposer> sm(getComposerService());
+ return sm->freezeDisplay(dpy, flags);
}
-status_t SurfaceComposerClient::setMatrix(
- SurfaceID id,
- float dsdx, float dtdx,
- float dsdy, float dtdy )
+status_t SurfaceComposerClient::unfreezeDisplay(DisplayID dpy, uint32_t flags)
{
- layer_state_t* s = lockLayerState(id);
- if (!s) return BAD_INDEX;
- s->what |= ISurfaceComposer::eMatrixChanged;
- layer_state_t::matrix22_t matrix;
- matrix.dsdx = dsdx;
- matrix.dtdx = dtdx;
- matrix.dsdy = dsdy;
- matrix.dtdy = dtdy;
- s->matrix = matrix;
- unlockLayerState();
- return NO_ERROR;
+ sp<ISurfaceComposer> sm(getComposerService());
+ return sm->unfreezeDisplay(dpy, flags);
}
-status_t SurfaceComposerClient::setFreezeTint(SurfaceID id, uint32_t tint)
+int SurfaceComposerClient::setOrientation(DisplayID dpy,
+ int orientation, uint32_t flags)
{
- layer_state_t* s = lockLayerState(id);
- if (!s) return BAD_INDEX;
- s->what |= ISurfaceComposer::eFreezeTintChanged;
- s->tint = tint;
- unlockLayerState();
- return NO_ERROR;
+ sp<ISurfaceComposer> sm(getComposerService());
+ return sm->setOrientation(dpy, orientation, flags);
}
// ----------------------------------------------------------------------------
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 0925001965dd..3bf6477cf208 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -148,6 +148,11 @@ status_t SurfaceTexture::setBufferCount(int bufferCount) {
LOGV("SurfaceTexture::setBufferCount");
Mutex::Autolock lock(mMutex);
+ if (bufferCount > NUM_BUFFER_SLOTS) {
+ LOGE("setBufferCount: bufferCount larger than slots available");
+ return BAD_VALUE;
+ }
+
// Error out if the user has dequeued buffers
for (int i=0 ; i<mBufferCount ; i++) {
if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) {
@@ -208,7 +213,7 @@ status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
uint32_t format, uint32_t usage) {
LOGV("SurfaceTexture::dequeueBuffer");
- if ((w && !h) || (!w & h)) {
+ if ((w && !h) || (!w && h)) {
LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h);
return BAD_VALUE;
}
@@ -699,10 +704,10 @@ nsecs_t SurfaceTexture::getTimestamp() {
}
void SurfaceTexture::setFrameAvailableListener(
- const sp<FrameAvailableListener>& l) {
+ const sp<FrameAvailableListener>& listener) {
LOGV("SurfaceTexture::setFrameAvailableListener");
Mutex::Autolock lock(mMutex);
- mFrameAvailableListener = l;
+ mFrameAvailableListener = listener;
}
sp<IBinder> SurfaceTexture::getAllocator() {
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index dfa9211afac5..c06400e5219a 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -84,10 +84,10 @@ protected:
ASSERT_TRUE(mSurfaceControl != NULL);
ASSERT_TRUE(mSurfaceControl->isValid());
- ASSERT_EQ(NO_ERROR, mComposerClient->openTransaction());
+ SurfaceComposerClient::openGlobalTransaction();
ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(0x7FFFFFFF));
ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
- ASSERT_EQ(NO_ERROR, mComposerClient->closeTransaction());
+ SurfaceComposerClient::closeGlobalTransaction();
sp<ANativeWindow> window = mSurfaceControl->getSurface();
mEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 35c86405584b..450cdf1f8f47 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -36,10 +36,10 @@ protected:
ASSERT_TRUE(mSurfaceControl != NULL);
ASSERT_TRUE(mSurfaceControl->isValid());
- ASSERT_EQ(NO_ERROR, mComposerClient->openTransaction());
+ SurfaceComposerClient::openGlobalTransaction();
ASSERT_EQ(NO_ERROR, mSurfaceControl->setLayer(30000));
ASSERT_EQ(NO_ERROR, mSurfaceControl->show());
- ASSERT_EQ(NO_ERROR, mComposerClient->closeTransaction());
+ SurfaceComposerClient::closeGlobalTransaction();
mSurface = mSurfaceControl->getSurface();
ASSERT_TRUE(mSurface != NULL);
diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp
index ffdfe663afe9..c46d6f4724a2 100644
--- a/libs/ui/InputTransport.cpp
+++ b/libs/ui/InputTransport.cpp
@@ -443,7 +443,8 @@ status_t InputPublisher::appendMotionSample(
if (! mPinned || ! mMotionEventSampleDataTail) {
LOGE("channel '%s' publisher ~ Cannot append motion sample because there is no current "
- "AMOTION_EVENT_ACTION_MOVE event.", mChannel->getName().string());
+ "AMOTION_EVENT_ACTION_MOVE or AMOTION_EVENT_ACTION_HOVER_MOVE event.",
+ mChannel->getName().string());
return INVALID_OPERATION;
}
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index 093189c5c05a..774e8c974558 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -27,6 +27,7 @@ commonSources:= \
Debug.cpp \
FileMap.cpp \
Flattenable.cpp \
+ LinearTransform.cpp \
ObbFile.cpp \
Pool.cpp \
PropertyMap.cpp \
diff --git a/libs/utils/LinearTransform.cpp b/libs/utils/LinearTransform.cpp
new file mode 100644
index 000000000000..d752415cf5f0
--- /dev/null
+++ b/libs/utils/LinearTransform.cpp
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 __STDC_LIMIT_MACROS
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <utils/LinearTransform.h>
+
+namespace android {
+
+template<class T> static inline T ABS(T x) { return (x < 0) ? -x : x; }
+
+// Static math methods involving linear transformations
+static bool scale_u64_to_u64(
+ uint64_t val,
+ uint32_t N,
+ uint32_t D,
+ uint64_t* res,
+ bool round_up_not_down) {
+ uint64_t tmp1, tmp2;
+ uint32_t r;
+
+ assert(res);
+ assert(D);
+
+ // Let U32(X) denote a uint32_t containing the upper 32 bits of a 64 bit
+ // integer X.
+ // Let L32(X) denote a uint32_t containing the lower 32 bits of a 64 bit
+ // integer X.
+ // Let X[A, B] with A <= B denote bits A through B of the integer X.
+ // Let (A | B) denote the concatination of two 32 bit ints, A and B.
+ // IOW X = (A | B) => U32(X) == A && L32(X) == B
+ //
+ // compute M = val * N (a 96 bit int)
+ // ---------------------------------
+ // tmp2 = U32(val) * N (a 64 bit int)
+ // tmp1 = L32(val) * N (a 64 bit int)
+ // which means
+ // M = val * N = (tmp2 << 32) + tmp1
+ tmp2 = (val >> 32) * N;
+ tmp1 = (val & UINT32_MAX) * N;
+
+ // compute M[32, 95]
+ // tmp2 = tmp2 + U32(tmp1)
+ // = (U32(val) * N) + U32(L32(val) * N)
+ // = M[32, 95]
+ tmp2 += tmp1 >> 32;
+
+ // if M[64, 95] >= D, then M/D has bits > 63 set and we have
+ // an overflow.
+ if ((tmp2 >> 32) >= D) {
+ *res = UINT64_MAX;
+ return false;
+ }
+
+ // Divide. Going in we know
+ // tmp2 = M[32, 95]
+ // U32(tmp2) < D
+ r = tmp2 % D;
+ tmp2 /= D;
+
+ // At this point
+ // tmp1 = L32(val) * N
+ // tmp2 = M[32, 95] / D
+ // = (M / D)[32, 95]
+ // r = M[32, 95] % D
+ // U32(tmp2) = 0
+ //
+ // compute tmp1 = (r | M[0, 31])
+ tmp1 = (tmp1 & UINT32_MAX) | ((uint64_t)r << 32);
+
+ // Divide again. Keep the remainder around in order to round properly.
+ r = tmp1 % D;
+ tmp1 /= D;
+
+ // At this point
+ // tmp2 = (M / D)[32, 95]
+ // tmp1 = (M / D)[ 0, 31]
+ // r = M % D
+ // U32(tmp1) = 0
+ // U32(tmp2) = 0
+
+ // Pack the result and deal with the round-up case (As well as the
+ // remote possiblility over overflow in such a case).
+ *res = (tmp2 << 32) | tmp1;
+ if (r && round_up_not_down) {
+ ++(*res);
+ if (!(*res)) {
+ *res = UINT64_MAX;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool linear_transform_s64_to_s64(
+ int64_t val,
+ int64_t basis1,
+ int32_t N,
+ uint32_t D,
+ int64_t basis2,
+ int64_t* out) {
+ uint64_t scaled, res;
+ uint64_t abs_val;
+ bool is_neg;
+
+ if (!out)
+ return false;
+
+ // Compute abs(val - basis_64). Keep track of whether or not this delta
+ // will be negative after the scale opertaion.
+ if (val < basis1) {
+ is_neg = true;
+ abs_val = basis1 - val;
+ } else {
+ is_neg = false;
+ abs_val = val - basis1;
+ }
+
+ if (N < 0)
+ is_neg = !is_neg;
+
+ if (!scale_u64_to_u64(abs_val,
+ ABS(N),
+ D,
+ &scaled,
+ is_neg))
+ return false; // overflow/undeflow
+
+ // if scaled is >= 0x8000<etc>, then we are going to overflow or
+ // underflow unless ABS(basis2) is large enough to pull us back into the
+ // non-overflow/underflow region.
+ if (scaled & INT64_MIN) {
+ if (is_neg && (basis2 < 0))
+ return false; // certain underflow
+
+ if (!is_neg && (basis2 >= 0))
+ return false; // certain overflow
+
+ if (ABS(basis2) <= static_cast<int64_t>(scaled & INT64_MAX))
+ return false; // not enough
+
+ // Looks like we are OK
+ *out = (is_neg ? (-scaled) : scaled) + basis2;
+ } else {
+ // Scaled fits within signed bounds, so we just need to check for
+ // over/underflow for two signed integers. Basically, if both scaled
+ // and basis2 have the same sign bit, and the result has a different
+ // sign bit, then we have under/overflow. An easy way to compute this
+ // is
+ // (scaled_signbit XNOR basis_signbit) &&
+ // (scaled_signbit XOR res_signbit)
+ // ==
+ // (scaled_signbit XOR basis_signbit XOR 1) &&
+ // (scaled_signbit XOR res_signbit)
+
+ if (is_neg)
+ scaled = -scaled;
+ res = scaled + basis2;
+
+ if ((scaled ^ basis2 ^ INT64_MIN) & (scaled ^ res) & INT64_MIN)
+ return false;
+
+ *out = res;
+ }
+
+ return true;
+}
+
+bool LinearTransform::doForwardTransform(int64_t a_in, int64_t* b_out) const {
+ if (0 == a_to_b_denom)
+ return false;
+
+ return linear_transform_s64_to_s64(a_in,
+ a_zero,
+ a_to_b_numer,
+ a_to_b_denom,
+ b_zero,
+ b_out);
+}
+
+bool LinearTransform::doReverseTransform(int64_t b_in, int64_t* a_out) const {
+ if (0 == a_to_b_numer)
+ return false;
+
+ return linear_transform_s64_to_s64(b_in,
+ b_zero,
+ a_to_b_denom,
+ a_to_b_numer,
+ a_zero,
+ a_out);
+}
+
+template <class T> void LinearTransform::reduce(T* N, T* D) {
+ T a, b;
+ if (!N || !D || !(*D)) {
+ assert(false);
+ return;
+ }
+
+ a = *N;
+ b = *D;
+
+ if (a == 0) {
+ *D = 1;
+ return;
+ }
+
+ // This implements Euclid's method to find GCD.
+ if (a < b) {
+ T tmp = a;
+ a = b;
+ b = tmp;
+ }
+
+ while (1) {
+ // a is now the greater of the two.
+ const T remainder = a % b;
+ if (remainder == 0) {
+ *N /= b;
+ *D /= b;
+ return;
+ }
+ // by swapping remainder and b, we are guaranteeing that a is
+ // still the greater of the two upon entrance to the loop.
+ a = b;
+ b = remainder;
+ }
+};
+
+template void LinearTransform::reduce<uint64_t>(uint64_t* N, uint64_t* D);
+template void LinearTransform::reduce<uint32_t>(uint32_t* N, uint32_t* D);
+
+void LinearTransform::reduce(int32_t* N, uint32_t* D) {
+ if (N && D && *D) {
+ if (*N < 0) {
+ *N = -(*N);
+ reduce(reinterpret_cast<uint32_t*>(N), D);
+ *N = -(*N);
+ } else {
+ reduce(reinterpret_cast<uint32_t*>(N), D);
+ }
+ }
+}
+
+} // namespace android
diff --git a/location/java/android/location/Country.java b/location/java/android/location/Country.java
index 3c05403a6bc2..939bd4af109c 100755
--- a/location/java/android/location/Country.java
+++ b/location/java/android/location/Country.java
@@ -19,6 +19,8 @@ package android.location;
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Locale;
+
/**
* This class wraps the country information.
*
@@ -74,7 +76,7 @@ public class Country implements Parcelable {
|| source > COUNTRY_SOURCE_LOCALE) {
throw new IllegalArgumentException();
}
- mCountryIso = countryIso.toLowerCase();
+ mCountryIso = countryIso.toUpperCase(Locale.US);
mSource = source;
}
diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
index ffc3346da993..29dec6373b19 100755
--- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
+++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java
@@ -205,7 +205,7 @@ public class GpsNetInitiatedHandler {
mNiNotification.defaults &= ~Notification.DEFAULT_SOUND;
}
- mNiNotification.flags = Notification.FLAG_ONGOING_EVENT;
+ mNiNotification.flags = Notification.FLAG_ONGOING_EVENT | Notification.FLAG_AUTO_CANCEL;
mNiNotification.tickerText = getNotifTicker(notif, mContext);
// if not to popup dialog immediately, pending intent will open the dialog
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 33312d195656..482b437dd3dc 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -611,15 +611,11 @@ public class MediaPlayer
* needed. Not calling this method when playing back a video will
* result in only the audio track being played.
*
- * @param sh the SurfaceHolder to use for video display
- */
- /*
- * This portion of comment has a non-Javadoc prefix so as not to refer to a
- * hidden method. When unhidden, merge it with the previous javadoc comment.
- *
* Either a surface or surface texture must be set if a display or video sink
* is needed. Not calling this method or {@link #setTexture(SurfaceTexture)}
* when playing back a video will result in only the audio track being played.
+ *
+ * @param sh the SurfaceHolder to use for video display
*/
public void setDisplay(SurfaceHolder sh) {
mSurfaceHolder = sh;
@@ -648,7 +644,8 @@ public class MediaPlayer
* SurfaceTexture set as the video sink have an unspecified zero point,
* and cannot be directly compared between different media sources or different
* instances of the same media source, or across multiple runs of the same
- * program.
+ * program. The timestamp is normally monotonically increasing and unaffected
+ * by time-of-day adjustments, but is reset when the position is set.
*/
public void setTexture(SurfaceTexture st) {
ParcelSurfaceTexture pst = null;
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 6f425966d592..e3cbd5783c8f 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -720,8 +720,9 @@ public class MediaRecorder
*
* <p>Since API level 13, if applications set a camera via
* {@link #setCamera(Camera)}, the apps can use the camera after this method
- * call. The apps do not need to lock the camera again. The apps should not
- * start another recording session during recording.
+ * call. The apps do not need to lock the camera again. However, if this
+ * method fails, the apps should still lock the camera back. The apps should
+ * not start another recording session during recording.
*
* @throws IllegalStateException if it is called before
* prepare().
diff --git a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
index 29c4b89e8517..0d2bcd5376e5 100644
--- a/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
+++ b/media/java/android/media/videoeditor/MediaArtistNativeHelper.java
@@ -957,12 +957,8 @@ class MediaArtistNativeHelper {
public static final int FADE_FROM_BLACK = 8;
- public static final int CURTAIN_OPENING = 9;
-
public static final int FADE_TO_BLACK = 16;
- public static final int CURTAIN_CLOSING = 17;
-
public static final int EXTERNAL = 256;
public static final int BLACK_AND_WHITE = 257;
diff --git a/media/jni/mediaeditor/VideoEditorClasses.cpp b/media/jni/mediaeditor/VideoEditorClasses.cpp
index d43a5622a769..277e16c4dc3b 100755
--- a/media/jni/mediaeditor/VideoEditorClasses.cpp
+++ b/media/jni/mediaeditor/VideoEditorClasses.cpp
@@ -378,9 +378,7 @@ VIDEOEDIT_JAVA_DEFINE_CONSTANTS(VideoEffect)
{
VIDEOEDIT_JAVA_CONSTANT_INIT("NONE", M4VSS3GPP_kVideoEffectType_None),
VIDEOEDIT_JAVA_CONSTANT_INIT("FADE_FROM_BLACK", M4VSS3GPP_kVideoEffectType_FadeFromBlack),
- VIDEOEDIT_JAVA_CONSTANT_INIT("CURTAIN_OPENING", M4VSS3GPP_kVideoEffectType_CurtainOpening),
VIDEOEDIT_JAVA_CONSTANT_INIT("FADE_TO_BLACK", M4VSS3GPP_kVideoEffectType_FadeToBlack),
- VIDEOEDIT_JAVA_CONSTANT_INIT("CURTAIN_CLOSING", M4VSS3GPP_kVideoEffectType_CurtainClosing),
VIDEOEDIT_JAVA_CONSTANT_INIT("EXTERNAL", M4VSS3GPP_kVideoEffectType_External),
VIDEOEDIT_JAVA_CONSTANT_INIT("BLACK_AND_WHITE", M4xVSS_kVideoEffectType_BlackAndWhite),
VIDEOEDIT_JAVA_CONSTANT_INIT("PINK", M4xVSS_kVideoEffectType_Pink),
diff --git a/media/jni/mediaeditor/VideoEditorOsal.cpp b/media/jni/mediaeditor/VideoEditorOsal.cpp
index 53e7de176ae4..a8c08ac936bd 100755
--- a/media/jni/mediaeditor/VideoEditorOsal.cpp
+++ b/media/jni/mediaeditor/VideoEditorOsal.cpp
@@ -166,7 +166,6 @@ static const VideoEdit_Osal_Result gkRESULTS[] =
VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_NO_SUPPORTED_VIDEO_STREAM_IN_FILE ),
VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_INTERNAL_STATE ),
VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_LUMA_FILTER_ERROR ),
- VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_CURTAIN_FILTER_ERROR ),
VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_TRANSITION_FILTER_ERROR ),
VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_AUDIO_DECODER_INIT_FAILED ),
VIDEOEDIT_OSAL_RESULT_INIT(M4VSS3GPP_ERR_AUDIO_DECODED_PCM_SIZE_ISSUE ),
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index a77dff1615d4..1e7c9693bc1a 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -250,7 +250,11 @@ sp<IMediaPlayer> MediaPlayerService::create(
const KeyedVector<String8, String8> *headers, int audioSessionId)
{
int32_t connId = android_atomic_inc(&mNextConnId);
- sp<Client> c = new Client(this, pid, connId, client, audioSessionId);
+
+ sp<Client> c = new Client(
+ this, pid, connId, client, audioSessionId,
+ IPCThreadState::self()->getCallingUid());
+
LOGV("Create new client(%d) from pid %d, url=%s, connId=%d, audioSessionId=%d",
connId, pid, url, connId, audioSessionId);
if (NO_ERROR != c->setDataSource(url, headers))
@@ -268,7 +272,11 @@ sp<IMediaPlayer> MediaPlayerService::create(pid_t pid, const sp<IMediaPlayerClie
int fd, int64_t offset, int64_t length, int audioSessionId)
{
int32_t connId = android_atomic_inc(&mNextConnId);
- sp<Client> c = new Client(this, pid, connId, client, audioSessionId);
+
+ sp<Client> c = new Client(
+ this, pid, connId, client, audioSessionId,
+ IPCThreadState::self()->getCallingUid());
+
LOGV("Create new client(%d) from pid %d, fd=%d, offset=%lld, length=%lld, audioSessionId=%d",
connId, pid, fd, offset, length, audioSessionId);
if (NO_ERROR != c->setDataSource(fd, offset, length)) {
@@ -286,7 +294,10 @@ sp<IMediaPlayer> MediaPlayerService::create(
pid_t pid, const sp<IMediaPlayerClient> &client,
const sp<IStreamSource> &source, int audioSessionId) {
int32_t connId = android_atomic_inc(&mNextConnId);
- sp<Client> c = new Client(this, pid, connId, client, audioSessionId);
+
+ sp<Client> c = new Client(
+ this, pid, connId, client, audioSessionId,
+ IPCThreadState::self()->getCallingUid());
LOGV("Create new client(%d) from pid %d, audioSessionId=%d",
connId, pid, audioSessionId);
@@ -496,8 +507,10 @@ void MediaPlayerService::removeClient(wp<Client> client)
mClients.remove(client);
}
-MediaPlayerService::Client::Client(const sp<MediaPlayerService>& service, pid_t pid,
- int32_t connId, const sp<IMediaPlayerClient>& client, int audioSessionId)
+MediaPlayerService::Client::Client(
+ const sp<MediaPlayerService>& service, pid_t pid,
+ int32_t connId, const sp<IMediaPlayerClient>& client,
+ int audioSessionId, uid_t uid)
{
LOGV("Client(%d) constructor", connId);
mPid = pid;
@@ -507,6 +520,7 @@ MediaPlayerService::Client::Client(const sp<MediaPlayerService>& service, pid_t
mLoop = false;
mStatus = NO_INIT;
mAudioSessionId = audioSessionId;
+ mUID = uid;
#if CALLBACK_ANTAGONIZER
LOGD("create Antagonizer");
@@ -671,6 +685,9 @@ sp<MediaPlayerBase> MediaPlayerService::Client::createPlayer(player_type playerT
if (p == NULL) {
p = android::createPlayer(playerType, this, notify);
}
+
+ p->setUID(mUID);
+
return p;
}
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 8bab471fac6b..e32b92a659ca 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -306,7 +306,8 @@ private:
pid_t pid,
int32_t connId,
const sp<IMediaPlayerClient>& client,
- int audioSessionId);
+ int audioSessionId,
+ uid_t uid);
Client();
virtual ~Client();
@@ -336,6 +337,7 @@ private:
bool mLoop;
int32_t mConnId;
int mAudioSessionId;
+ uid_t mUID;
// Metadata filters.
media::Metadata::Filter mMetadataAllow; // protected by mLock
diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp
index 870e290ee09e..40e055cc5aca 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.cpp
+++ b/media/libmediaplayerservice/StagefrightPlayer.cpp
@@ -47,6 +47,12 @@ status_t StagefrightPlayer::initCheck() {
return OK;
}
+status_t StagefrightPlayer::setUID(uid_t uid) {
+ mPlayer->setUID(uid);
+
+ return OK;
+}
+
status_t StagefrightPlayer::setDataSource(
const char *url, const KeyedVector<String8, String8> *headers) {
return mPlayer->setDataSource(url, headers);
diff --git a/media/libmediaplayerservice/StagefrightPlayer.h b/media/libmediaplayerservice/StagefrightPlayer.h
index 85a546dc89e8..cbc6d4996da1 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.h
+++ b/media/libmediaplayerservice/StagefrightPlayer.h
@@ -31,6 +31,8 @@ public:
virtual status_t initCheck();
+ virtual status_t setUID(uid_t uid);
+
virtual status_t setDataSource(
const char *url, const KeyedVector<String8, String8> *headers);
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index b3b3af5b39a9..5a5330d69feb 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -35,8 +35,11 @@ namespace android {
NuPlayer::HTTPLiveSource::HTTPLiveSource(
const char *url,
- const KeyedVector<String8, String8> *headers)
+ const KeyedVector<String8, String8> *headers,
+ bool uidValid, uid_t uid)
: mURL(url),
+ mUIDValid(uidValid),
+ mUID(uid),
mFlags(0),
mEOS(false),
mOffset(0) {
@@ -65,7 +68,8 @@ void NuPlayer::HTTPLiveSource::start() {
mLiveLooper->start();
mLiveSession = new LiveSession(
- (mFlags & kFlagIncognito) ? LiveSession::kFlagIncognito : 0);
+ (mFlags & kFlagIncognito) ? LiveSession::kFlagIncognito : 0,
+ mUIDValid, mUID);
mLiveLooper->registerHandler(mLiveSession);
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
index 7a337e9aa025..36c67c501b38 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
@@ -29,7 +29,9 @@ struct LiveSession;
struct NuPlayer::HTTPLiveSource : public NuPlayer::Source {
HTTPLiveSource(
const char *url,
- const KeyedVector<String8, String8> *headers);
+ const KeyedVector<String8, String8> *headers,
+ bool uidValid = false,
+ uid_t uid = 0);
virtual void start();
@@ -54,6 +56,8 @@ private:
AString mURL;
KeyedVector<String8, String8> mExtraHeaders;
+ bool mUIDValid;
+ uid_t mUID;
uint32_t mFlags;
bool mEOS;
off64_t mOffset;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index effa7038fe6d..b06f20d55c80 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -44,7 +44,8 @@ namespace android {
////////////////////////////////////////////////////////////////////////////////
NuPlayer::NuPlayer()
- : mAudioEOS(false),
+ : mUIDValid(false),
+ mAudioEOS(false),
mVideoEOS(false),
mScanSourcesPending(false),
mScanSourcesGeneration(0),
@@ -57,6 +58,11 @@ NuPlayer::NuPlayer()
NuPlayer::~NuPlayer() {
}
+void NuPlayer::setUID(uid_t uid) {
+ mUIDValid = true;
+ mUID = uid;
+}
+
void NuPlayer::setDriver(const wp<NuPlayerDriver> &driver) {
mDriver = driver;
}
@@ -72,7 +78,7 @@ void NuPlayer::setDataSource(
const char *url, const KeyedVector<String8, String8> *headers) {
sp<AMessage> msg = new AMessage(kWhatSetDataSource, id());
- msg->setObject("source", new HTTPLiveSource(url, headers));
+ msg->setObject("source", new HTTPLiveSource(url, headers, mUIDValid, mUID));
msg->post();
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index fb5b001fb798..cf9185b814d9 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -33,6 +33,8 @@ struct NuPlayerDriver;
struct NuPlayer : public AHandler {
NuPlayer();
+ void setUID(uid_t uid);
+
void setDriver(const wp<NuPlayerDriver> &driver);
void setDataSource(const sp<IStreamSource> &source);
@@ -84,6 +86,8 @@ private:
};
wp<NuPlayerDriver> mDriver;
+ bool mUIDValid;
+ uid_t mUID;
sp<Source> mSource;
sp<NativeWindowWrapper> mNativeWindow;
sp<MediaPlayerBase::AudioSink> mAudioSink;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index e1213f41c345..7cd8b6cc7f55 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -55,6 +55,12 @@ status_t NuPlayerDriver::initCheck() {
return OK;
}
+status_t NuPlayerDriver::setUID(uid_t uid) {
+ mPlayer->setUID(uid);
+
+ return OK;
+}
+
status_t NuPlayerDriver::setDataSource(
const char *url, const KeyedVector<String8, String8> *headers) {
CHECK_EQ((int)mState, (int)UNINITIALIZED);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index 145fd80b2dda..1bb7ca23f850 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -28,6 +28,8 @@ struct NuPlayerDriver : public MediaPlayerInterface {
virtual status_t initCheck();
+ virtual status_t setUID(uid_t uid);
+
virtual status_t setDataSource(
const char *url, const KeyedVector<String8, String8> *headers);
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 513eda82f868..d4d07b2815d9 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1190,6 +1190,17 @@ bool ACodec::BaseState::onOMXMessage(const sp<AMessage> &msg) {
CHECK(msg->findInt32("data1", &data1));
CHECK(msg->findInt32("data2", &data2));
+ if (event == OMX_EventCmdComplete
+ && data1 == OMX_CommandFlush
+ && data2 == (int32_t)OMX_ALL) {
+ // Use of this notification is not consistent across
+ // implementations. We'll drop this notification and rely
+ // on flush-complete notifications on the individual port
+ // indices instead.
+
+ return true;
+ }
+
return onOMXEvent(
static_cast<OMX_EVENTTYPE>(event),
static_cast<OMX_U32>(data1),
@@ -2119,6 +2130,7 @@ bool ACodec::ExecutingToIdleState::onOMXEvent(
return BaseState::onOMXEvent(event, data1, data2);
}
}
+
void ACodec::ExecutingToIdleState::changeStateIfWeOwnAllBuffers() {
if (mCodec->allYourBuffersAreBelongToUs()) {
CHECK_EQ(mCodec->mOMX->sendCommand(
@@ -2282,6 +2294,11 @@ bool ACodec::FlushingState::onOMXEvent(
if (data2 == kPortIndexInput || data2 == kPortIndexOutput) {
CHECK(!mFlushComplete[data2]);
mFlushComplete[data2] = true;
+
+ if (mFlushComplete[kPortIndexInput]
+ && mFlushComplete[kPortIndexOutput]) {
+ changeStateIfWeOwnAllBuffers();
+ }
} else {
CHECK_EQ(data2, OMX_ALL);
CHECK(mFlushComplete[kPortIndexInput]);
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index aa7edccb2ffb..77c25d19591b 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -128,6 +128,9 @@ struct AwesomeNativeWindowRenderer : public AwesomeRenderer {
}
virtual void render(MediaBuffer *buffer) {
+ int64_t timeUs;
+ CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
+ native_window_set_buffers_timestamp(mNativeWindow.get(), timeUs * 1000);
status_t err = mNativeWindow->queueBuffer(
mNativeWindow.get(), buffer->graphicBuffer().get());
if (err != 0) {
@@ -180,6 +183,7 @@ void addBatteryData(uint32_t params) {
////////////////////////////////////////////////////////////////////////////////
AwesomePlayer::AwesomePlayer()
: mQueueStarted(false),
+ mUIDValid(false),
mTimeSource(NULL),
mVideoRendererIsPreview(false),
mAudioPlayer(NULL),
@@ -243,6 +247,13 @@ void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) {
mListener = listener;
}
+void AwesomePlayer::setUID(uid_t uid) {
+ LOGI("AwesomePlayer running on behalf of uid %d", uid);
+
+ mUID = uid;
+ mUIDValid = true;
+}
+
status_t AwesomePlayer::setDataSource(
const char *uri, const KeyedVector<String8, String8> *headers) {
Mutex::Autolock autoLock(mLock);
@@ -1928,6 +1939,10 @@ status_t AwesomePlayer::finishSetDataSource_l() {
? HTTPBase::kFlagIncognito
: 0);
+ if (mUIDValid) {
+ mConnectingDataSource->setUID(mUID);
+ }
+
mLock.unlock();
status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
mLock.lock();
@@ -2009,6 +2024,10 @@ status_t AwesomePlayer::finishSetDataSource_l() {
mRTSPController = new ARTSPController(mLooper);
mConnectingRTSPController = mRTSPController;
+ if (mUIDValid) {
+ mConnectingRTSPController->setUID(mUID);
+ }
+
mLock.unlock();
status_t err = mRTSPController->connect(mUri.string());
mLock.lock();
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index bdffce9c10fe..ed8149abbbd3 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -158,9 +158,12 @@ CameraSource::CameraSource(
mVideoSize.width = -1;
mVideoSize.height = -1;
+ int64_t token = IPCThreadState::self()->clearCallingIdentity();
mInitCheck = init(camera, proxy, cameraId,
videoSize, frameRate,
storeMetaDataInVideoBuffers);
+ if (mInitCheck != OK) releaseCamera();
+ IPCThreadState::self()->restoreCallingIdentity(token);
}
status_t CameraSource::initCheck() const {
@@ -295,7 +298,6 @@ status_t CameraSource::configureCamera(
if (width != -1 && height != -1) {
if (!isVideoSizeSupported(width, height, sizes)) {
LOGE("Video dimension (%dx%d) is unsupported", width, height);
- releaseCamera();
return BAD_VALUE;
}
if (isSetVideoSizeSupportedByCamera) {
@@ -309,7 +311,6 @@ status_t CameraSource::configureCamera(
// If one and only one of the width and height is -1
// we reject such a request.
LOGE("Requested video size (%dx%d) is not supported", width, height);
- releaseCamera();
return BAD_VALUE;
} else { // width == -1 && height == -1
// Do not configure the camera.
@@ -327,7 +328,6 @@ status_t CameraSource::configureCamera(
if (strstr(supportedFrameRates, buf) == NULL) {
LOGE("Requested frame rate (%d) is not supported: %s",
frameRate, supportedFrameRates);
- releaseCamera();
return BAD_VALUE;
}
@@ -463,7 +463,6 @@ status_t CameraSource::init(
bool storeMetaDataInVideoBuffers) {
status_t err = OK;
- int64_t token = IPCThreadState::self()->clearCallingIdentity();
if ((err = isCameraAvailable(camera, proxy, cameraId)) != OK) {
LOGE("Camera connection could not be established.");
@@ -505,8 +504,6 @@ status_t CameraSource::init(
}
}
- IPCThreadState::self()->restoreCallingIdentity(token);
-
int64_t glitchDurationUs = (1000000LL / mVideoFrameRate);
if (glitchDurationUs > mGlitchDurationThresholdUs) {
mGlitchDurationThresholdUs = glitchDurationUs;
@@ -573,13 +570,21 @@ void CameraSource::stopCameraRecording() {
void CameraSource::releaseCamera() {
LOGV("releaseCamera");
- if ((mCameraFlags & FLAGS_HOT_CAMERA) == 0) {
- LOGV("Camera was cold when we started, stopping preview");
- mCamera->stopPreview();
+ if (mCamera != 0) {
+ if ((mCameraFlags & FLAGS_HOT_CAMERA) == 0) {
+ LOGV("Camera was cold when we started, stopping preview");
+ mCamera->stopPreview();
+ mCamera->disconnect();
+ } else {
+ // Unlock the camera so the application can lock it back.
+ mCamera->unlock();
+ }
+ mCamera.clear();
+ }
+ if (mCameraRecordingProxy != 0) {
+ mCameraRecordingProxy->asBinder()->unlinkToDeath(mDeathNotifier);
+ mCameraRecordingProxy.clear();
}
- mCamera.clear();
- mCameraRecordingProxy->asBinder()->unlinkToDeath(mDeathNotifier);
- mCameraRecordingProxy.clear();
mCameraFlags = 0;
}
diff --git a/media/libstagefright/HTTPBase.cpp b/media/libstagefright/HTTPBase.cpp
index c0ae29dc1ac7..0d2455108a23 100644
--- a/media/libstagefright/HTTPBase.cpp
+++ b/media/libstagefright/HTTPBase.cpp
@@ -37,7 +37,8 @@ HTTPBase::HTTPBase()
mTotalTransferBytes(0),
mPrevBandwidthMeasureTimeUs(0),
mPrevEstimatedBandWidthKbps(0),
- mBandWidthCollectFreqMs(5000) {
+ mBandWidthCollectFreqMs(5000),
+ mUIDValid(false) {
}
// static
@@ -119,4 +120,19 @@ status_t HTTPBase::setBandwidthStatCollectFreq(int32_t freqMs) {
return OK;
}
+void HTTPBase::setUID(uid_t uid) {
+ mUIDValid = true;
+ mUID = uid;
+}
+
+bool HTTPBase::getUID(uid_t *uid) const {
+ if (!mUIDValid) {
+ return false;
+ }
+
+ *uid = mUID;
+
+ return true;
+}
+
} // namespace android
diff --git a/media/libstagefright/HTTPStream.cpp b/media/libstagefright/HTTPStream.cpp
index a156da69b6cd..d526ebd8bc1a 100644
--- a/media/libstagefright/HTTPStream.cpp
+++ b/media/libstagefright/HTTPStream.cpp
@@ -43,6 +43,7 @@ const char *HTTPStream::kStatusKey = ":status:"; // MUST be lowercase.
HTTPStream::HTTPStream()
: mState(READY),
+ mUIDValid(false),
mSocket(-1),
mSSLContext(NULL),
mSSL(NULL) {
@@ -57,6 +58,11 @@ HTTPStream::~HTTPStream() {
}
}
+void HTTPStream::setUID(uid_t uid) {
+ mUIDValid = true;
+ mUID = uid;
+}
+
static bool MakeSocketBlocking(int s, bool blocking) {
// Make socket non-blocking.
int flags = fcntl(s, F_GETFL, 0);
@@ -250,6 +256,10 @@ status_t HTTPStream::connect(const char *server, int port, bool https) {
continue;
}
+ if (mUIDValid) {
+ RegisterSocketUser(mSocket, mUID);
+ }
+
setReceiveTimeout(30); // Time out reads after 30 secs by default.
int s = mSocket;
@@ -596,5 +606,18 @@ void HTTPStream::setReceiveTimeout(int seconds) {
CHECK_EQ(0, setsockopt(mSocket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)));
}
+// static
+void HTTPStream::RegisterSocketUser(int s, uid_t uid) {
+ // Lower bits MUST be 0.
+ static const uint64_t kTag = 0xdeadbeef00000000ll;
+
+ AString line = StringPrintf("t %d %llu %d", s, kTag, uid);
+
+ int fd = open("/proc/net/xt_qtaguid/ctrl", O_WRONLY);
+ write(fd, line.c_str(), line.size());
+ close(fd);
+ fd = -1;
+}
+
} // namespace android
diff --git a/media/libstagefright/NuHTTPDataSource.cpp b/media/libstagefright/NuHTTPDataSource.cpp
index dac2ee4766d0..29497673fbd4 100644
--- a/media/libstagefright/NuHTTPDataSource.cpp
+++ b/media/libstagefright/NuHTTPDataSource.cpp
@@ -140,6 +140,11 @@ status_t NuHTTPDataSource::connect(
return ERROR_MALFORMED;
}
+ uid_t uid;
+ if (getUID(&uid)) {
+ mHTTP.setUID(uid);
+ }
+
return connect(host, port, path, https, headers, offset);
}
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index cd97302c290b..1ac2c1fbbfb4 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -477,6 +477,15 @@ sp<MediaSource> OMXCodec::Create(
const char *matchComponentName,
uint32_t flags,
const sp<ANativeWindow> &nativeWindow) {
+ int32_t requiresSecureBuffers;
+ if (source->getFormat()->findInt32(
+ kKeyRequiresSecureBuffers,
+ &requiresSecureBuffers)
+ && requiresSecureBuffers) {
+ flags |= kIgnoreCodecSpecificData;
+ flags |= kUseSecureInputBuffers;
+ }
+
const char *mime;
bool success = meta->findCString(kKeyMIMEType, &mime);
CHECK(success);
@@ -530,17 +539,17 @@ sp<MediaSource> OMXCodec::Create(
LOGV("Successfully allocated OMX node '%s'", componentName);
sp<OMXCodec> codec = new OMXCodec(
- omx, node, quirks,
+ omx, node, quirks, flags,
createEncoder, mime, componentName,
source, nativeWindow);
observer->setCodec(codec);
- err = codec->configureCodec(meta, flags);
+ err = codec->configureCodec(meta);
if (err == OK) {
if (!strcmp("OMX.Nvidia.mpeg2v.decode", componentName)) {
- codec->mOnlySubmitOneBufferAtOneTime = true;
+ codec->mFlags |= kOnlySubmitOneInputBufferAtOneTime;
}
return codec;
@@ -553,24 +562,11 @@ sp<MediaSource> OMXCodec::Create(
return NULL;
}
-status_t OMXCodec::configureCodec(const sp<MetaData> &meta, uint32_t flags) {
- mIsMetaDataStoredInVideoBuffers = false;
- if (flags & kStoreMetaDataInVideoBuffers) {
- mIsMetaDataStoredInVideoBuffers = true;
- }
-
- mOnlySubmitOneBufferAtOneTime = false;
- if (flags & kOnlySubmitOneInputBufferAtOneTime) {
- mOnlySubmitOneBufferAtOneTime = true;
- }
+status_t OMXCodec::configureCodec(const sp<MetaData> &meta) {
+ LOGV("configureCodec protected=%d",
+ (mFlags & kEnableGrallocUsageProtected) ? 1 : 0);
- mEnableGrallocUsageProtected = false;
- if (flags & kEnableGrallocUsageProtected) {
- mEnableGrallocUsageProtected = true;
- }
- LOGV("configureCodec protected=%d", mEnableGrallocUsageProtected);
-
- if (!(flags & kIgnoreCodecSpecificData)) {
+ if (!(mFlags & kIgnoreCodecSpecificData)) {
uint32_t type;
const void *data;
size_t size;
@@ -745,7 +741,7 @@ status_t OMXCodec::configureCodec(const sp<MetaData> &meta, uint32_t flags) {
initOutputFormat(meta);
- if ((flags & kClientNeedsFramebuffer)
+ if ((mFlags & kClientNeedsFramebuffer)
&& !strncmp(mComponentName, "OMX.SEC.", 8)) {
OMX_INDEXTYPE index;
@@ -1468,7 +1464,8 @@ status_t OMXCodec::setVideoOutputFormat(
}
OMXCodec::OMXCodec(
- const sp<IOMX> &omx, IOMX::node_id node, uint32_t quirks,
+ const sp<IOMX> &omx, IOMX::node_id node,
+ uint32_t quirks, uint32_t flags,
bool isEncoder,
const char *mime,
const char *componentName,
@@ -1478,6 +1475,7 @@ OMXCodec::OMXCodec(
mOMXLivesLocally(omx->livesLocally(getpid())),
mNode(node),
mQuirks(quirks),
+ mFlags(flags),
mIsEncoder(isEncoder),
mMIME(strdup(mime)),
mComponentName(strdup(componentName)),
@@ -1645,13 +1643,14 @@ status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) {
return allocateOutputBuffersFromNativeWindow();
}
- if (mEnableGrallocUsageProtected && portIndex == kPortIndexOutput) {
+ if ((mFlags & kEnableGrallocUsageProtected) && portIndex == kPortIndexOutput) {
LOGE("protected output buffers must be stent to an ANativeWindow");
return PERMISSION_DENIED;
}
status_t err = OK;
- if (mIsMetaDataStoredInVideoBuffers && portIndex == kPortIndexInput) {
+ if ((mFlags & kStoreMetaDataInVideoBuffers)
+ && portIndex == kPortIndexInput) {
err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexInput, OMX_TRUE);
if (err != OK) {
LOGE("Storing meta data in video buffers is not supported");
@@ -1687,7 +1686,8 @@ status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) {
IOMX::buffer_id buffer;
if (portIndex == kPortIndexInput
- && (mQuirks & kRequiresAllocateBufferOnInputPorts)) {
+ && ((mQuirks & kRequiresAllocateBufferOnInputPorts)
+ || (mFlags & kUseSecureInputBuffers))) {
if (mOMXLivesLocally) {
mem.clear();
@@ -1748,6 +1748,31 @@ status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) {
// dumpPortStatus(portIndex);
+ if (portIndex == kPortIndexInput && (mFlags & kUseSecureInputBuffers)) {
+ Vector<MediaBuffer *> buffers;
+ for (size_t i = 0; i < def.nBufferCountActual; ++i) {
+ const BufferInfo &info = mPortBuffers[kPortIndexInput].itemAt(i);
+
+ MediaBuffer *mbuf = new MediaBuffer(info.mData, info.mSize);
+ buffers.push(mbuf);
+ }
+
+ status_t err = mSource->setBuffers(buffers);
+
+ if (err != OK) {
+ for (size_t i = 0; i < def.nBufferCountActual; ++i) {
+ buffers.editItemAt(i)->release();
+ }
+ buffers.clear();
+
+ CODEC_LOGE(
+ "Codec requested to use secure input buffers but "
+ "upstream source didn't support that.");
+
+ return err;
+ }
+ }
+
return OK;
}
@@ -1815,7 +1840,7 @@ status_t OMXCodec::allocateOutputBuffersFromNativeWindow() {
// XXX: Currently this error is logged, but not fatal.
usage = 0;
}
- if (mEnableGrallocUsageProtected) {
+ if (mFlags & kEnableGrallocUsageProtected) {
usage |= GRALLOC_USAGE_PROTECTED;
}
@@ -1838,7 +1863,7 @@ status_t OMXCodec::allocateOutputBuffersFromNativeWindow() {
}
}
- LOGV("native_window_set_usage usage=0x%x", usage);
+ LOGV("native_window_set_usage usage=0x%lx", usage);
err = native_window_set_usage(
mNativeWindow.get(), usage | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP);
if (err != 0) {
@@ -2067,7 +2092,12 @@ void OMXCodec::on_message(const omx_message &msg) {
} else if (mState != ERROR
&& mPortStatus[kPortIndexInput] != SHUTTING_DOWN) {
CHECK_EQ((int)mPortStatus[kPortIndexInput], (int)ENABLED);
- drainInputBuffer(&buffers->editItemAt(i));
+
+ if (mFlags & kUseSecureInputBuffers) {
+ drainAnyInputBuffer();
+ } else {
+ drainInputBuffer(&buffers->editItemAt(i));
+ }
}
break;
}
@@ -2804,32 +2834,81 @@ void OMXCodec::fillOutputBuffers() {
void OMXCodec::drainInputBuffers() {
CHECK(mState == EXECUTING || mState == RECONFIGURING);
- Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
- for (size_t i = 0; i < buffers->size(); ++i) {
- BufferInfo *info = &buffers->editItemAt(i);
+ if (mFlags & kUseSecureInputBuffers) {
+ Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
+ for (size_t i = 0; i < buffers->size(); ++i) {
+ if (!drainAnyInputBuffer()
+ || (mFlags & kOnlySubmitOneInputBufferAtOneTime)) {
+ break;
+ }
+ }
+ } else {
+ Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
+ for (size_t i = 0; i < buffers->size(); ++i) {
+ BufferInfo *info = &buffers->editItemAt(i);
- if (info->mStatus != OWNED_BY_US) {
- continue;
+ if (info->mStatus != OWNED_BY_US) {
+ continue;
+ }
+
+ if (!drainInputBuffer(info)) {
+ break;
+ }
+
+ if (mFlags & kOnlySubmitOneInputBufferAtOneTime) {
+ break;
+ }
}
+ }
+}
- if (!drainInputBuffer(info)) {
- break;
+bool OMXCodec::drainAnyInputBuffer() {
+ return drainInputBuffer((BufferInfo *)NULL);
+}
+
+OMXCodec::BufferInfo *OMXCodec::findInputBufferByDataPointer(void *ptr) {
+ Vector<BufferInfo> *infos = &mPortBuffers[kPortIndexInput];
+ for (size_t i = 0; i < infos->size(); ++i) {
+ BufferInfo *info = &infos->editItemAt(i);
+
+ if (info->mData == ptr) {
+ CODEC_LOGV(
+ "input buffer data ptr = %p, buffer_id = %p",
+ ptr,
+ info->mBuffer);
+
+ return info;
}
+ }
- if (mOnlySubmitOneBufferAtOneTime) {
- break;
+ TRESPASS();
+}
+
+OMXCodec::BufferInfo *OMXCodec::findEmptyInputBuffer() {
+ Vector<BufferInfo> *infos = &mPortBuffers[kPortIndexInput];
+ for (size_t i = 0; i < infos->size(); ++i) {
+ BufferInfo *info = &infos->editItemAt(i);
+
+ if (info->mStatus == OWNED_BY_US) {
+ return info;
}
}
+
+ TRESPASS();
}
bool OMXCodec::drainInputBuffer(BufferInfo *info) {
- CHECK_EQ((int)info->mStatus, (int)OWNED_BY_US);
+ if (info != NULL) {
+ CHECK_EQ((int)info->mStatus, (int)OWNED_BY_US);
+ }
if (mSignalledEOS) {
return false;
}
if (mCodecSpecificDataIndex < mCodecSpecificData.size()) {
+ CHECK(!(mFlags & kUseSecureInputBuffers));
+
const CodecSpecificData *specific =
mCodecSpecificData[mCodecSpecificDataIndex];
@@ -2925,6 +3004,11 @@ bool OMXCodec::drainInputBuffer(BufferInfo *info) {
break;
}
+ if (mFlags & kUseSecureInputBuffers) {
+ info = findInputBufferByDataPointer(srcBuffer->data());
+ CHECK(info != NULL);
+ }
+
size_t remainingBytes = info->mSize - offset;
if (srcBuffer->range_length() > remainingBytes) {
@@ -2960,14 +3044,24 @@ bool OMXCodec::drainInputBuffer(BufferInfo *info) {
releaseBuffer = false;
info->mMediaBuffer = srcBuffer;
} else {
- if (mIsMetaDataStoredInVideoBuffers) {
+ if (mFlags & kStoreMetaDataInVideoBuffers) {
releaseBuffer = false;
info->mMediaBuffer = srcBuffer;
}
- memcpy((uint8_t *)info->mData + offset,
- (const uint8_t *)srcBuffer->data()
- + srcBuffer->range_offset(),
- srcBuffer->range_length());
+
+ if (mFlags & kUseSecureInputBuffers) {
+ // Data in "info" is already provided at this time.
+
+ releaseBuffer = false;
+
+ CHECK(info->mMediaBuffer == NULL);
+ info->mMediaBuffer = srcBuffer;
+ } else {
+ memcpy((uint8_t *)info->mData + offset,
+ (const uint8_t *)srcBuffer->data()
+ + srcBuffer->range_offset(),
+ srcBuffer->range_length());
+ }
}
int64_t lastBufferTimeUs;
@@ -3036,6 +3130,16 @@ bool OMXCodec::drainInputBuffer(BufferInfo *info) {
info->mBuffer, offset,
timestampUs, timestampUs / 1E6);
+ if (info == NULL) {
+ CHECK(mFlags & kUseSecureInputBuffers);
+ CHECK(signalEOS);
+
+ // This is fishy, there's still a MediaBuffer corresponding to this
+ // info available to the source at this point even though we're going
+ // to use it to signal EOS to the codec.
+ info = findEmptyInputBuffer();
+ }
+
err = mOMX->emptyBuffer(
mNode, info->mBuffer, 0, offset,
flags, timestampUs);
diff --git a/media/libstagefright/WVMExtractor.cpp b/media/libstagefright/WVMExtractor.cpp
index 7072d58d6cce..26eda0c4cfb1 100644
--- a/media/libstagefright/WVMExtractor.cpp
+++ b/media/libstagefright/WVMExtractor.cpp
@@ -33,25 +33,26 @@
#include <utils/Errors.h>
+/* The extractor lifetime is short - just long enough to get
+ * the media sources constructed - so the shared lib needs to remain open
+ * beyond the lifetime of the extractor. So keep the handle as a global
+ * rather than a member of the extractor
+ */
+void *gVendorLibHandle = NULL;
+
namespace android {
-Mutex WVMExtractor::sMutex;
-uint32_t WVMExtractor::sActiveExtractors = 0;
-void *WVMExtractor::sVendorLibHandle = NULL;
+static Mutex gWVMutex;
WVMExtractor::WVMExtractor(const sp<DataSource> &source)
: mDataSource(source) {
{
- Mutex::Autolock autoLock(sMutex);
-
- if (sVendorLibHandle == NULL) {
- CHECK(sActiveExtractors == 0);
- sVendorLibHandle = dlopen("libwvm.so", RTLD_NOW);
+ Mutex::Autolock autoLock(gWVMutex);
+ if (gVendorLibHandle == NULL) {
+ gVendorLibHandle = dlopen("libwvm.so", RTLD_NOW);
}
- sActiveExtractors++;
-
- if (sVendorLibHandle == NULL) {
+ if (gVendorLibHandle == NULL) {
LOGE("Failed to open libwvm.so");
return;
}
@@ -59,7 +60,7 @@ WVMExtractor::WVMExtractor(const sp<DataSource> &source)
typedef WVMLoadableExtractor *(*GetInstanceFunc)(sp<DataSource>);
GetInstanceFunc getInstanceFunc =
- (GetInstanceFunc) dlsym(sVendorLibHandle,
+ (GetInstanceFunc) dlsym(gVendorLibHandle,
"_ZN7android11GetInstanceENS_2spINS_10DataSourceEEE");
if (getInstanceFunc) {
@@ -71,17 +72,6 @@ WVMExtractor::WVMExtractor(const sp<DataSource> &source)
}
WVMExtractor::~WVMExtractor() {
- Mutex::Autolock autoLock(sMutex);
-
- CHECK(sActiveExtractors > 0);
- sActiveExtractors--;
-
- // Close lib after last use
- if (sActiveExtractors == 0) {
- if (sVendorLibHandle != NULL)
- dlclose(sVendorLibHandle);
- sVendorLibHandle = NULL;
- }
}
size_t WVMExtractor::countTracks() {
diff --git a/media/libstagefright/chromium_http/support.cpp b/media/libstagefright/chromium_http/support.cpp
index ed6846c4e406..f4b36688f4cd 100644
--- a/media/libstagefright/chromium_http/support.cpp
+++ b/media/libstagefright/chromium_http/support.cpp
@@ -41,6 +41,7 @@ namespace android {
static Mutex gNetworkThreadLock;
static base::Thread *gNetworkThread = NULL;
static scoped_refptr<net::URLRequestContext> gReqContext;
+static scoped_ptr<net::NetworkChangeNotifier> gNetworkChangeNotifier;
static void InitializeNetworkThreadIfNecessary() {
Mutex::Autolock autoLock(gNetworkThreadLock);
@@ -52,6 +53,8 @@ static void InitializeNetworkThreadIfNecessary() {
gReqContext = new SfRequestContext;
+ gNetworkChangeNotifier.reset(net::NetworkChangeNotifier::Create());
+
net::AndroidNetworkLibrary::RegisterSharedInstance(
new SfNetworkLibrary);
}
@@ -112,31 +115,31 @@ SfRequestContext::SfRequestContext() {
mUserAgent = ua.c_str();
- net_log_ = new SfNetLog;
+ set_net_log(new SfNetLog());
- host_resolver_ =
+ set_host_resolver(
net::CreateSystemHostResolver(
net::HostResolver::kDefaultParallelism,
NULL /* resolver_proc */,
- net_log_);
+ net_log()));
- ssl_config_service_ =
- net::SSLConfigService::CreateSystemSSLConfigService();
+ set_ssl_config_service(
+ net::SSLConfigService::CreateSystemSSLConfigService());
- proxy_service_ = net::ProxyService::CreateWithoutProxyResolver(
- new net::ProxyConfigServiceAndroid, net_log_);
+ set_proxy_service(net::ProxyService::CreateWithoutProxyResolver(
+ new net::ProxyConfigServiceAndroid, net_log()));
- http_transaction_factory_ = new net::HttpCache(
- host_resolver_,
+ set_http_transaction_factory(new net::HttpCache(
+ host_resolver(),
new net::CertVerifier(),
- dnsrr_resolver_,
- dns_cert_checker_.get(),
- proxy_service_.get(),
- ssl_config_service_.get(),
- net::HttpAuthHandlerFactory::CreateDefault(host_resolver_),
- network_delegate_,
- net_log_,
- NULL); // backend_factory
+ dnsrr_resolver(),
+ dns_cert_checker(),
+ proxy_service(),
+ ssl_config_service(),
+ net::HttpAuthHandlerFactory::CreateDefault(host_resolver()),
+ network_delegate(),
+ net_log(),
+ NULL)); // backend_factory
}
const std::string &SfRequestContext::GetUserAgent(const GURL &url) const {
diff --git a/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp b/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
index e3292e63c679..009676011714 100644
--- a/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
+++ b/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
@@ -475,7 +475,9 @@ status_t AVCEncoder::read(
}
status_t err = mSource->read(&mInputBuffer, options);
if (err != OK) {
- LOGE("Failed to read input video frame: %d", err);
+ if (err != ERROR_END_OF_STREAM) {
+ LOGE("Failed to read input video frame: %d", err);
+ }
outputBuffer->release();
return err;
}
diff --git a/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp
index 15ed2193ae61..d7249c1ebb4f 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp
+++ b/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp
@@ -398,10 +398,13 @@ status_t M4vH263Encoder::read(
}
// Ready for accepting an input video frame
- if (OK != mSource->read(&mInputBuffer, options)) {
- LOGE("Failed to read from data source");
+ status_t err = mSource->read(&mInputBuffer, options);
+ if (OK != err) {
+ if (err != ERROR_END_OF_STREAM) {
+ LOGE("Failed to read from data source");
+ }
outputBuffer->release();
- return UNKNOWN_ERROR;
+ return err;
}
if (mInputBuffer->size() - ((mVideoWidth * mVideoHeight * 3) >> 1) != 0) {
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 165683e986b6..8ecc17ce5580 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -41,8 +41,10 @@ namespace android {
const int64_t LiveSession::kMaxPlaylistAgeUs = 15000000ll;
-LiveSession::LiveSession(uint32_t flags)
+LiveSession::LiveSession(uint32_t flags, bool uidValid, uid_t uid)
: mFlags(flags),
+ mUIDValid(uidValid),
+ mUID(uid),
mDataSource(new LiveDataSource),
mHTTPDataSource(
HTTPBase::Create(
@@ -58,6 +60,9 @@ LiveSession::LiveSession(uint32_t flags)
mSeekDone(false),
mDisconnectPending(false),
mMonitorQueueGeneration(0) {
+ if (mUIDValid) {
+ mHTTPDataSource->setUID(mUID);
+ }
}
LiveSession::~LiveSession() {
@@ -408,13 +413,20 @@ rinse_repeat:
if (firstTime) {
Mutex::Autolock autoLock(mLock);
- int32_t targetDuration;
- if (!mPlaylist->isComplete()
- || !mPlaylist->meta()->findInt32(
- "target-duration", &targetDuration)) {
+ if (!mPlaylist->isComplete()) {
mDurationUs = -1;
} else {
- mDurationUs = 1000000ll * targetDuration * mPlaylist->size();
+ mDurationUs = 0;
+ for (size_t i = 0; i < mPlaylist->size(); ++i) {
+ sp<AMessage> itemMeta;
+ CHECK(mPlaylist->itemAt(
+ i, NULL /* uri */, &itemMeta));
+
+ int64_t itemDurationUs;
+ CHECK(itemMeta->findInt64("durationUs", &itemDurationUs));
+
+ mDurationUs += itemDurationUs;
+ }
}
}
@@ -431,14 +443,26 @@ rinse_repeat:
bool bandwidthChanged = false;
if (mSeekTimeUs >= 0) {
- int32_t targetDuration;
- if (mPlaylist->isComplete() &&
- mPlaylist->meta()->findInt32(
- "target-duration", &targetDuration)) {
- int64_t seekTimeSecs = (mSeekTimeUs + 500000ll) / 1000000ll;
- int64_t index = seekTimeSecs / targetDuration;
-
- if (index >= 0 && index < mPlaylist->size()) {
+ if (mPlaylist->isComplete()) {
+ size_t index = 0;
+ int64_t segmentStartUs = 0;
+ while (index < mPlaylist->size()) {
+ sp<AMessage> itemMeta;
+ CHECK(mPlaylist->itemAt(
+ index, NULL /* uri */, &itemMeta));
+
+ int64_t itemDurationUs;
+ CHECK(itemMeta->findInt64("durationUs", &itemDurationUs));
+
+ if (mSeekTimeUs < segmentStartUs + itemDurationUs) {
+ break;
+ }
+
+ segmentStartUs += itemDurationUs;
+ ++index;
+ }
+
+ if (index < mPlaylist->size()) {
int32_t newSeqNumber = firstSeqNumberInPlaylist + index;
if (newSeqNumber != mSeqNumber) {
@@ -652,6 +676,10 @@ status_t LiveSession::decryptBuffer(
? HTTPBase::kFlagIncognito
: 0);
+ if (mUIDValid) {
+ keySource->setUID(mUID);
+ }
+
status_t err = keySource->connect(keyURI.c_str());
if (err == OK) {
diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
index 765f79565d5a..123fbf8b23e4 100644
--- a/media/libstagefright/httplive/M3UParser.cpp
+++ b/media/libstagefright/httplive/M3UParser.cpp
@@ -64,14 +64,21 @@ size_t M3UParser::size() {
}
bool M3UParser::itemAt(size_t index, AString *uri, sp<AMessage> *meta) {
- uri->clear();
- if (meta) { *meta = NULL; }
+ if (uri) {
+ uri->clear();
+ }
+
+ if (meta) {
+ *meta = NULL;
+ }
if (index >= mItems.size()) {
return false;
}
- *uri = mItems.itemAt(index).mURI;
+ if (uri) {
+ *uri = mItems.itemAt(index).mURI;
+ }
if (meta) {
*meta = mItems.itemAt(index).mMeta;
diff --git a/media/libstagefright/include/ARTSPController.h b/media/libstagefright/include/ARTSPController.h
index ce7ffe5c2352..2bd5be632a26 100644
--- a/media/libstagefright/include/ARTSPController.h
+++ b/media/libstagefright/include/ARTSPController.h
@@ -30,6 +30,8 @@ struct MyHandler;
struct ARTSPController : public MediaExtractor {
ARTSPController(const sp<ALooper> &looper);
+ void setUID(uid_t uid);
+
status_t connect(const char *url);
void disconnect();
@@ -80,6 +82,9 @@ private:
sp<MyHandler> mHandler;
sp<AHandlerReflector<ARTSPController> > mReflector;
+ bool mUIDValid;
+ uid_t mUID;
+
void (*mSeekDoneCb)(void *);
void *mSeekDoneCookie;
int64_t mLastSeekCompletedTimeUs;
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index f6df3801c2fe..e069b4dbaf65 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -62,6 +62,7 @@ struct AwesomePlayer {
~AwesomePlayer();
void setListener(const wp<MediaPlayerBase> &listener);
+ void setUID(uid_t uid);
status_t setDataSource(
const char *uri,
@@ -150,6 +151,8 @@ private:
TimedEventQueue mQueue;
bool mQueueStarted;
wp<MediaPlayerBase> mListener;
+ bool mUIDValid;
+ uid_t mUID;
sp<Surface> mSurface;
sp<ANativeWindow> mNativeWindow;
diff --git a/media/libstagefright/include/HTTPBase.h b/media/libstagefright/include/HTTPBase.h
index 3a7fbb690d16..2e25dd918086 100644
--- a/media/libstagefright/include/HTTPBase.h
+++ b/media/libstagefright/include/HTTPBase.h
@@ -48,13 +48,15 @@ struct HTTPBase : public DataSource {
virtual status_t setBandwidthStatCollectFreq(int32_t freqMs);
+ void setUID(uid_t uid);
+ bool getUID(uid_t *uid) const;
+
static sp<HTTPBase> Create(uint32_t flags = 0);
protected:
void addBandwidthMeasurement(size_t numBytes, int64_t delayUs);
private:
-
struct BandwidthEntry {
int64_t mDelayUs;
size_t mNumBytes;
@@ -76,6 +78,8 @@ private:
int32_t mPrevEstimatedBandWidthKbps;
int32_t mBandWidthCollectFreqMs;
+ bool mUIDValid;
+ uid_t mUID;
DISALLOW_EVIL_CONSTRUCTORS(HTTPBase);
};
diff --git a/media/libstagefright/include/HTTPStream.h b/media/libstagefright/include/HTTPStream.h
index 09e6a5fbdf52..88ba9d6e1435 100644
--- a/media/libstagefright/include/HTTPStream.h
+++ b/media/libstagefright/include/HTTPStream.h
@@ -32,6 +32,8 @@ public:
HTTPStream();
~HTTPStream();
+ void setUID(uid_t uid);
+
status_t connect(const char *server, int port = -1, bool https = false);
status_t disconnect();
@@ -58,6 +60,8 @@ public:
// _excluding_ the termianting CRLF.
status_t receive_line(char *line, size_t size);
+ static void RegisterSocketUser(int s, uid_t uid);
+
private:
enum State {
READY,
@@ -67,6 +71,10 @@ private:
State mState;
Mutex mLock;
+
+ bool mUIDValid;
+ uid_t mUID;
+
int mSocket;
KeyedVector<AString, AString> mHeaders;
diff --git a/media/libstagefright/include/LiveSession.h b/media/libstagefright/include/LiveSession.h
index 99abe64c2fea..188ef5e605b3 100644
--- a/media/libstagefright/include/LiveSession.h
+++ b/media/libstagefright/include/LiveSession.h
@@ -35,7 +35,7 @@ struct LiveSession : public AHandler {
// Don't log any URLs.
kFlagIncognito = 1,
};
- LiveSession(uint32_t flags = 0);
+ LiveSession(uint32_t flags = 0, bool uidValid = false, uid_t uid = 0);
sp<DataSource> getDataSource();
@@ -77,6 +77,8 @@ private:
};
uint32_t mFlags;
+ bool mUIDValid;
+ uid_t mUID;
sp<LiveDataSource> mDataSource;
diff --git a/media/libstagefright/include/WVMExtractor.h b/media/libstagefright/include/WVMExtractor.h
index 0817babb45e0..deecd2543a92 100644
--- a/media/libstagefright/include/WVMExtractor.h
+++ b/media/libstagefright/include/WVMExtractor.h
@@ -18,7 +18,6 @@
#define WVM_EXTRACTOR_H_
-#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaExtractor.h>
#include <utils/Errors.h>
@@ -68,10 +67,6 @@ private:
WVMExtractor(const WVMExtractor &);
WVMExtractor &operator=(const WVMExtractor &);
-
- static Mutex sMutex;
- static uint32_t sActiveExtractors;
- static void *sVendorLibHandle;
};
} // namespace android
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index c4e0cdcab5d3..072d6b2fd46d 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -34,13 +34,17 @@
#include <openssl/md5.h>
#include <sys/socket.h>
+#include "HTTPStream.h"
+
namespace android {
// static
const int64_t ARTSPConnection::kSelectTimeoutUs = 1000ll;
-ARTSPConnection::ARTSPConnection()
- : mState(DISCONNECTED),
+ARTSPConnection::ARTSPConnection(bool uidValid, uid_t uid)
+ : mUIDValid(uidValid),
+ mUID(uid),
+ mState(DISCONNECTED),
mAuthType(NONE),
mSocket(-1),
mConnectionID(0),
@@ -246,6 +250,10 @@ void ARTSPConnection::onConnect(const sp<AMessage> &msg) {
mSocket = socket(AF_INET, SOCK_STREAM, 0);
+ if (mUIDValid) {
+ HTTPStream::RegisterSocketUser(mSocket, mUID);
+ }
+
MakeSocketBlocking(mSocket, false);
struct sockaddr_in remote;
diff --git a/media/libstagefright/rtsp/ARTSPConnection.h b/media/libstagefright/rtsp/ARTSPConnection.h
index ac2e3ae1b856..5cb84fd08f96 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.h
+++ b/media/libstagefright/rtsp/ARTSPConnection.h
@@ -33,7 +33,7 @@ struct ARTSPResponse : public RefBase {
};
struct ARTSPConnection : public AHandler {
- ARTSPConnection();
+ ARTSPConnection(bool uidValid = false, uid_t uid = 0);
void connect(const char *url, const sp<AMessage> &reply);
void disconnect(const sp<AMessage> &reply);
@@ -74,6 +74,8 @@ private:
static const int64_t kSelectTimeoutUs;
+ bool mUIDValid;
+ uid_t mUID;
State mState;
AString mUser, mPass;
AuthType mAuthType;
diff --git a/media/libstagefright/rtsp/ARTSPController.cpp b/media/libstagefright/rtsp/ARTSPController.cpp
index 1328d2ec595c..2ebae7e37abc 100644
--- a/media/libstagefright/rtsp/ARTSPController.cpp
+++ b/media/libstagefright/rtsp/ARTSPController.cpp
@@ -28,6 +28,7 @@ namespace android {
ARTSPController::ARTSPController(const sp<ALooper> &looper)
: mState(DISCONNECTED),
mLooper(looper),
+ mUIDValid(false),
mSeekDoneCb(NULL),
mSeekDoneCookie(NULL),
mLastSeekCompletedTimeUs(-1) {
@@ -40,6 +41,11 @@ ARTSPController::~ARTSPController() {
mLooper->unregisterHandler(mReflector->id());
}
+void ARTSPController::setUID(uid_t uid) {
+ mUIDValid = true;
+ mUID = uid;
+}
+
status_t ARTSPController::connect(const char *url) {
Mutex::Autolock autoLock(mLock);
@@ -49,7 +55,7 @@ status_t ARTSPController::connect(const char *url) {
sp<AMessage> msg = new AMessage(kWhatConnectDone, mReflector->id());
- mHandler = new MyHandler(url, mLooper);
+ mHandler = new MyHandler(url, mLooper, mUIDValid, mUID);
mState = CONNECTING;
diff --git a/media/libstagefright/rtsp/ASessionDescription.cpp b/media/libstagefright/rtsp/ASessionDescription.cpp
index fd0505eb267c..f03f7a268fb2 100644
--- a/media/libstagefright/rtsp/ASessionDescription.cpp
+++ b/media/libstagefright/rtsp/ASessionDescription.cpp
@@ -301,9 +301,6 @@ void ASessionDescription::ParseFormatDesc(
// static
bool ASessionDescription::parseNTPRange(
const char *s, float *npt1, float *npt2) {
- *npt1 = 0.0f;
- *npt2 = 0.0f;
-
if (s[0] == '-') {
return false; // no start time available.
}
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index f89f8e20054d..3188959564a0 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -40,6 +40,8 @@
#include <sys/socket.h>
#include <netdb.h>
+#include "HTTPStream.h"
+
// If no access units are received within 5 secs, assume that the rtp
// stream has ended and signal end of stream.
static int64_t kAccessUnitTimeoutUs = 5000000ll;
@@ -92,10 +94,14 @@ static bool GetAttribute(const char *s, const char *key, AString *value) {
}
struct MyHandler : public AHandler {
- MyHandler(const char *url, const sp<ALooper> &looper)
- : mLooper(looper),
+ MyHandler(
+ const char *url, const sp<ALooper> &looper,
+ bool uidValid = false, uid_t uid = 0)
+ : mUIDValid(uidValid),
+ mUID(uid),
+ mLooper(looper),
mNetLooper(new ALooper),
- mConn(new ARTSPConnection),
+ mConn(new ARTSPConnection(mUIDValid, mUID)),
mRTPConn(new ARTPConnection),
mOriginalSessionURL(url),
mSessionURL(url),
@@ -995,12 +1001,10 @@ struct MyHandler : public AHandler {
AString val;
CHECK(GetAttribute(range.c_str(), "npt", &val));
- bool seekable = true;
-
float npt1, npt2;
if (!ASessionDescription::parseNTPRange(val.c_str(), &npt1, &npt2)) {
// This is a live stream and therefore not seekable.
- seekable = false;
+ return;
}
i = response->mHeaders.indexOfKey("rtp-info");
@@ -1046,7 +1050,7 @@ struct MyHandler : public AHandler {
++n;
}
- mSeekable = seekable;
+ mSeekable = true;
}
sp<APacketSource> getPacketSource(size_t index) {
@@ -1080,6 +1084,8 @@ private:
List<sp<ABuffer> > mPackets;
};
+ bool mUIDValid;
+ uid_t mUID;
sp<ALooper> mLooper;
sp<ALooper> mNetLooper;
sp<ARTSPConnection> mConn;
@@ -1174,6 +1180,11 @@ private:
ARTPConnection::MakePortPair(
&info->mRTPSocket, &info->mRTCPSocket, &rtpPort);
+ if (mUIDValid) {
+ HTTPStream::RegisterSocketUser(info->mRTPSocket, mUID);
+ HTTPStream::RegisterSocketUser(info->mRTCPSocket, mUID);
+ }
+
request.append("Transport: RTP/AVP/UDP;unicast;client_port=");
request.append(rtpPort);
request.append("-");
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 6d8eab63c074..f42cbbfc4f7a 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -25,6 +25,11 @@
android:exported="true"
/>
+ <!-- started from PhoneWindowManager
+ TODO: Should have an android:permission attribute -->
+ <service android:name=".screenshot.TakeScreenshotService"
+ android:exported="false" />
+
<activity android:name=".usb.UsbPreferenceActivity"
android:theme="@*android:style/Theme.Holo.Dialog.Alert"
android:excludeFromRecents="true">
diff --git a/packages/SystemUI/res/drawable-hdpi/global_screenshot_background.9.png b/packages/SystemUI/res/drawable-hdpi/global_screenshot_background.9.png
new file mode 100644
index 000000000000..e14111dae168
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/global_screenshot_background.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/global_screenshot_background.9.png b/packages/SystemUI/res/drawable-mdpi/global_screenshot_background.9.png
new file mode 100644
index 000000000000..e14111dae168
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/global_screenshot_background.9.png
Binary files differ
diff --git a/packages/SystemUI/res/layout/global_screenshot.xml b/packages/SystemUI/res/layout/global_screenshot.xml
new file mode 100644
index 000000000000..6cb8799eaeb3
--- /dev/null
+++ b/packages/SystemUI/res/layout/global_screenshot.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <ImageView android:id="@+id/global_screenshot_background"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="#FF000000"
+ android:visibility="gone" />
+ <FrameLayout
+ android:id="@+id/global_screenshot_container"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:background="@drawable/global_screenshot_background"
+ android:visibility="gone">
+ <ImageView android:id="@+id/global_screenshot"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:adjustViewBounds="true" />
+ </FrameLayout>
+ <ImageView android:id="@+id/global_screenshot_flash"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="#FFFFFFFF"
+ android:visibility="gone" />
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
index bc2f7ee3ae44..51e7d97ef1ec 100644
--- a/packages/SystemUI/res/layout/navigation_bar.xml
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -25,14 +25,13 @@
android:layout_width="match_parent"
>
- <FrameLayout
- android:id="@+id/background"
+ <FrameLayout android:id="@+id/rot0"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:background="#FF000000"
>
- <LinearLayout android:id="@+id/rot0"
+ <LinearLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="horizontal"
@@ -40,12 +39,12 @@
<!-- navigation controls -->
<View
- android:layout_width="32dp"
+ android:layout_width="40dp"
android:layout_height="match_parent"
android:layout_weight="0"
/>
<com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
- android:layout_width="54dp"
+ android:layout_width="80dp"
android:layout_height="match_parent"
android:src="@drawable/ic_sysbar_back_default"
systemui:keyCode="4"
@@ -57,7 +56,7 @@
android:layout_weight="1"
/>
<com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
- android:layout_width="54dp"
+ android:layout_width="80dp"
android:layout_height="match_parent"
android:src="@drawable/ic_sysbar_home_default"
systemui:keyCode="3"
@@ -69,13 +68,13 @@
android:layout_weight="1"
/>
<ImageView android:id="@+id/recent_apps"
- android:layout_width="54dp"
+ android:layout_width="80dp"
android:layout_height="match_parent"
android:src="@drawable/ic_sysbar_recent_default"
android:layout_weight="0"
/>
<com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
- android:layout_width="32dp"
+ android:layout_width="40dp"
android:layout_height="match_parent"
android:src="@drawable/ic_sysbar_menu_default"
systemui:keyCode="82"
@@ -84,17 +83,31 @@
/>
</LinearLayout>
- <LinearLayout android:id="@+id/rot90"
+ <View android:id="@+id/deadzone"
+ android:layout_height="@dimen/navigation_bar_deadzone_size"
+ android:layout_width="match_parent"
+ android:layout_gravity="top"
+ android:clickable="true"
+ />
+ </FrameLayout>
+
+ <FrameLayout android:id="@+id/rot90"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:background="#FF000000"
+ android:visibility="gone"
+ android:paddingTop="24dp"
+ >
+
+ <LinearLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical"
- android:visibility="gone"
- android:paddingTop="24dp"
>
<!-- navigation controls -->
<com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/menu"
- android:layout_height="32dp"
+ android:layout_height="40dp"
android:layout_width="match_parent"
android:src="@drawable/ic_sysbar_menu_default_land"
systemui:keyCode="82"
@@ -102,7 +115,7 @@
android:visibility="invisible"
/>
<ImageView android:id="@+id/recent_apps"
- android:layout_height="54dp"
+ android:layout_height="80dp"
android:layout_width="match_parent"
android:src="@drawable/ic_sysbar_recent_default_land"
android:layout_weight="0"
@@ -113,7 +126,7 @@
android:layout_weight="1"
/>
<com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/home"
- android:layout_height="54dp"
+ android:layout_height="80dp"
android:layout_width="match_parent"
android:src="@drawable/ic_sysbar_home_default_land"
systemui:keyCode="3"
@@ -125,28 +138,32 @@
android:layout_weight="1"
/>
<com.android.systemui.statusbar.policy.KeyButtonView android:id="@+id/back"
- android:layout_height="54dp"
+ android:layout_height="80dp"
android:layout_width="match_parent"
android:src="@drawable/ic_sysbar_back_default_land"
systemui:keyCode="4"
android:layout_weight="0"
/>
<View
- android:layout_height="32dp"
+ android:layout_height="40dp"
android:layout_width="match_parent"
android:layout_weight="0"
/>
</LinearLayout>
- <LinearLayout android:id="@+id/rot270"
+ <View android:id="@+id/deadzone"
+ android:layout_width="@dimen/navigation_bar_deadzone_size"
android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:orientation="vertical"
- android:visibility="gone"
- >
-
- <!-- not used -->
- </LinearLayout>
-
+ android:layout_gravity="left"
+ android:clickable="true"
+ />
</FrameLayout>
+
+ <!-- not used -->
+ <View android:id="@+id/rot270"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"
+ android:visibility="gone"
+ />
+
</com.android.systemui.statusbar.phone.NavigationBarView>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 7a4ac5d816f6..5298f2e66927 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -36,10 +36,6 @@
<!-- Whether or not we show the number in the bar. -->
<bool name="config_statusBarShowNumber">true</bool>
- <!-- Whether a software navigation bar should be shown. NOTE: in the future this may be
- autodetected from the Configuration. -->
- <bool name="config_showNavigationBar">false</bool>
-
<!-- How many icons may be shown at once in the system bar. Includes any
slots that may be reused for things like IME control. -->
<integer name="config_maxNotificationIcons">5</integer>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 3944c203cc3d..da28e1eac25d 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -40,7 +40,11 @@
<dimen name="peek_window_y_offset">-12dp</dimen>
<!-- thickness (height) of the navigation bar on phones that require it -->
- <dimen name="navigation_bar_size">32dp</dimen>
+ <dimen name="navigation_bar_size">48dp</dimen>
+
+ <!-- thickness (height) of the dead zone at the top of the navigation bar,
+ reducing false presses on navbar buttons; approx 2mm -->
+ <dimen name="navigation_bar_deadzone_size">12dp</dimen>
<!-- thickness (height) of each notification row, including any separators or padding -->
<dimen name="notification_height">65dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 86e0cd014302..70f9b7521959 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -165,4 +165,9 @@
<string name="use_ptp_button_title">Mount as a camera (PTP)</string>
<!-- Label for the installer CD image option in UsbPreferenceActivity. [CHAR LIMIT=50] -->
<string name="installer_cd_button_title">Install Android File Transfer application for Mac</string>
+
+ <!-- toast message displayed when a screenshot is saved to the Gallery. -->
+ <string name="screenshot_saving_toast">Screenshot saved to Gallery</string>
+ <!-- toast message displayed when we fail to take a screenshot. -->
+ <string name="screenshot_failed_toast">Could not save screenshot</string>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
new file mode 100644
index 000000000000..83a5578cfa36
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.app.Activity;
+import android.content.ContentValues;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.PixelFormat;
+import android.media.MediaScannerConnection;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Binder;
+import android.os.Environment;
+import android.os.ServiceManager;
+import android.provider.MediaStore;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.Display;
+import android.view.IWindowManager;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.Surface;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.systemui.R;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.Thread;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * POD used in the AsyncTask which saves an image in the background.
+ */
+class SaveImageInBackgroundData {
+ Context context;
+ Bitmap image;
+ int result;
+}
+
+/**
+ * An AsyncTask that saves an image to the media store in the background.
+ */
+class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Void,
+ SaveImageInBackgroundData> {
+ private static final String TAG = "SaveImageInBackgroundTask";
+ private static final String SCREENSHOTS_DIR_NAME = "Screenshots";
+ private static final String SCREENSHOT_FILE_PATH_TEMPLATE = "%s/%s/Screenshot_%s-%d.png";
+
+ @Override
+ protected SaveImageInBackgroundData doInBackground(SaveImageInBackgroundData... params) {
+ if (params.length != 1) return null;
+
+ Context context = params[0].context;
+ Bitmap image = params[0].image;
+
+ try{
+ long currentTime = System.currentTimeMillis();
+ String date = new SimpleDateFormat("MM-dd-yy-kk-mm-ss").format(new Date(currentTime));
+ String imageDir = Environment.getExternalStoragePublicDirectory(
+ Environment.DIRECTORY_PICTURES).getAbsolutePath();
+ String imageFilePath = String.format(SCREENSHOT_FILE_PATH_TEMPLATE,
+ imageDir, SCREENSHOTS_DIR_NAME,
+ date, currentTime % 1000);
+
+ // Save the screenshot to the MediaStore
+ ContentValues values = new ContentValues();
+ values.put(MediaStore.Images.ImageColumns.DATA, imageFilePath);
+ values.put(MediaStore.Images.ImageColumns.TITLE, "Screenshot");
+ values.put(MediaStore.Images.ImageColumns.DISPLAY_NAME, "Screenshot");
+ values.put(MediaStore.Images.ImageColumns.DATE_TAKEN, currentTime);
+ values.put(MediaStore.Images.ImageColumns.DATE_ADDED, currentTime);
+ values.put(MediaStore.Images.ImageColumns.DATE_MODIFIED, currentTime);
+ values.put(MediaStore.Images.ImageColumns.MIME_TYPE, "image/png");
+ Uri uri = context.getContentResolver().insert(
+ MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
+
+ OutputStream out = context.getContentResolver().openOutputStream(uri);
+ image.compress(Bitmap.CompressFormat.PNG, 100, out);
+ out.flush();
+ out.close();
+
+ params[0].result = 0;
+ }catch(IOException e){
+ params[0].result = 1;
+ }
+
+ return params[0];
+ };
+
+ @Override
+ protected void onPostExecute(SaveImageInBackgroundData params) {
+ if (params.result > 0) {
+ // Show a message that we've failed to save the image to disk
+ Toast.makeText(params.context, R.string.screenshot_failed_toast,
+ Toast.LENGTH_SHORT).show();
+ } else {
+ // Show a message that we've saved the screenshot to disk
+ Toast.makeText(params.context, R.string.screenshot_saving_toast,
+ Toast.LENGTH_SHORT).show();
+ }
+ };
+}
+
+/**
+ * TODO:
+ * - Performance when over gl surfaces? Ie. Gallery
+ * - what do we say in the Toast? Which icon do we get if the user uses another
+ * type of gallery?
+ */
+class GlobalScreenshot {
+ private static final String TAG = "GlobalScreenshot";
+ private static final int SCREENSHOT_FADE_IN_DURATION = 900;
+ private static final int SCREENSHOT_FADE_OUT_DELAY = 1000;
+ private static final int SCREENSHOT_FADE_OUT_DURATION = 450;
+ private static final int TOAST_FADE_IN_DURATION = 500;
+ private static final int TOAST_FADE_OUT_DELAY = 1000;
+ private static final int TOAST_FADE_OUT_DURATION = 500;
+ private static final float BACKGROUND_ALPHA = 0.65f;
+ private static final float SCREENSHOT_SCALE = 0.85f;
+ private static final float SCREENSHOT_MIN_SCALE = 0.7f;
+ private static final float SCREENSHOT_ROTATION = -6.75f; // -12.5f;
+
+ private Context mContext;
+ private LayoutInflater mLayoutInflater;
+ private IWindowManager mIWindowManager;
+ private WindowManager mWindowManager;
+ private WindowManager.LayoutParams mWindowLayoutParams;
+ private Display mDisplay;
+ private DisplayMetrics mDisplayMetrics;
+ private Matrix mDisplayMatrix;
+
+ private Bitmap mScreenBitmap;
+ private View mScreenshotLayout;
+ private ImageView mBackgroundView;
+ private FrameLayout mScreenshotContainerView;
+ private ImageView mScreenshotView;
+
+ private AnimatorSet mScreenshotAnimation;
+
+ // General use cubic interpolator
+ final TimeInterpolator mCubicInterpolator = new TimeInterpolator() {
+ public float getInterpolation(float t) {
+ return t*t*t;
+ }
+ };
+ // The interpolator used to control the background alpha at the start of the animation
+ final TimeInterpolator mBackgroundViewAlphaInterpolator = new TimeInterpolator() {
+ public float getInterpolation(float t) {
+ float tStep = 0.35f;
+ if (t < tStep) {
+ return t * (1f / tStep);
+ } else {
+ return 1f;
+ }
+ }
+ };
+
+ /**
+ * @param context everything needs a context :(
+ */
+ public GlobalScreenshot(Context context) {
+ mContext = context;
+ mLayoutInflater = (LayoutInflater)
+ context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ // Inflate the screenshot layout
+ mDisplayMetrics = new DisplayMetrics();
+ mDisplayMatrix = new Matrix();
+ mScreenshotLayout = mLayoutInflater.inflate(R.layout.global_screenshot, null);
+ mBackgroundView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot_background);
+ mScreenshotContainerView = (FrameLayout) mScreenshotLayout.findViewById(R.id.global_screenshot_container);
+ mScreenshotView = (ImageView) mScreenshotLayout.findViewById(R.id.global_screenshot);
+ mScreenshotLayout.setFocusable(true);
+ mScreenshotLayout.setOnTouchListener(new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ // Intercept and ignore all touch events
+ return true;
+ }
+ });
+
+ // Setup the window that we are going to use
+ mIWindowManager = IWindowManager.Stub.asInterface(
+ ServiceManager.getService(Context.WINDOW_SERVICE));
+ mWindowLayoutParams = new WindowManager.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT, 0, 0,
+ WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY,
+ WindowManager.LayoutParams.FLAG_FULLSCREEN
+ | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
+ | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED_SYSTEM
+ | WindowManager.LayoutParams.FLAG_KEEP_SURFACE_WHILE_ANIMATING
+ | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+ | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED,
+ PixelFormat.TRANSLUCENT);
+ mWindowLayoutParams.token = new Binder();
+ mWindowLayoutParams.setTitle("ScreenshotAnimation");
+ mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+ mDisplay = mWindowManager.getDefaultDisplay();
+ }
+
+ /**
+ * Creates a new worker thread and saves the screenshot to the media store.
+ */
+ private void saveScreenshotInWorkerThread() {
+ SaveImageInBackgroundData data = new SaveImageInBackgroundData();
+ data.context = mContext;
+ data.image = mScreenBitmap;
+ new SaveImageInBackgroundTask().execute(data);
+ }
+
+ /**
+ * @return the current display rotation in degrees
+ */
+ private float getDegreesForRotation(int value) {
+ switch (value) {
+ case Surface.ROTATION_90:
+ return 90f;
+ case Surface.ROTATION_180:
+ return 180f;
+ case Surface.ROTATION_270:
+ return 270f;
+ }
+ return 0f;
+ }
+
+ /**
+ * Takes a screenshot of the current display and shows an animation.
+ */
+ void takeScreenshot() {
+ // We need to orient the screenshot correctly (and the Surface api seems to take screenshots
+ // only in the natural orientation of the device :!)
+ mDisplay.getRealMetrics(mDisplayMetrics);
+ float[] dims = {mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels};
+ float degrees = getDegreesForRotation(mDisplay.getRotation());
+ boolean requiresRotation = (degrees > 0);
+ if (requiresRotation) {
+ // Get the dimensions of the device in its native orientation
+ mDisplayMatrix.reset();
+ mDisplayMatrix.preRotate(-degrees);
+ mDisplayMatrix.mapPoints(dims);
+ dims[0] = Math.abs(dims[0]);
+ dims[1] = Math.abs(dims[1]);
+ }
+ mScreenBitmap = Surface.screenshot((int) dims[0], (int) dims[1]);
+ if (requiresRotation) {
+ // Rotate the screenshot to the current orientation
+ Bitmap ss = Bitmap.createBitmap(mDisplayMetrics.widthPixels,
+ mDisplayMetrics.heightPixels, Bitmap.Config.ARGB_8888);
+ Canvas c = new Canvas(ss);
+ c.translate(ss.getWidth() / 2, ss.getHeight() / 2);
+ c.rotate(360f - degrees);
+ c.translate(-dims[0] / 2, -dims[1] / 2);
+ c.drawBitmap(mScreenBitmap, 0, 0, null);
+ mScreenBitmap = ss;
+ }
+
+ // If we couldn't take the screenshot, notify the user
+ if (mScreenBitmap == null) {
+ Toast.makeText(mContext, R.string.screenshot_failed_toast,
+ Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ // Start the post-screenshot animation
+ startAnimation();
+ }
+
+
+ /**
+ * Starts the animation after taking the screenshot
+ */
+ private void startAnimation() {
+ // Add the view for the animation
+ mScreenshotView.setImageBitmap(mScreenBitmap);
+ mScreenshotLayout.requestFocus();
+
+ // Setup the animation with the screenshot just taken
+ if (mScreenshotAnimation != null) {
+ mScreenshotAnimation.end();
+ }
+
+ mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);
+ ValueAnimator screenshotFadeInAnim = createScreenshotFadeInAnimation();
+ ValueAnimator screenshotFadeOutAnim = createScreenshotFadeOutAnimation();
+ mScreenshotAnimation = new AnimatorSet();
+ mScreenshotAnimation.play(screenshotFadeInAnim).before(screenshotFadeOutAnim);
+ mScreenshotAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ // Save the screenshot once we have a bit of time now
+ saveScreenshotInWorkerThread();
+
+ mWindowManager.removeView(mScreenshotLayout);
+ }
+ });
+ mScreenshotAnimation.start();
+ }
+ private ValueAnimator createScreenshotFadeInAnimation() {
+ ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
+ anim.setInterpolator(mCubicInterpolator);
+ anim.setDuration(SCREENSHOT_FADE_IN_DURATION);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mBackgroundView.setVisibility(View.VISIBLE);
+ mScreenshotContainerView.setVisibility(View.VISIBLE);
+ }
+ });
+ anim.addUpdateListener(new AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ float t = ((Float) animation.getAnimatedValue()).floatValue();
+ mBackgroundView.setAlpha(mBackgroundViewAlphaInterpolator.getInterpolation(t) *
+ BACKGROUND_ALPHA);
+ float scaleT = SCREENSHOT_SCALE + (1f - t) * SCREENSHOT_SCALE;
+ mScreenshotContainerView.setAlpha(t*t*t*t);
+ mScreenshotContainerView.setScaleX(scaleT);
+ mScreenshotContainerView.setScaleY(scaleT);
+ mScreenshotContainerView.setRotation(t * SCREENSHOT_ROTATION);
+ }
+ });
+ return anim;
+ }
+ private ValueAnimator createScreenshotFadeOutAnimation() {
+ ValueAnimator anim = ValueAnimator.ofFloat(1f, 0f);
+ anim.setInterpolator(mCubicInterpolator);
+ anim.setStartDelay(SCREENSHOT_FADE_OUT_DELAY);
+ anim.setDuration(SCREENSHOT_FADE_OUT_DURATION);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mBackgroundView.setVisibility(View.GONE);
+ mScreenshotContainerView.setVisibility(View.GONE);
+ }
+ });
+ anim.addUpdateListener(new AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ float t = ((Float) animation.getAnimatedValue()).floatValue();
+ float scaleT = SCREENSHOT_MIN_SCALE +
+ t*(SCREENSHOT_SCALE - SCREENSHOT_MIN_SCALE);
+ mScreenshotContainerView.setAlpha(t);
+ mScreenshotContainerView.setScaleX(scaleT);
+ mScreenshotContainerView.setScaleY(scaleT);
+ mBackgroundView.setAlpha(t * t * BACKGROUND_ALPHA);
+ }
+ });
+ return anim;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
new file mode 100644
index 000000000000..35eaedf1f941
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.screenshot;
+
+import android.app.Service;
+import android.app.AlertDialog;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.Uri;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.util.Log;
+
+import com.android.internal.app.AlertActivity;
+import com.android.internal.app.AlertController;
+
+import com.android.systemui.R;
+
+public class TakeScreenshotService extends Service {
+ private static final String TAG = "TakeScreenshotService";
+
+ private static GlobalScreenshot mScreenshot;
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ if (mScreenshot == null) {
+ mScreenshot = new GlobalScreenshot(this);
+ }
+ mScreenshot.takeScreenshot();
+ return null;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 22181b8337ae..550fc57e9a78 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -36,13 +36,14 @@ import com.android.internal.statusbar.IStatusBarService;
import com.android.systemui.R;
public class NavigationBarView extends LinearLayout {
+ final static boolean DEBUG_DEADZONE = false;
+
final static boolean NAVBAR_ALWAYS_AT_RIGHT = true;
protected IStatusBarService mBarService;
final Display mDisplay;
View mCurrentView = null;
View[] mRotatedViews = new View[4];
- View mBackground;
Animator mLastAnimator = null;
public View getRecentsButton() {
@@ -74,13 +75,13 @@ public class NavigationBarView extends LinearLayout {
}
private void setLights(final boolean on) {
- float oldAlpha = mBackground.getAlpha();
+ float oldAlpha = mCurrentView.getAlpha();
android.util.Log.d("NavigationBarView", "animating alpha: " + oldAlpha + " -> "
+ (on ? 1f : 0f));
if (mLastAnimator != null && mLastAnimator.isRunning()) mLastAnimator.cancel();
- mLastAnimator = ObjectAnimator.ofFloat(mBackground, "alpha", oldAlpha, on ? 1f : 0f)
+ mLastAnimator = ObjectAnimator.ofFloat(mCurrentView, "alpha", oldAlpha, on ? 1f : 0f)
.setDuration(on ? 250 : 1500);
mLastAnimator.addListener(new AnimatorListenerAdapter() {
@Override
@@ -92,8 +93,6 @@ public class NavigationBarView extends LinearLayout {
}
public void onFinishInflate() {
- mBackground = findViewById(R.id.background);
-
mRotatedViews[Surface.ROTATION_0] =
mRotatedViews[Surface.ROTATION_180] = findViewById(R.id.rot0);
@@ -121,6 +120,10 @@ public class NavigationBarView extends LinearLayout {
mCurrentView = mRotatedViews[rot];
mCurrentView.setVisibility(View.VISIBLE);
+ if (DEBUG_DEADZONE) {
+ mCurrentView.findViewById(R.id.deadzone).setBackgroundColor(0x808080FF);
+ }
+
android.util.Log.d("NavigationBarView", "reorient(): rot=" + mDisplay.getRotation());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index d8474db3c2ef..4c7b0dd2ca54 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -246,7 +246,7 @@ public class PhoneStatusBar extends StatusBar {
mIntruderAlertView.setClickable(true);
try {
- boolean showNav = res.getBoolean(R.bool.config_showNavigationBar);
+ boolean showNav = res.getBoolean(com.android.internal.R.bool.config_showNavigationBar);
if (showNav) {
mNavigationBarView =
(NavigationBarView) View.inflate(context, R.layout.navigation_bar, null);
diff --git a/packages/VpnDialogs/Android.mk b/packages/VpnDialogs/Android.mk
index 89f010aaebcb..ac84125f8f4e 100644
--- a/packages/VpnDialogs/Android.mk
+++ b/packages/VpnDialogs/Android.mk
@@ -20,6 +20,8 @@ include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
+LOCAL_CERTIFICATE := platform
+
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := VpnDialogs
diff --git a/packages/VpnDialogs/AndroidManifest.xml b/packages/VpnDialogs/AndroidManifest.xml
index 4e6784ce0884..c0b0a08067cf 100644
--- a/packages/VpnDialogs/AndroidManifest.xml
+++ b/packages/VpnDialogs/AndroidManifest.xml
@@ -1,5 +1,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.vpndialogs">
+ package="com.android.vpndialogs"
+ android:sharedUserId="android.uid.system">
<application android:label="VpnDialogs">
<activity android:name=".ConfirmDialog"
diff --git a/packages/VpnDialogs/res/values/strings.xml b/packages/VpnDialogs/res/values/strings.xml
index 8186e2629173..df6d36bd2814 100644
--- a/packages/VpnDialogs/res/values/strings.xml
+++ b/packages/VpnDialogs/res/values/strings.xml
@@ -29,6 +29,7 @@
<string name="accept">I trust this application.</string>
+ <string name="legacy_title">VPN is connected</string>
<string name="configure">Configure</string>
<string name="disconnect">Disconnect</string>
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
index ba3f3448f066..c076ba0bfd2f 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
@@ -64,9 +64,6 @@ public class ManageDialog extends Activity implements Handler.Callback,
mService = IConnectivityManager.Stub.asInterface(
ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
- PackageManager pm = getPackageManager();
- ApplicationInfo app = pm.getApplicationInfo(mConfig.packageName, 0);
-
View view = View.inflate(this, R.layout.manage, null);
if (mConfig.sessionName != null) {
((TextView) view.findViewById(R.id.session)).setText(mConfig.sessionName);
@@ -75,15 +72,29 @@ public class ManageDialog extends Activity implements Handler.Callback,
mDataTransmitted = (TextView) view.findViewById(R.id.data_transmitted);
mDataReceived = (TextView) view.findViewById(R.id.data_received);
- mDialog = new AlertDialog.Builder(this)
- .setIcon(app.loadIcon(pm))
- .setTitle(app.loadLabel(pm))
- .setView(view)
- .setNeutralButton(R.string.disconnect, this)
- .setNegativeButton(android.R.string.cancel, this)
- .create();
+ if (mConfig.packageName == null) {
+ // Legacy VPN does not have a package name.
+ mDialog = new AlertDialog.Builder(this)
+ .setIcon(android.R.drawable.ic_dialog_info)
+ .setTitle(R.string.legacy_title)
+ .setView(view)
+ .setNeutralButton(R.string.disconnect, this)
+ .setNegativeButton(android.R.string.cancel, this)
+ .create();
+ } else {
+ PackageManager pm = getPackageManager();
+ ApplicationInfo app = pm.getApplicationInfo(mConfig.packageName, 0);
+
+ mDialog = new AlertDialog.Builder(this)
+ .setIcon(app.loadIcon(pm))
+ .setTitle(app.loadLabel(pm))
+ .setView(view)
+ .setNeutralButton(R.string.disconnect, this)
+ .setNegativeButton(android.R.string.cancel, this)
+ .create();
+ }
- if (mConfig.configureActivity != null) {
+ if (mConfig.configureIntent != null) {
mDialog.setButton(DialogInterface.BUTTON_POSITIVE,
getText(R.string.configure), this);
}
@@ -113,9 +124,7 @@ public class ManageDialog extends Activity implements Handler.Callback,
public void onClick(DialogInterface dialog, int which) {
try {
if (which == AlertDialog.BUTTON_POSITIVE) {
- Intent intent = new Intent();
- intent.setClassName(mConfig.packageName, mConfig.configureActivity);
- startActivity(intent);
+ mConfig.configureIntent.send();
} else if (which == AlertDialog.BUTTON_NEUTRAL) {
mService.prepareVpn("");
}
diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java
index 8b7a61e21ce7..1c4084c77cd1 100644
--- a/policy/src/com/android/internal/policy/impl/LockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/LockScreen.java
@@ -64,7 +64,6 @@ class LockScreen extends LinearLayout implements KeyguardScreen,
private KeyguardUpdateMonitor mUpdateMonitor;
private KeyguardScreenCallback mCallback;
- private SlidingTab mSlidingTab;
private TextView mScreenLocked;
private TextView mEmergencyCallText;
private Button mEmergencyCallButton;
@@ -89,11 +88,9 @@ class LockScreen extends LinearLayout implements KeyguardScreen,
private boolean mEnableMenuKeyInLockScreen;
private StatusView mStatusView;
- private WaveView mEnergyWave;
- private SlidingTabMethods mSlidingTabMethods;
- private WaveViewMethods mWaveViewMethods;
- private MultiWaveView mMultiWaveView;
- private MultiWaveViewMethods mMultiWaveViewMethods;
+ private UnlockWidgetCommonMethods mUnlockWidgetMethods;
+ private View mUnlockWidget;
+
/**
* The status of this lock screen.
@@ -151,9 +148,28 @@ class LockScreen extends LinearLayout implements KeyguardScreen,
}
}
- class SlidingTabMethods implements SlidingTab.OnTriggerListener {
+ private interface UnlockWidgetCommonMethods {
+ // Update resources based on phone state
+ public void updateResources();
+
+ // Get the view associated with this widget
+ public View getView();
- private void updateRightTabResources() {
+ // Reset the view
+ public void reset(boolean animate);
+
+ // Animate the widget if it supports ping()
+ public void ping();
+ }
+
+ class SlidingTabMethods implements SlidingTab.OnTriggerListener, UnlockWidgetCommonMethods {
+ private final SlidingTab mSlidingTab;
+
+ SlidingTabMethods(SlidingTab slidingTab) {
+ mSlidingTab = slidingTab;
+ }
+
+ public void updateResources() {
boolean vibe = mSilentMode
&& (mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_VIBRATE);
@@ -175,7 +191,6 @@ class LockScreen extends LinearLayout implements KeyguardScreen,
mCallback.goToUnlockScreen();
} else if (whichHandle == SlidingTab.OnTriggerListener.RIGHT_HANDLE) {
toggleRingMode();
- updateRightTabResources();
doSilenceRingToast();
mCallback.pokeWakelock();
}
@@ -195,12 +210,29 @@ class LockScreen extends LinearLayout implements KeyguardScreen,
mCallback.pokeWakelock();
}
}
+
+ public View getView() {
+ return mSlidingTab;
+ }
+
+ public void reset(boolean animate) {
+ mSlidingTab.reset(animate);
+ }
+
+ public void ping() {
+ }
}
private static final int WAIT_FOR_ANIMATION_TIMEOUT = 0;
private static final int STAY_ON_WHILE_GRABBED_TIMEOUT = 30000;
- class WaveViewMethods implements WaveView.OnTriggerListener {
+ class WaveViewMethods implements WaveView.OnTriggerListener, UnlockWidgetCommonMethods {
+
+ private final WaveView mWaveView;
+
+ WaveViewMethods(WaveView waveView) {
+ mWaveView = waveView;
+ }
/** {@inheritDoc} */
public void onTrigger(View v, int whichHandle) {
if (whichHandle == WaveView.OnTriggerListener.CENTER_HANDLE) {
@@ -210,8 +242,6 @@ class LockScreen extends LinearLayout implements KeyguardScreen,
/** {@inheritDoc} */
public void onGrabbedStateChange(View v, int grabbedState) {
- if (DBG) Log.v(TAG, "*** LockScreen accel is "
- + (mEnergyWave.isHardwareAccelerated() ? "on":"off"));
// Don't poke the wake lock when returning to a state where the handle is
// not grabbed since that can happen when the system (instead of the user)
// cancels the grab.
@@ -219,30 +249,51 @@ class LockScreen extends LinearLayout implements KeyguardScreen,
mCallback.pokeWakelock(STAY_ON_WHILE_GRABBED_TIMEOUT);
}
}
+
+ public void updateResources() {
+ }
+
+ public View getView() {
+ return mWaveView;
+ }
+ public void reset(boolean animate) {
+ mWaveView.reset();
+ }
+ public void ping() {
+ }
}
- class MultiWaveViewMethods implements MultiWaveView.OnTriggerListener {
+ class MultiWaveViewMethods implements MultiWaveView.OnTriggerListener,
+ UnlockWidgetCommonMethods {
+
+ private final MultiWaveView mMultiWaveView;
+
+ MultiWaveViewMethods(MultiWaveView multiWaveView) {
+ mMultiWaveView = multiWaveView;
+ }
+
+ public void updateResources() {
+ mMultiWaveView.setTargetResources(mSilentMode ? R.array.lockscreen_targets_when_silent
+ : R.array.lockscreen_targets_when_soundon);
+ }
+
public void onGrabbed(View v, int handle) {
}
+
public void onReleased(View v, int handle) {
}
+
public void onTrigger(View v, int target) {
if (target == 0) { // TODO: Use resources to determine which handle was used
mCallback.goToUnlockScreen();
} else if (target == 2) {
toggleRingMode();
- updateResources();
doSilenceRingToast();
+ mUnlockWidgetMethods.updateResources();
mCallback.pokeWakelock();
}
-
- }
-
- private void updateResources() {
- mMultiWaveView.setTargetResources(mSilentMode ? R.array.lockscreen_targets_when_silent
- : R.array.lockscreen_targets_when_soundon);
}
public void onGrabbedStateChange(View v, int handle) {
@@ -253,6 +304,18 @@ class LockScreen extends LinearLayout implements KeyguardScreen,
mCallback.pokeWakelock();
}
}
+
+ public View getView() {
+ return mMultiWaveView;
+ }
+
+ public void reset(boolean animate) {
+ mMultiWaveView.reset(animate);
+ }
+
+ public void ping() {
+ mMultiWaveView.ping();
+ }
}
private void requestUnlockScreen() {
@@ -371,32 +434,39 @@ class LockScreen extends LinearLayout implements KeyguardScreen,
mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
mSilentMode = isSilentMode();
- View unlockWidget = findViewById(R.id.unlock_widget);
- if (unlockWidget instanceof SlidingTab) {
- mSlidingTab = (SlidingTab) unlockWidget;
- mSlidingTab.setHoldAfterTrigger(true, false);
- mSlidingTab.setLeftHintText(R.string.lockscreen_unlock_label);
- mSlidingTab.setLeftTabResources(
+ mUnlockWidget = findViewById(R.id.unlock_widget);
+ if (mUnlockWidget instanceof SlidingTab) {
+ SlidingTab slidingTabView = (SlidingTab) mUnlockWidget;
+ slidingTabView.setHoldAfterTrigger(true, false);
+ slidingTabView.setLeftHintText(R.string.lockscreen_unlock_label);
+ slidingTabView.setLeftTabResources(
R.drawable.ic_jog_dial_unlock,
R.drawable.jog_tab_target_green,
R.drawable.jog_tab_bar_left_unlock,
R.drawable.jog_tab_left_unlock);
- mSlidingTabMethods = new SlidingTabMethods();
- mSlidingTab.setOnTriggerListener(mSlidingTabMethods);
- mSlidingTabMethods.updateRightTabResources();
- } else if (unlockWidget instanceof WaveView) {
- mEnergyWave = (WaveView) unlockWidget;
- mWaveViewMethods = new WaveViewMethods();
- mEnergyWave.setOnTriggerListener(mWaveViewMethods);
- } else if (unlockWidget instanceof MultiWaveView) {
- mMultiWaveView = (MultiWaveView) unlockWidget;
- mMultiWaveViewMethods = new MultiWaveViewMethods();
- mMultiWaveViewMethods.updateResources(); // update silence/ring resources
- mMultiWaveView.setOnTriggerListener(mMultiWaveViewMethods);
+ SlidingTabMethods slidingTabMethods = new SlidingTabMethods(slidingTabView);
+ slidingTabView.setOnTriggerListener(slidingTabMethods);
+ mUnlockWidgetMethods = slidingTabMethods;
+ } else if (mUnlockWidget instanceof WaveView) {
+ WaveView waveView = (WaveView) mUnlockWidget;
+ WaveViewMethods waveViewMethods = new WaveViewMethods(waveView);
+ waveView.setOnTriggerListener(waveViewMethods);
+ mUnlockWidgetMethods = waveViewMethods;
+ } else if (mUnlockWidget instanceof MultiWaveView) {
+ MultiWaveView multiWaveView = (MultiWaveView) mUnlockWidget;
+ MultiWaveViewMethods multiWaveViewMethods = new MultiWaveViewMethods(multiWaveView);
+ multiWaveView.setOnTriggerListener(multiWaveViewMethods);
+ mUnlockWidgetMethods = multiWaveViewMethods;
} else {
- throw new IllegalStateException("Unrecognized unlock widget: " + unlockWidget);
+ throw new IllegalStateException("Unrecognized unlock widget: " + mUnlockWidget);
}
+ // Update widget with initial ring state
+ mUnlockWidgetMethods.updateResources();
+
+ if (DBG) Log.v(TAG, "*** LockScreen accel is "
+ + (mUnlockWidget.isHardwareAccelerated() ? "on":"off"));
+
resetStatusInfo(updateMonitor);
}
@@ -540,16 +610,14 @@ class LockScreen extends LinearLayout implements KeyguardScreen,
* Enables unlocking of this screen. Typically just shows the unlock widget.
*/
private void enableUnlock() {
- if (mEnergyWave != null) mEnergyWave.setVisibility(View.VISIBLE);
- if (mSlidingTab != null) mSlidingTab.setVisibility(View.VISIBLE);
+ mUnlockWidgetMethods.getView().setVisibility(View.VISIBLE);
}
/**
* Disable unlocking of this screen. Typically just hides the unlock widget.
*/
private void disableUnlock() {
- if (mEnergyWave != null) mEnergyWave.setVisibility(View.GONE);
- if (mSlidingTab != null) mSlidingTab.setVisibility(View.GONE);
+ mUnlockWidgetMethods.getView().setVisibility(View.GONE);
}
/**
@@ -728,20 +796,13 @@ class LockScreen extends LinearLayout implements KeyguardScreen,
/** {@inheritDoc} */
public void onPause() {
- if (mEnergyWave != null) {
- mEnergyWave.reset();
- }
- if (mMultiWaveView != null) {
- mMultiWaveView.reset(false);
- }
+ mUnlockWidgetMethods.reset(false);
}
/** {@inheritDoc} */
public void onResume() {
resetStatusInfo(mUpdateMonitor);
- if (mMultiWaveView != null) {
- mMultiWaveView.ping();
- }
+ mUnlockWidgetMethods.ping();
}
/** {@inheritDoc} */
@@ -757,7 +818,7 @@ class LockScreen extends LinearLayout implements KeyguardScreen,
boolean silent = AudioManager.RINGER_MODE_NORMAL != state;
if (silent != mSilentMode) {
mSilentMode = silent;
- if (mSlidingTabMethods != null) mSlidingTabMethods.updateRightTabResources();
+ mUnlockWidgetMethods.updateResources();
}
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index b52e7e1c42a2..ad6cebb60b78 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -28,6 +28,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.CompatibilityInfo;
@@ -372,6 +373,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// What we do when the user long presses on home
private int mLongPressOnHomeBehavior = -1;
+ // Screenshot trigger states
+ private boolean mVolumeDownTriggered;
+ private boolean mPowerDownTriggered;
+
ShortcutManager mShortcutManager;
PowerManager.WakeLock mBroadcastWakeLock;
@@ -2339,6 +2344,26 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
}
+ private void takeScreenshot() {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ ComponentName cn = new ComponentName("com.android.systemui",
+ "com.android.systemui.screenshot.TakeScreenshotService");
+ Intent intent = new Intent();
+ intent.setComponent(cn);
+ ServiceConnection conn = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {}
+ @Override
+ public void onServiceDisconnected(ComponentName name) {}
+ };
+ mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE);
+ mContext.unbindService(conn);
+ }
+ });
+ }
+
/** {@inheritDoc} */
@Override
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
@@ -2398,6 +2423,24 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// Handle special keys.
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_DOWN:
+ if (down) {
+ // If the power key down was already triggered, take the screenshot
+ if (mPowerDownTriggered) {
+ // Dismiss the power-key longpress
+ mHandler.removeCallbacks(mPowerLongPress);
+ mPowerKeyHandled = true;
+
+ // Take the screenshot
+ takeScreenshot();
+
+ // Prevent the event from being passed through to the current activity
+ result &= ~ACTION_PASS_TO_USER;
+ break;
+ }
+ mVolumeDownTriggered = true;
+ } else {
+ mVolumeDownTriggered = false;
+ }
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_MUTE: {
if (down) {
@@ -2478,6 +2521,18 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case KeyEvent.KEYCODE_POWER: {
result &= ~ACTION_PASS_TO_USER;
if (down) {
+ // If the volume down key has been triggered, then just take the screenshot
+ if (mVolumeDownTriggered) {
+ // Take the screenshot
+ takeScreenshot();
+ mPowerKeyHandled = true;
+
+ // Prevent the event from being passed through to the current activity
+ break;
+ }
+ mPowerDownTriggered = true;
+
+
ITelephony telephonyService = getTelephonyService();
boolean hungUp = false;
if (telephonyService != null) {
@@ -2499,6 +2554,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
interceptPowerKeyDown(!isScreenOn || hungUp);
} else {
+ mPowerDownTriggered = false;
if (interceptPowerKeyUp(canceled)) {
result = (result & ~ACTION_POKE_USER_ACTIVITY) | ACTION_GO_TO_SLEEP;
}
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index 95b8a5723e2f..ca2540bfad20 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -212,8 +212,8 @@ status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis,
struct input_absinfo info;
if(ioctl(device->fd, EVIOCGABS(axis), &info)) {
- LOGW("Error reading absolute controller %d for device %s fd %d\n",
- axis, device->identifier.name.string(), device->fd);
+ LOGW("Error reading absolute controller %d for device %s fd %d, errno=%d",
+ axis, device->identifier.name.string(), device->fd, errno);
return -errno;
}
@@ -335,6 +335,33 @@ int32_t EventHub::getSwitchStateLocked(Device* device, int32_t sw) const {
return AKEY_STATE_UNKNOWN;
}
+status_t EventHub::getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const {
+ if (axis >= 0 && axis <= ABS_MAX) {
+ AutoMutex _l(mLock);
+
+ Device* device = getDeviceLocked(deviceId);
+ if (device != NULL) {
+ return getAbsoluteAxisValueLocked(device, axis, outValue);
+ }
+ }
+ *outValue = 0;
+ return -1;
+}
+
+status_t EventHub::getAbsoluteAxisValueLocked(Device* device, int32_t axis,
+ int32_t* outValue) const {
+ struct input_absinfo info;
+
+ if(ioctl(device->fd, EVIOCGABS(axis), &info)) {
+ LOGW("Error reading absolute controller %d for device %s fd %d, errno=%d",
+ axis, device->identifier.name.string(), device->fd, errno);
+ return -errno;
+ }
+
+ *outValue = info.value;
+ return OK;
+}
+
bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes,
const int32_t* keyCodes, uint8_t* outFlags) const {
AutoMutex _l(mLock);
diff --git a/services/input/EventHub.h b/services/input/EventHub.h
index 0a34e45a565c..695dfdfb25e6 100644
--- a/services/input/EventHub.h
+++ b/services/input/EventHub.h
@@ -186,6 +186,8 @@ public:
virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const = 0;
virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const = 0;
virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const = 0;
+ virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis,
+ int32_t* outValue) const = 0;
/*
* Examine key input devices for specific framework keycode support
@@ -237,6 +239,7 @@ public:
virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const;
virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const;
virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const;
+ virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const;
virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes,
const int32_t* keyCodes, uint8_t* outFlags) const;
@@ -305,6 +308,7 @@ private:
int32_t getScanCodeStateLocked(Device* device, int32_t scanCode) const;
int32_t getKeyCodeStateLocked(Device* device, int32_t keyCode) const;
int32_t getSwitchStateLocked(Device* device, int32_t sw) const;
+ int32_t getAbsoluteAxisValueLocked(Device* device, int32_t axis, int32_t* outValue) const;
bool markSupportedKeyCodesLocked(Device* device, size_t numCodes,
const int32_t* keyCodes, uint8_t* outFlags) const;
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index 4a50d8a7eda8..10b9083549f2 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -569,9 +569,9 @@ void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropR
break;
case DROP_REASON_BLOCKED:
LOGI("Dropped event because the current application is not responding and the user "
- "has started interating with a different application.");
+ "has started interacting with a different application.");
reason = "inbound event was dropped because the current application is not responding "
- "and the user has started interating with a different application";
+ "and the user has started interacting with a different application";
break;
case DROP_REASON_STALE:
LOGI("Dropped event because it is stale.");
@@ -1239,7 +1239,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
const InputWindow* newHoverWindow = NULL;
bool isSplit = mTouchState.split;
- bool wrongDevice = mTouchState.down
+ bool switchedDevice = mTouchState.deviceId >= 0
&& (mTouchState.deviceId != entry->deviceId
|| mTouchState.source != entry->source);
bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE
@@ -1248,28 +1248,27 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
bool newGesture = (maskedAction == AMOTION_EVENT_ACTION_DOWN
|| maskedAction == AMOTION_EVENT_ACTION_SCROLL
|| isHoverAction);
+ bool wrongDevice = false;
if (newGesture) {
bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN;
- if (wrongDevice && !down) {
+ if (switchedDevice && mTouchState.down && !down) {
+#if DEBUG_FOCUS
+ LOGD("Dropping event because a pointer for a different device is already down.");
+#endif
mTempTouchState.copyFrom(mTouchState);
- } else {
- mTempTouchState.reset();
- mTempTouchState.down = down;
- mTempTouchState.deviceId = entry->deviceId;
- mTempTouchState.source = entry->source;
- isSplit = false;
- wrongDevice = false;
+ injectionResult = INPUT_EVENT_INJECTION_FAILED;
+ switchedDevice = false;
+ wrongDevice = true;
+ goto Failed;
}
+ mTempTouchState.reset();
+ mTempTouchState.down = down;
+ mTempTouchState.deviceId = entry->deviceId;
+ mTempTouchState.source = entry->source;
+ isSplit = false;
} else {
mTempTouchState.copyFrom(mTouchState);
}
- if (wrongDevice) {
-#if DEBUG_FOCUS
- LOGD("Dropping event because a pointer for a different device is already down.");
-#endif
- injectionResult = INPUT_EVENT_INJECTION_FAILED;
- goto Failed;
- }
if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {
/* Case 1: New splittable pointer going down, or need target for hover or scroll. */
@@ -1598,18 +1597,38 @@ Failed:
// Update final pieces of touch state if the injector had permission.
if (injectionPermission == INJECTION_PERMISSION_GRANTED) {
if (!wrongDevice) {
- if (maskedAction == AMOTION_EVENT_ACTION_UP
- || maskedAction == AMOTION_EVENT_ACTION_CANCEL
- || isHoverAction) {
+ if (switchedDevice) {
+#if DEBUG_FOCUS
+ LOGD("Conflicting pointer actions: Switched to a different device.");
+#endif
+ *outConflictingPointerActions = true;
+ }
+
+ if (isHoverAction) {
+ // Started hovering, therefore no longer down.
+ if (mTouchState.down) {
+#if DEBUG_FOCUS
+ LOGD("Conflicting pointer actions: Hover received while pointer was down.");
+#endif
+ *outConflictingPointerActions = true;
+ }
+ mTouchState.reset();
+ if (maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER
+ || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) {
+ mTouchState.deviceId = entry->deviceId;
+ mTouchState.source = entry->source;
+ }
+ } else if (maskedAction == AMOTION_EVENT_ACTION_UP
+ || maskedAction == AMOTION_EVENT_ACTION_CANCEL) {
// All pointers up or canceled.
mTouchState.reset();
} else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
// First pointer went down.
if (mTouchState.down) {
- *outConflictingPointerActions = true;
#if DEBUG_FOCUS
- LOGD("Pointer down received while already down.");
+ LOGD("Conflicting pointer actions: Down received while already down.");
#endif
+ *outConflictingPointerActions = true;
}
mTouchState.copyFrom(mTempTouchState);
} else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) {
@@ -1868,6 +1887,18 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
return;
}
+ // If the motion event was modified in flight, then we cannot stream the sample.
+ if ((motionEventDispatchEntry->targetFlags & InputTarget::FLAG_DISPATCH_MASK)
+ != InputTarget::FLAG_DISPATCH_AS_IS) {
+#if DEBUG_BATCHING
+ LOGD("channel '%s' ~ Not streaming because the motion event was not "
+ "being dispatched as-is. "
+ "(Waiting for next dispatch cycle to start.)",
+ connection->getInputChannelName());
+#endif
+ return;
+ }
+
// The dispatch entry is in progress and is still potentially open for streaming.
// Try to stream the new motion sample. This might fail if the consumer has already
// consumed the motion event (or if the channel is broken).
@@ -1972,6 +2003,66 @@ void InputDispatcher::enqueueDispatchEntryLocked(
dispatchEntry->headMotionSample = appendedMotionSample;
}
+ // Apply target flags and update the connection's input state.
+ switch (eventEntry->type) {
+ case EventEntry::TYPE_KEY: {
+ KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
+ dispatchEntry->resolvedAction = keyEntry->action;
+ dispatchEntry->resolvedFlags = keyEntry->flags;
+
+ if (!connection->inputState.trackKey(keyEntry,
+ dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) {
+#if DEBUG_DISPATCH_CYCLE
+ LOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key event",
+ connection->getInputChannelName());
+#endif
+ return; // skip the inconsistent event
+ }
+ break;
+ }
+
+ case EventEntry::TYPE_MOTION: {
+ MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
+ if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
+ dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_OUTSIDE;
+ } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT) {
+ dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_EXIT;
+ } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER) {
+ dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;
+ } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) {
+ dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_CANCEL;
+ } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER) {
+ dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_DOWN;
+ } else {
+ dispatchEntry->resolvedAction = motionEntry->action;
+ }
+ if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE
+ && !connection->inputState.isHovering(
+ motionEntry->deviceId, motionEntry->source)) {
+#if DEBUG_DISPATCH_CYCLE
+ LOGD("channel '%s' ~ enqueueDispatchEntryLocked: filling in missing hover enter event",
+ connection->getInputChannelName());
+#endif
+ dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;
+ }
+
+ dispatchEntry->resolvedFlags = motionEntry->flags;
+ if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) {
+ dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
+ }
+
+ if (!connection->inputState.trackMotion(motionEntry,
+ dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) {
+#if DEBUG_DISPATCH_CYCLE
+ LOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent motion event",
+ connection->getInputChannelName());
+#endif
+ return; // skip the inconsistent event
+ }
+ break;
+ }
+ }
+
// Enqueue the dispatch entry.
connection->outboundQueue.enqueueAtTail(dispatchEntry);
}
@@ -1999,16 +2090,11 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
case EventEntry::TYPE_KEY: {
KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
- // Apply target flags.
- int32_t action = keyEntry->action;
- int32_t flags = keyEntry->flags;
-
- // Update the connection's input state.
- connection->inputState.trackKey(keyEntry, action);
-
// Publish the key event.
- status = connection->inputPublisher.publishKeyEvent(keyEntry->deviceId, keyEntry->source,
- action, flags, keyEntry->keyCode, keyEntry->scanCode,
+ status = connection->inputPublisher.publishKeyEvent(
+ keyEntry->deviceId, keyEntry->source,
+ dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
+ keyEntry->keyCode, keyEntry->scanCode,
keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,
keyEntry->eventTime);
@@ -2024,24 +2110,6 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
case EventEntry::TYPE_MOTION: {
MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
- // Apply target flags.
- int32_t action = motionEntry->action;
- int32_t flags = motionEntry->flags;
- if (dispatchEntry->targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
- action = AMOTION_EVENT_ACTION_OUTSIDE;
- } else if (dispatchEntry->targetFlags & InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT) {
- action = AMOTION_EVENT_ACTION_HOVER_EXIT;
- } else if (dispatchEntry->targetFlags & InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER) {
- action = AMOTION_EVENT_ACTION_HOVER_ENTER;
- } else if (dispatchEntry->targetFlags & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) {
- action = AMOTION_EVENT_ACTION_CANCEL;
- } else if (dispatchEntry->targetFlags & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER) {
- action = AMOTION_EVENT_ACTION_DOWN;
- }
- if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) {
- flags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
- }
-
// If headMotionSample is non-NULL, then it points to the first new sample that we
// were unable to dispatch during the previous cycle so we resume dispatching from
// that point in the list of motion samples.
@@ -2082,13 +2150,11 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
}
}
- // Update the connection's input state.
- connection->inputState.trackMotion(motionEntry, action);
-
// Publish the motion event and the first motion sample.
- status = connection->inputPublisher.publishMotionEvent(motionEntry->deviceId,
- motionEntry->source, action, flags, motionEntry->edgeFlags,
- motionEntry->metaState, motionEntry->buttonState,
+ status = connection->inputPublisher.publishMotionEvent(
+ motionEntry->deviceId, motionEntry->source,
+ dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
+ motionEntry->edgeFlags, motionEntry->metaState, motionEntry->buttonState,
xOffset, yOffset,
motionEntry->xPrecision, motionEntry->yPrecision,
motionEntry->downTime, firstMotionSample->eventTime,
@@ -2102,8 +2168,8 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
return;
}
- if (action == AMOTION_EVENT_ACTION_MOVE
- || action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
+ if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_MOVE
+ || dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) {
// Append additional motion samples.
MotionSample* nextMotionSample = firstMotionSample->next;
for (; nextMotionSample != NULL; nextMotionSample = nextMotionSample->next) {
@@ -2355,23 +2421,22 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(
break;
}
- int32_t xOffset, yOffset;
- float scaleFactor;
+ InputTarget target;
const InputWindow* window = getWindowLocked(connection->inputChannel);
if (window) {
- xOffset = -window->frameLeft;
- yOffset = -window->frameTop;
- scaleFactor = window->scaleFactor;
+ target.xOffset = -window->frameLeft;
+ target.yOffset = -window->frameTop;
+ target.scaleFactor = window->scaleFactor;
} else {
- xOffset = 0;
- yOffset = 0;
- scaleFactor = 1.0f;
+ target.xOffset = 0;
+ target.yOffset = 0;
+ target.scaleFactor = 1.0f;
}
+ target.inputChannel = connection->inputChannel;
+ target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
- DispatchEntry* cancelationDispatchEntry =
- mAllocator.obtainDispatchEntry(cancelationEventEntry, // increments ref
- 0, xOffset, yOffset, scaleFactor);
- connection->outboundQueue.enqueueAtTail(cancelationDispatchEntry);
+ enqueueDispatchEntryLocked(connection, cancelationEventEntry, // increments ref
+ &target, false, InputTarget::FLAG_DISPATCH_AS_IS);
mAllocator.releaseEventEntry(cancelationEventEntry);
}
@@ -3327,6 +3392,7 @@ void InputDispatcher::resetAndDropEverythingLocked(const char* reason) {
resetTargetsLocked();
mTouchState.reset();
+ mLastHoverWindow = NULL;
}
void InputDispatcher::logDispatchStateLocked() {
@@ -4125,113 +4191,188 @@ bool InputDispatcher::InputState::isNeutral() const {
return mKeyMementos.isEmpty() && mMotionMementos.isEmpty();
}
-void InputDispatcher::InputState::trackEvent(const EventEntry* entry, int32_t action) {
- switch (entry->type) {
- case EventEntry::TYPE_KEY:
- trackKey(static_cast<const KeyEntry*>(entry), action);
- break;
-
- case EventEntry::TYPE_MOTION:
- trackMotion(static_cast<const MotionEntry*>(entry), action);
- break;
+bool InputDispatcher::InputState::isHovering(int32_t deviceId, uint32_t source) const {
+ for (size_t i = 0; i < mMotionMementos.size(); i++) {
+ const MotionMemento& memento = mMotionMementos.itemAt(i);
+ if (memento.deviceId == deviceId
+ && memento.source == source
+ && memento.hovering) {
+ return true;
+ }
}
+ return false;
}
-void InputDispatcher::InputState::trackKey(const KeyEntry* entry, int32_t action) {
- if (action == AKEY_EVENT_ACTION_UP
- && (entry->flags & AKEY_EVENT_FLAG_FALLBACK)) {
- for (size_t i = 0; i < mFallbackKeys.size(); ) {
- if (mFallbackKeys.valueAt(i) == entry->keyCode) {
- mFallbackKeys.removeItemsAt(i);
- } else {
- i += 1;
+bool InputDispatcher::InputState::trackKey(const KeyEntry* entry,
+ int32_t action, int32_t flags) {
+ switch (action) {
+ case AKEY_EVENT_ACTION_UP: {
+ if (entry->flags & AKEY_EVENT_FLAG_FALLBACK) {
+ for (size_t i = 0; i < mFallbackKeys.size(); ) {
+ if (mFallbackKeys.valueAt(i) == entry->keyCode) {
+ mFallbackKeys.removeItemsAt(i);
+ } else {
+ i += 1;
+ }
}
}
+ ssize_t index = findKeyMemento(entry);
+ if (index >= 0) {
+ mKeyMementos.removeAt(index);
+ return true;
+ }
+#if DEBUG_OUTBOUND_EVENT_DETAILS
+ LOGD("Dropping inconsistent key up event: deviceId=%d, source=%08x, "
+ "keyCode=%d, scanCode=%d",
+ entry->deviceId, entry->source, entry->keyCode, entry->scanCode);
+#endif
+ return false;
}
- for (size_t i = 0; i < mKeyMementos.size(); i++) {
- KeyMemento& memento = mKeyMementos.editItemAt(i);
- if (memento.deviceId == entry->deviceId
- && memento.source == entry->source
- && memento.keyCode == entry->keyCode
- && memento.scanCode == entry->scanCode) {
- switch (action) {
- case AKEY_EVENT_ACTION_UP:
- mKeyMementos.removeAt(i);
- return;
-
- case AKEY_EVENT_ACTION_DOWN:
- mKeyMementos.removeAt(i);
- goto Found;
-
- default:
- return;
- }
+ case AKEY_EVENT_ACTION_DOWN: {
+ ssize_t index = findKeyMemento(entry);
+ if (index >= 0) {
+ mKeyMementos.removeAt(index);
}
+ addKeyMemento(entry, flags);
+ return true;
}
-Found:
- if (action == AKEY_EVENT_ACTION_DOWN) {
- mKeyMementos.push();
- KeyMemento& memento = mKeyMementos.editTop();
- memento.deviceId = entry->deviceId;
- memento.source = entry->source;
- memento.keyCode = entry->keyCode;
- memento.scanCode = entry->scanCode;
- memento.flags = entry->flags;
- memento.downTime = entry->downTime;
+ default:
+ return true;
}
}
-void InputDispatcher::InputState::trackMotion(const MotionEntry* entry, int32_t action) {
+bool InputDispatcher::InputState::trackMotion(const MotionEntry* entry,
+ int32_t action, int32_t flags) {
int32_t actionMasked = action & AMOTION_EVENT_ACTION_MASK;
- for (size_t i = 0; i < mMotionMementos.size(); i++) {
- MotionMemento& memento = mMotionMementos.editItemAt(i);
- if (memento.deviceId == entry->deviceId
- && memento.source == entry->source) {
- switch (actionMasked) {
- case AMOTION_EVENT_ACTION_UP:
- case AMOTION_EVENT_ACTION_CANCEL:
- case AMOTION_EVENT_ACTION_HOVER_ENTER:
- case AMOTION_EVENT_ACTION_HOVER_MOVE:
- case AMOTION_EVENT_ACTION_HOVER_EXIT:
- mMotionMementos.removeAt(i);
- return;
+ switch (actionMasked) {
+ case AMOTION_EVENT_ACTION_UP:
+ case AMOTION_EVENT_ACTION_CANCEL: {
+ ssize_t index = findMotionMemento(entry, false /*hovering*/);
+ if (index >= 0) {
+ mMotionMementos.removeAt(index);
+ return true;
+ }
+#if DEBUG_OUTBOUND_EVENT_DETAILS
+ LOGD("Dropping inconsistent motion up or cancel event: deviceId=%d, source=%08x, "
+ "actionMasked=%d",
+ entry->deviceId, entry->source, actionMasked);
+#endif
+ return false;
+ }
- case AMOTION_EVENT_ACTION_DOWN:
- mMotionMementos.removeAt(i);
- goto Found;
+ case AMOTION_EVENT_ACTION_DOWN: {
+ ssize_t index = findMotionMemento(entry, false /*hovering*/);
+ if (index >= 0) {
+ mMotionMementos.removeAt(index);
+ }
+ addMotionMemento(entry, flags, false /*hovering*/);
+ return true;
+ }
- case AMOTION_EVENT_ACTION_POINTER_UP:
- case AMOTION_EVENT_ACTION_POINTER_DOWN:
- case AMOTION_EVENT_ACTION_MOVE:
- memento.setPointers(entry);
- return;
+ case AMOTION_EVENT_ACTION_POINTER_UP:
+ case AMOTION_EVENT_ACTION_POINTER_DOWN:
+ case AMOTION_EVENT_ACTION_MOVE: {
+ ssize_t index = findMotionMemento(entry, false /*hovering*/);
+ if (index >= 0) {
+ MotionMemento& memento = mMotionMementos.editItemAt(index);
+ memento.setPointers(entry);
+ return true;
+ }
+ if (actionMasked == AMOTION_EVENT_ACTION_MOVE
+ && (entry->source & (AINPUT_SOURCE_CLASS_JOYSTICK
+ | AINPUT_SOURCE_CLASS_NAVIGATION))) {
+ // Joysticks and trackballs can send MOVE events without corresponding DOWN or UP.
+ return true;
+ }
+#if DEBUG_OUTBOUND_EVENT_DETAILS
+ LOGD("Dropping inconsistent motion pointer up/down or move event: "
+ "deviceId=%d, source=%08x, actionMasked=%d",
+ entry->deviceId, entry->source, actionMasked);
+#endif
+ return false;
+ }
- default:
- return;
- }
+ case AMOTION_EVENT_ACTION_HOVER_EXIT: {
+ ssize_t index = findMotionMemento(entry, true /*hovering*/);
+ if (index >= 0) {
+ mMotionMementos.removeAt(index);
+ return true;
}
+#if DEBUG_OUTBOUND_EVENT_DETAILS
+ LOGD("Dropping inconsistent motion hover exit event: deviceId=%d, source=%08x",
+ entry->deviceId, entry->source);
+#endif
+ return false;
}
-Found:
- switch (actionMasked) {
- case AMOTION_EVENT_ACTION_DOWN:
case AMOTION_EVENT_ACTION_HOVER_ENTER:
- case AMOTION_EVENT_ACTION_HOVER_MOVE:
- case AMOTION_EVENT_ACTION_HOVER_EXIT:
- mMotionMementos.push();
- MotionMemento& memento = mMotionMementos.editTop();
- memento.deviceId = entry->deviceId;
- memento.source = entry->source;
- memento.xPrecision = entry->xPrecision;
- memento.yPrecision = entry->yPrecision;
- memento.downTime = entry->downTime;
- memento.setPointers(entry);
- memento.hovering = actionMasked != AMOTION_EVENT_ACTION_DOWN;
+ case AMOTION_EVENT_ACTION_HOVER_MOVE: {
+ ssize_t index = findMotionMemento(entry, true /*hovering*/);
+ if (index >= 0) {
+ mMotionMementos.removeAt(index);
+ }
+ addMotionMemento(entry, flags, true /*hovering*/);
+ return true;
+ }
+
+ default:
+ return true;
}
}
+ssize_t InputDispatcher::InputState::findKeyMemento(const KeyEntry* entry) const {
+ for (size_t i = 0; i < mKeyMementos.size(); i++) {
+ const KeyMemento& memento = mKeyMementos.itemAt(i);
+ if (memento.deviceId == entry->deviceId
+ && memento.source == entry->source
+ && memento.keyCode == entry->keyCode
+ && memento.scanCode == entry->scanCode) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+ssize_t InputDispatcher::InputState::findMotionMemento(const MotionEntry* entry,
+ bool hovering) const {
+ for (size_t i = 0; i < mMotionMementos.size(); i++) {
+ const MotionMemento& memento = mMotionMementos.itemAt(i);
+ if (memento.deviceId == entry->deviceId
+ && memento.source == entry->source
+ && memento.hovering == hovering) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+void InputDispatcher::InputState::addKeyMemento(const KeyEntry* entry, int32_t flags) {
+ mKeyMementos.push();
+ KeyMemento& memento = mKeyMementos.editTop();
+ memento.deviceId = entry->deviceId;
+ memento.source = entry->source;
+ memento.keyCode = entry->keyCode;
+ memento.scanCode = entry->scanCode;
+ memento.flags = flags;
+ memento.downTime = entry->downTime;
+}
+
+void InputDispatcher::InputState::addMotionMemento(const MotionEntry* entry,
+ int32_t flags, bool hovering) {
+ mMotionMementos.push();
+ MotionMemento& memento = mMotionMementos.editTop();
+ memento.deviceId = entry->deviceId;
+ memento.source = entry->source;
+ memento.flags = flags;
+ memento.xPrecision = entry->xPrecision;
+ memento.yPrecision = entry->yPrecision;
+ memento.downTime = entry->downTime;
+ memento.setPointers(entry);
+ memento.hovering = hovering;
+}
+
void InputDispatcher::InputState::MotionMemento::setPointers(const MotionEntry* entry) {
pointerCount = entry->pointerCount;
for (uint32_t i = 0; i < entry->pointerCount; i++) {
@@ -4243,20 +4384,17 @@ void InputDispatcher::InputState::MotionMemento::setPointers(const MotionEntry*
void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTime,
Allocator* allocator, Vector<EventEntry*>& outEvents,
const CancelationOptions& options) {
- for (size_t i = 0; i < mKeyMementos.size(); ) {
+ for (size_t i = 0; i < mKeyMementos.size(); i++) {
const KeyMemento& memento = mKeyMementos.itemAt(i);
if (shouldCancelKey(memento, options)) {
outEvents.push(allocator->obtainKeyEntry(currentTime,
memento.deviceId, memento.source, 0,
AKEY_EVENT_ACTION_UP, memento.flags | AKEY_EVENT_FLAG_CANCELED,
memento.keyCode, memento.scanCode, 0, 0, memento.downTime));
- mKeyMementos.removeAt(i);
- } else {
- i += 1;
}
}
- for (size_t i = 0; i < mMotionMementos.size(); ) {
+ for (size_t i = 0; i < mMotionMementos.size(); i++) {
const MotionMemento& memento = mMotionMementos.itemAt(i);
if (shouldCancelMotion(memento, options)) {
outEvents.push(allocator->obtainMotionEntry(currentTime,
@@ -4264,12 +4402,9 @@ void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTim
memento.hovering
? AMOTION_EVENT_ACTION_HOVER_EXIT
: AMOTION_EVENT_ACTION_CANCEL,
- 0, 0, 0, 0,
+ memento.flags, 0, 0, 0,
memento.xPrecision, memento.yPrecision, memento.downTime,
memento.pointerCount, memento.pointerProperties, memento.pointerCoords));
- mMotionMementos.removeAt(i);
- } else {
- i += 1;
}
}
}
diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h
index 676d162daaac..bdd1922b9339 100644
--- a/services/input/InputDispatcher.h
+++ b/services/input/InputDispatcher.h
@@ -522,6 +522,10 @@ private:
// True if dispatch has started.
bool inProgress;
+ // Set to the resolved action and flags when the event is enqueued.
+ int32_t resolvedAction;
+ int32_t resolvedFlags;
+
// For motion events:
// Pointer to the first motion sample to dispatch in this cycle.
// Usually NULL to indicate that the list of motion samples begins at
@@ -709,14 +713,19 @@ private:
// Returns true if there is no state to be canceled.
bool isNeutral() const;
- // Records tracking information for an event that has just been published.
- void trackEvent(const EventEntry* entry, int32_t action);
+ // Returns true if the specified source is known to have received a hover enter
+ // motion event.
+ bool isHovering(int32_t deviceId, uint32_t source) const;
// Records tracking information for a key event that has just been published.
- void trackKey(const KeyEntry* entry, int32_t action);
+ // Returns true if the event should be delivered, false if it is inconsistent
+ // and should be skipped.
+ bool trackKey(const KeyEntry* entry, int32_t action, int32_t flags);
// Records tracking information for a motion event that has just been published.
- void trackMotion(const MotionEntry* entry, int32_t action);
+ // Returns true if the event should be delivered, false if it is inconsistent
+ // and should be skipped.
+ bool trackMotion(const MotionEntry* entry, int32_t action, int32_t flags);
// Synthesizes cancelation events for the current state and resets the tracked state.
void synthesizeCancelationEvents(nsecs_t currentTime, Allocator* allocator,
@@ -756,6 +765,7 @@ private:
struct MotionMemento {
int32_t deviceId;
uint32_t source;
+ int32_t flags;
float xPrecision;
float yPrecision;
nsecs_t downTime;
@@ -771,6 +781,12 @@ private:
Vector<MotionMemento> mMotionMementos;
KeyedVector<int32_t, int32_t> mFallbackKeys;
+ ssize_t findKeyMemento(const KeyEntry* entry) const;
+ ssize_t findMotionMemento(const MotionEntry* entry, bool hovering) const;
+
+ void addKeyMemento(const KeyEntry* entry, int32_t flags);
+ void addMotionMemento(const MotionEntry* entry, int32_t flags, bool hovering);
+
static bool shouldCancelKey(const KeyMemento& memento,
const CancelationOptions& options);
static bool shouldCancelMotion(const MotionMemento& memento,
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index 5a25f8cc9584..79218a5581ca 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -53,6 +53,7 @@
#define INDENT2 " "
#define INDENT3 " "
#define INDENT4 " "
+#define INDENT5 " "
namespace android {
@@ -921,7 +922,7 @@ void InputDevice::process(const RawEvent* rawEvents, size_t count) {
for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) {
#if DEBUG_RAW_EVENTS
LOGD("Input event: device=%d type=0x%04x scancode=0x%04x "
- "keycode=0x%04x value=0x%04x flags=0x%08x",
+ "keycode=0x%04x value=0x%08x flags=0x%08x",
rawEvent->deviceId, rawEvent->type, rawEvent->scanCode, rawEvent->keyCode,
rawEvent->value, rawEvent->flags);
#endif
@@ -1921,8 +1922,17 @@ void TouchInputMapper::dump(String8& dump) {
dump.appendFormat(INDENT4 "DistanceScale: %0.3f\n", mLocked.distanceScale);
dump.appendFormat(INDENT3 "Last Touch:\n");
- dump.appendFormat(INDENT4 "Pointer Count: %d\n", mLastTouch.pointerCount);
dump.appendFormat(INDENT4 "Button State: 0x%08x\n", mLastTouch.buttonState);
+ dump.appendFormat(INDENT4 "Pointer Count: %d\n", mLastTouch.pointerCount);
+ for (uint32_t i = 0; i < mLastTouch.pointerCount; i++) {
+ const PointerData& pointer = mLastTouch.pointers[i];
+ dump.appendFormat(INDENT5 "[%d]: id=%d, x=%d, y=%d, pressure=%d, "
+ "touchMajor=%d, touchMinor=%d, toolMajor=%d, toolMinor=%d, "
+ "orientation=%d, distance=%d, isStylus=%s\n", i,
+ pointer.id, pointer.x, pointer.y, pointer.pressure,
+ pointer.touchMajor, pointer.touchMinor, pointer.toolMajor, pointer.toolMinor,
+ pointer.orientation, pointer.distance, toString(pointer.isStylus));
+ }
if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) {
dump.appendFormat(INDENT3 "Pointer Gesture Detector:\n");
@@ -3704,6 +3714,29 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag
mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex,
mPointerGesture.currentGestureIdBits, -1,
0, 0, mPointerGesture.downTime);
+ } else if (dispatchedGestureIdBits.isEmpty()
+ && !mPointerGesture.lastGestureIdBits.isEmpty()) {
+ // Synthesize a hover move event after all pointers go up to indicate that
+ // the pointer is hovering again even if the user is not currently touching
+ // the touch pad. This ensures that a view will receive a fresh hover enter
+ // event after a tap.
+ float x, y;
+ mPointerController->getPosition(&x, &y);
+
+ PointerProperties pointerProperties;
+ pointerProperties.clear();
+ pointerProperties.id = 0;
+ pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_INDIRECT_FINGER;
+
+ PointerCoords pointerCoords;
+ pointerCoords.clear();
+ pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
+ pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
+
+ getDispatcher()->notifyMotion(when, getDeviceId(), mPointerSource, policyFlags,
+ AMOTION_EVENT_ACTION_HOVER_MOVE, 0,
+ metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ 1, &pointerProperties, &pointerCoords, 0, 0, mPointerGesture.downTime);
}
// Update state.
@@ -5361,7 +5394,6 @@ void SingleTouchInputMapper::configureRawAxes() {
MultiTouchInputMapper::MultiTouchInputMapper(InputDevice* device) :
TouchInputMapper(device), mSlotCount(0), mUsingSlotsProtocol(false) {
- clearState();
}
MultiTouchInputMapper::~MultiTouchInputMapper() {
@@ -5371,6 +5403,24 @@ void MultiTouchInputMapper::clearState() {
mAccumulator.clearSlots(mSlotCount);
mAccumulator.clearButtons();
mButtonState = 0;
+
+ if (mUsingSlotsProtocol) {
+ // Query the driver for the current slot index and use it as the initial slot
+ // before we start reading events from the device. It is possible that the
+ // current slot index will not be the same as it was when the first event was
+ // written into the evdev buffer, which means the input mapper could start
+ // out of sync with the initial state of the events in the evdev buffer.
+ // In the extremely unlikely case that this happens, the data from
+ // two slots will be confused until the next ABS_MT_SLOT event is received.
+ // This can cause the touch point to "jump", but at least there will be
+ // no stuck touches.
+ status_t status = getEventHub()->getAbsoluteAxisValue(getDeviceId(), ABS_MT_SLOT,
+ &mAccumulator.currentSlot);
+ if (status) {
+ LOGW("Could not retrieve current multitouch slot index. status=%d", status);
+ mAccumulator.currentSlot = -1;
+ }
+ }
}
void MultiTouchInputMapper::reset() {
@@ -5649,6 +5699,8 @@ void MultiTouchInputMapper::configureRawAxes() {
}
mAccumulator.allocateSlots(mSlotCount);
+
+ clearState();
}
diff --git a/services/input/SpriteController.cpp b/services/input/SpriteController.cpp
index 08cc75e631eb..0ae2ab898d67 100644
--- a/services/input/SpriteController.cpp
+++ b/services/input/SpriteController.cpp
@@ -252,11 +252,7 @@ void SpriteController::doUpdateSprites() {
| DIRTY_VISIBILITY | DIRTY_HOTSPOT))))) {
status_t status;
if (!haveTransaction) {
- status = mSurfaceComposerClient->openTransaction();
- if (status) {
- LOGE("Error %d opening transation to update sprite surface.", status);
- break;
- }
+ SurfaceComposerClient::openGlobalTransaction();
haveTransaction = true;
}
@@ -322,10 +318,7 @@ void SpriteController::doUpdateSprites() {
}
if (haveTransaction) {
- status_t status = mSurfaceComposerClient->closeTransaction();
- if (status) {
- LOGE("Error %d closing transaction to update sprite surface.", status);
- }
+ SurfaceComposerClient::closeGlobalTransaction();
}
// If any surfaces were changed, write back the new surface properties to the sprites.
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index e349248b1c5a..d3c5ece7cbef 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -429,6 +429,7 @@ class FakeEventHub : public EventHubInterface {
KeyedVector<int32_t, int32_t> keyCodeStates;
KeyedVector<int32_t, int32_t> scanCodeStates;
KeyedVector<int32_t, int32_t> switchStates;
+ KeyedVector<int32_t, int32_t> absoluteAxisValue;
KeyedVector<int32_t, KeyInfo> keys;
KeyedVector<int32_t, bool> leds;
Vector<VirtualKeyDefinition> virtualKeys;
@@ -514,6 +515,11 @@ public:
device->switchStates.replaceValueFor(switchCode, state);
}
+ void setAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t value) {
+ Device* device = getDevice(deviceId);
+ device->absoluteAxisValue.replaceValueFor(axis, value);
+ }
+
void addKey(int32_t deviceId, int32_t scanCode, int32_t keyCode, uint32_t flags) {
Device* device = getDevice(deviceId);
KeyInfo info;
@@ -677,6 +683,20 @@ private:
return AKEY_STATE_UNKNOWN;
}
+ virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis,
+ int32_t* outValue) const {
+ Device* device = getDevice(deviceId);
+ if (device) {
+ ssize_t index = device->absoluteAxisValue.indexOfKey(axis);
+ if (index >= 0) {
+ *outValue = device->absoluteAxisValue.valueAt(index);
+ return OK;
+ }
+ }
+ *outValue = 0;
+ return -1;
+ }
+
virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes,
uint8_t* outFlags) const {
bool result = false;
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 8fb6274a7afb..663f4f47f56e 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -2533,7 +2533,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private VpnCallback() {
}
- public synchronized void override(String[] dnsServers) {
+ public synchronized void override(List<String> dnsServers, List<String> searchDomains) {
// TODO: override DNS servers and http proxy.
}
diff --git a/services/java/com/android/server/DnsPinger.java b/services/java/com/android/server/DnsPinger.java
index 05de53a2810c..4e33938b2ca8 100644
--- a/services/java/com/android/server/DnsPinger.java
+++ b/services/java/com/android/server/DnsPinger.java
@@ -16,16 +16,18 @@
package com.android.server;
-import android.content.ContentResolver;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
+import android.net.NetworkUtils;
import android.os.SystemClock;
+import android.provider.Settings;
import android.util.Slog;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
+import java.net.NetworkInterface;
import java.net.SocketTimeoutException;
import java.util.Collection;
import java.util.Random;
@@ -38,7 +40,7 @@ import java.util.Random;
* API may not differentiate between a time out and a failure lookup (which we
* really care about).
* <p>
- * TODO : More general API. Socket does not bind to specified connection type
+ * TODO : More general API. Socket does not bind to specified connection type
* TODO : Choice of DNS query location - current looks up www.android.com
*
* @hide
@@ -47,7 +49,7 @@ public final class DnsPinger {
private static final boolean V = true;
/** Number of bytes for the query */
- private static final int DNS_QUERY_BASE_SIZE = 33;
+ private static final int DNS_QUERY_BASE_SIZE = 32;
/** The DNS port */
private static final int DNS_PORT = 53;
@@ -56,46 +58,71 @@ public final class DnsPinger {
private static Random sRandom = new Random();
private ConnectivityManager mConnectivityManager = null;
- private ContentResolver mContentResolver;
private Context mContext;
private int mConnectionType;
+ private InetAddress mDefaultDns;
private String TAG;
-
/**
- * @param connectionType The connection type from @link {@link ConnectivityManager}
+ * @param connectionType The connection type from {@link ConnectivityManager}
*/
public DnsPinger(String TAG, Context context, int connectionType) {
mContext = context;
- mContentResolver = context.getContentResolver();
mConnectionType = connectionType;
+ if (!ConnectivityManager.isNetworkTypeValid(connectionType)) {
+ Slog.e(TAG, "Invalid connectionType in constructor: " + connectionType);
+ }
this.TAG = TAG;
+
+ mDefaultDns = getDefaultDns();
}
/**
- * @return The first DNS in the link properties of the specified connection type
+ * @return The first DNS in the link properties of the specified connection
+ * type or the default system DNS if the link properties has null
+ * dns set. Should not be null.
*/
public InetAddress getDns() {
- LinkProperties linkProperties = getCurLinkProperties();
- if (linkProperties == null)
- return null;
+ LinkProperties curLinkProps = getCurrentLinkProperties();
+ if (curLinkProps == null) {
+ Slog.e(TAG, "getCurLinkProperties:: LP for type" + mConnectionType + " is null!");
+ return mDefaultDns;
+ }
- Collection<InetAddress> dnses = linkProperties.getDnses();
- if (dnses == null || dnses.size() == 0)
- return null;
+ Collection<InetAddress> dnses = curLinkProps.getDnses();
+ if (dnses == null || dnses.size() == 0) {
+ Slog.v(TAG, "getDns::LinkProps has null dns - returning default");
+ return mDefaultDns;
+ }
return dnses.iterator().next();
}
- private LinkProperties getCurLinkProperties() {
+ private LinkProperties getCurrentLinkProperties() {
if (mConnectivityManager == null) {
mConnectivityManager = (ConnectivityManager) mContext.getSystemService(
Context.CONNECTIVITY_SERVICE);
}
+
return mConnectivityManager.getLinkProperties(mConnectionType);
}
+ private InetAddress getDefaultDns() {
+ String dns = Settings.Secure.getString(mContext.getContentResolver(),
+ Settings.Secure.DEFAULT_DNS_SERVER);
+ if (dns == null || dns.length() == 0) {
+ dns = mContext.getResources().getString(
+ com.android.internal.R.string.config_default_dns_server);
+ }
+ try {
+ return NetworkUtils.numericToInetAddress(dns);
+ } catch (IllegalArgumentException e) {
+ Slog.w(TAG, "getDefaultDns::malformed default dns address");
+ return null;
+ }
+ }
+
/**
* @return time to response. Negative value on error.
*/
@@ -107,8 +134,15 @@ public final class DnsPinger {
// Set some socket properties
socket.setSoTimeout(timeout);
- byte[] buf = new byte[DNS_QUERY_BASE_SIZE];
- fillQuery(buf);
+ // Try to bind but continue ping if bind fails
+ try {
+ socket.setNetworkInterface(NetworkInterface.getByName(
+ getCurrentLinkProperties().getInterfaceName()));
+ } catch (Exception e) {
+ Slog.d(TAG,"pingDns::Error binding to socket", e);
+ }
+
+ byte[] buf = constructQuery();
// Send the DNS query
@@ -141,48 +175,47 @@ public final class DnsPinger {
}
- private static void fillQuery(byte[] buf) {
-
- /*
- * See RFC2929 (though the bit tables in there are misleading for us.
- * For example, the recursion desired bit is the 0th bit for us, but
- * looking there it would appear as the 7th bit of the byte
- */
-
- // Make sure it's all zeroed out
- for (int i = 0; i < buf.length; i++)
- buf[i] = 0;
-
- // Form a query for www.android.com
+ /**
+ * @return google.com DNS query packet
+ */
+ private static byte[] constructQuery() {
+ byte[] buf = new byte[DNS_QUERY_BASE_SIZE];
// [0-1] bytes are an ID, generate random ID for this query
buf[0] = (byte) sRandom.nextInt(256);
buf[1] = (byte) sRandom.nextInt(256);
// [2-3] bytes are for flags.
- buf[2] = 1; // Recursion desired
+ buf[2] = 0x01; // Recursion desired
- // [4-5] bytes are for the query count
- buf[5] = 1; // One query
+ // [4-5] bytes are for number of queries (QCOUNT)
+ buf[5] = 0x01;
// [6-7] [8-9] [10-11] are all counts of other fields we don't use
// [12-15] for www
writeString(buf, 12, "www");
- // [16-23] for android
- writeString(buf, 16, "android");
+ // [16-22] for google
+ writeString(buf, 16, "google");
+
+ // [23-26] for com
+ writeString(buf, 23, "com");
- // [24-27] for com
- writeString(buf, 24, "com");
+ // [27] is a null byte terminator byte for the url
- // [29-30] bytes are for QTYPE, set to 1
- buf[30] = 1;
+ // [28-29] bytes are for QTYPE, set to 1 = A (host address)
+ buf[29] = 0x01;
- // [31-32] bytes are for QCLASS, set to 1
- buf[32] = 1;
+ // [30-31] bytes are for QCLASS, set to 1 = IN (internet)
+ buf[31] = 0x01;
+
+ return buf;
}
+ /**
+ * Writes the string's length and its contents to the buffer
+ */
private static void writeString(byte[] buf, int startPos, String string) {
int pos = startPos;
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index b03bd4d28df0..14abf808b71f 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -1641,7 +1641,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
final InputMethodInfo imi = mMethodMap.get(mCurMethodId);
if (imi == null) return false;
final int N = subtypes.length;
- mFileManager.addInputMethodSubtypes(mCurMethodId, subtypes);
+ mFileManager.addInputMethodSubtypes(imi, subtypes);
buildInputMethodListLocked(mMethodList, mMethodMap);
return true;
}
@@ -2023,25 +2023,26 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
final CharSequence label = imi.loadLabel(pm);
if (showSubtypes && enabledSubtypeSet.size() > 0) {
final int subtypeCount = imi.getSubtypeCount();
+ if (DEBUG) {
+ Slog.v(TAG, "Add subtypes: " + subtypeCount + ", " + imi.getId());
+ }
for (int j = 0; j < subtypeCount; ++j) {
- InputMethodSubtype subtype = imi.getSubtypeAt(j);
- if (enabledSubtypeSet.contains(String.valueOf(subtype.hashCode()))
- && !subtype.isAuxiliary()) {
+ final InputMethodSubtype subtype = imi.getSubtypeAt(j);
+ final String subtypeHashCode = String.valueOf(subtype.hashCode());
+ // We show all enabled IMEs and subtypes when an IME is shown.
+ if (enabledSubtypeSet.contains(subtypeHashCode)
+ && (mInputShown || !subtype.isAuxiliary())) {
final CharSequence title;
- int nameResId = subtype.getNameResId();
- String mode = subtype.getMode();
- if (nameResId != 0) {
- title = TextUtils.concat(subtype.getDisplayName(context,
- imi.getPackageName(), imi.getServiceInfo().applicationInfo),
- (TextUtils.isEmpty(label) ? "" : " (" + label + ")"));
- } else {
- CharSequence language = subtype.getLocale();
- // TODO: Use more friendly Title and UI
- title = label + "," + (mode == null ? "" : mode) + ","
- + (language == null ? "" : language);
- }
+ final String mode = subtype.getMode();
+ title = TextUtils.concat(subtype.getDisplayName(context,
+ imi.getPackageName(), imi.getServiceInfo().applicationInfo),
+ (TextUtils.isEmpty(label) ? "" : " (" + label + ")"));
imList.add(new Pair<CharSequence, Pair<InputMethodInfo, Integer>>(
title, new Pair<InputMethodInfo, Integer>(imi, j)));
+ // Removing this subtype from enabledSubtypeSet because we no longer
+ // need to add an entry of this subtype to imList to avoid duplicated
+ // entries.
+ enabledSubtypeSet.remove(subtypeHashCode);
}
}
} else {
@@ -2338,7 +2339,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
}
- ArrayList<InputMethodSubtype> applicableSubtypes = new ArrayList<InputMethodSubtype>(
+ final ArrayList<InputMethodSubtype> applicableSubtypes = new ArrayList<InputMethodSubtype>(
applicableModeAndSubtypesMap.values());
if (!containsKeyboardSubtype) {
InputMethodSubtype lastResortKeyboardSubtype = findLastResortApplicableSubtypeLocked(
@@ -3016,17 +3017,23 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
public void addInputMethodSubtypes(
- String imiId, InputMethodSubtype[] additionalSubtypes) {
+ InputMethodInfo imi, InputMethodSubtype[] additionalSubtypes) {
synchronized (mMethodMap) {
+ final HashSet<InputMethodSubtype> existingSubtypes =
+ new HashSet<InputMethodSubtype>();
+ for (int i = 0; i < imi.getSubtypeCount(); ++i) {
+ existingSubtypes.add(imi.getSubtypeAt(i));
+ }
+
final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
final int N = additionalSubtypes.length;
for (int i = 0; i < N; ++i) {
final InputMethodSubtype subtype = additionalSubtypes[i];
- if (!subtypes.contains(subtype)) {
+ if (!subtypes.contains(subtype) && !existingSubtypes.contains(subtype)) {
subtypes.add(subtype);
}
}
- mSubtypesMap.put(imiId, subtypes);
+ mSubtypesMap.put(imi.getId(), subtypes);
writeAdditionalInputMethodSubtypes(mSubtypesMap, mAdditionalInputMethodSubtypeFile,
mMethodMap);
}
@@ -3133,8 +3140,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
parser.getAttributeValue(null, ATTR_IME_SUBTYPE_MODE);
final String imeSubtypeExtraValue =
parser.getAttributeValue(null, ATTR_IME_SUBTYPE_EXTRA_VALUE);
- final boolean isAuxiliary =
- Boolean.valueOf(parser.getAttributeValue(null, ATTR_IS_AUXILIARY));
+ final boolean isAuxiliary = "1".equals(String.valueOf(
+ parser.getAttributeValue(null, ATTR_IS_AUXILIARY)));
final InputMethodSubtype subtype =
new InputMethodSubtype(label, icon, imeSubtypeLocale,
imeSubtypeMode, imeSubtypeExtraValue, isAuxiliary);
diff --git a/services/java/com/android/server/IntentResolver.java b/services/java/com/android/server/IntentResolver.java
index 1d3e3ac23c8b..b3d72200909c 100644
--- a/services/java/com/android/server/IntentResolver.java
+++ b/services/java/com/android/server/IntentResolver.java
@@ -41,7 +41,7 @@ import android.content.IntentFilter;
/**
* {@hide}
*/
-public class IntentResolver<F extends IntentFilter, R extends Object> {
+public abstract class IntentResolver<F extends IntentFilter, R extends Object> {
final private static String TAG = "IntentResolver";
final private static boolean DEBUG = false;
final private static boolean localLOGV = DEBUG || false;
@@ -333,14 +333,19 @@ public class IntentResolver<F extends IntentFilter, R extends Object> {
return false;
}
- protected String packageForFilter(F filter) {
- return null;
- }
+ /**
+ * Return the package that owns this filter. This must be implemented to
+ * provide correct filtering of Intents that have specified a package name
+ * they are to be delivered to.
+ */
+ protected abstract String packageForFilter(F filter);
+ @SuppressWarnings("unchecked")
protected R newResult(F filter, int match) {
return (R)filter;
}
+ @SuppressWarnings("unchecked")
protected void sortResults(List<R> results) {
Collections.sort(results, mResolvePrioritySorter);
}
@@ -502,6 +507,7 @@ public class IntentResolver<F extends IntentFilter, R extends Object> {
String resolvedType, String scheme, List<F> src, List<R> dest) {
final String action = intent.getAction();
final Uri data = intent.getData();
+ final String packageName = intent.getPackage();
final boolean excludingStopped = intent.isExcludingStopped();
@@ -520,6 +526,14 @@ public class IntentResolver<F extends IntentFilter, R extends Object> {
continue;
}
+ // Is delivery being limited to filters owned by a particular package?
+ if (packageName != null && !packageName.equals(packageForFilter(filter))) {
+ if (debug) {
+ Slog.v(TAG, " Filter is not from package " + packageName + "; skipping");
+ }
+ continue;
+ }
+
// Do we already have this one?
if (!allowFilterResult(filter, dest)) {
if (debug) {
@@ -561,6 +575,7 @@ public class IntentResolver<F extends IntentFilter, R extends Object> {
}
// Sorts a List of IntentFilter objects into descending priority order.
+ @SuppressWarnings("rawtypes")
private static final Comparator mResolvePrioritySorter = new Comparator() {
public int compare(Object o1, Object o2) {
final int q1 = ((IntentFilter) o1).getPriority();
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 656ec4d266dd..56afe7f51414 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -195,6 +195,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
final Object mKey;
final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
int mPendingBroadcasts;
+ String requiredPermissions;
Receiver(ILocationListener listener) {
mListener = listener;
@@ -284,7 +285,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
synchronized (this) {
// synchronize to ensure incrementPendingBroadcastsLocked()
// is called before decrementPendingBroadcasts()
- mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler);
+ mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
+ requiredPermissions);
// call this after broadcasting so we do not increment
// if we throw an exeption.
incrementPendingBroadcastsLocked();
@@ -319,7 +321,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
synchronized (this) {
// synchronize to ensure incrementPendingBroadcastsLocked()
// is called before decrementPendingBroadcasts()
- mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler);
+ mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
+ requiredPermissions);
// call this after broadcasting so we do not increment
// if we throw an exeption.
incrementPendingBroadcastsLocked();
@@ -358,7 +361,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
synchronized (this) {
// synchronize to ensure incrementPendingBroadcastsLocked()
// is called before decrementPendingBroadcasts()
- mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler);
+ mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
+ requiredPermissions);
// call this after broadcasting so we do not increment
// if we throw an exeption.
incrementPendingBroadcastsLocked();
@@ -572,22 +576,30 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
return Settings.Secure.isLocationProviderEnabled(resolver, provider);
}
- private void checkPermissionsSafe(String provider) {
- if ((LocationManager.GPS_PROVIDER.equals(provider)
- || LocationManager.PASSIVE_PROVIDER.equals(provider))
- && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
- != PackageManager.PERMISSION_GRANTED)) {
- throw new SecurityException("Provider " + provider
- + " requires ACCESS_FINE_LOCATION permission");
+ private String checkPermissionsSafe(String provider, String lastPermission) {
+ if (LocationManager.GPS_PROVIDER.equals(provider)
+ || LocationManager.PASSIVE_PROVIDER.equals(provider)) {
+ if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Provider " + provider
+ + " requires ACCESS_FINE_LOCATION permission");
+ }
+ return ACCESS_FINE_LOCATION;
}
- if (LocationManager.NETWORK_PROVIDER.equals(provider)
- && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
- != PackageManager.PERMISSION_GRANTED)
- && (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
- != PackageManager.PERMISSION_GRANTED)) {
- throw new SecurityException("Provider " + provider
- + " requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission");
+
+ // Assume any other provider requires the coarse or fine permission.
+ if (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
+ == PackageManager.PERMISSION_GRANTED) {
+ return ACCESS_FINE_LOCATION.equals(lastPermission)
+ ? lastPermission : ACCESS_COARSE_LOCATION;
}
+ if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
+ == PackageManager.PERMISSION_GRANTED) {
+ return ACCESS_FINE_LOCATION;
+ }
+
+ throw new SecurityException("Provider " + provider
+ + " requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission");
}
private boolean isAllowedProviderSafe(String provider) {
@@ -1099,8 +1111,21 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
}
+ void validatePendingIntent(PendingIntent intent) {
+ if (intent.isTargetedToPackage()) {
+ return;
+ }
+ Slog.i(TAG, "Given Intent does not require a specific package: "
+ + intent);
+ // XXX we should really throw a security exception, if the caller's
+ // targetSdkVersion is high enough.
+ //throw new SecurityException("Given Intent does not require a specific package: "
+ // + intent);
+ }
+
public void requestLocationUpdatesPI(String provider, Criteria criteria,
long minTime, float minDistance, boolean singleShot, PendingIntent intent) {
+ validatePendingIntent(intent);
if (criteria != null) {
// FIXME - should we consider using multiple providers simultaneously
// rather than only the best one?
@@ -1132,7 +1157,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
throw new IllegalArgumentException("provider=" + provider);
}
- checkPermissionsSafe(provider);
+ receiver.requiredPermissions = checkPermissionsSafe(provider,
+ receiver.requiredPermissions);
// so wakelock calls will succeed
final int callingUid = Binder.getCallingUid();
@@ -1300,7 +1326,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
// first check for permission to the provider
- checkPermissionsSafe(provider);
+ checkPermissionsSafe(provider, null);
// and check for ACCESS_LOCATION_EXTRA_COMMANDS
if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
!= PackageManager.PERMISSION_GRANTED)) {
@@ -1432,7 +1458,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
synchronized (this) {
// synchronize to ensure incrementPendingBroadcasts()
// is called before decrementPendingBroadcasts()
- intent.send(mContext, 0, enteredIntent, this, mLocationHandler);
+ intent.send(mContext, 0, enteredIntent, this, mLocationHandler,
+ ACCESS_FINE_LOCATION);
// call this after broadcasting so we do not increment
// if we throw an exeption.
incrementPendingBroadcasts();
@@ -1457,7 +1484,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
synchronized (this) {
// synchronize to ensure incrementPendingBroadcasts()
// is called before decrementPendingBroadcasts()
- intent.send(mContext, 0, exitedIntent, this, mLocationHandler);
+ intent.send(mContext, 0, exitedIntent, this, mLocationHandler,
+ ACCESS_FINE_LOCATION);
// call this after broadcasting so we do not increment
// if we throw an exeption.
incrementPendingBroadcasts();
@@ -1526,6 +1554,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
public void addProximityAlert(double latitude, double longitude,
float radius, long expiration, PendingIntent intent) {
+ validatePendingIntent(intent);
try {
synchronized (mLock) {
addProximityAlertLocked(latitude, longitude, radius, expiration, intent);
@@ -1626,7 +1655,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
return null;
}
- checkPermissionsSafe(provider);
+ checkPermissionsSafe(provider, null);
Bundle b = new Bundle();
b.putBoolean("network", p.requiresNetwork());
@@ -1668,7 +1697,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
private boolean _isProviderEnabledLocked(String provider) {
- checkPermissionsSafe(provider);
+ checkPermissionsSafe(provider, null);
LocationProviderInterface p = mProvidersByName.get(provider);
if (p == null) {
@@ -1694,7 +1723,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run
}
private Location _getLastKnownLocationLocked(String provider) {
- checkPermissionsSafe(provider);
+ checkPermissionsSafe(provider, null);
LocationProviderInterface p = mProvidersByName.get(provider);
if (p == null) {
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index d3244ecc376b..54e54327f8f7 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -1626,6 +1626,30 @@ class MountService extends IMountService.Stub implements INativeDaemonConnectorC
}
}
+ public String getSecureContainerFilesystemPath(String id) {
+ validatePermission(android.Manifest.permission.ASEC_ACCESS);
+ waitForReady();
+ warnOnNotMounted();
+
+ try {
+ ArrayList<String> rsp = mConnector.doCommand(String.format("asec fspath %s", id));
+ String []tok = rsp.get(0).split(" ");
+ int code = Integer.parseInt(tok[0]);
+ if (code != VoldResponseCode.AsecPathResult) {
+ throw new IllegalStateException(String.format("Unexpected response code %d", code));
+ }
+ return tok[1];
+ } catch (NativeDaemonConnectorException e) {
+ int code = e.getCode();
+ if (code == VoldResponseCode.OpFailedStorageNotFound) {
+ Slog.i(TAG, String.format("Container '%s' not found", id));
+ return null;
+ } else {
+ throw new IllegalStateException(String.format("Unexpected response code %d", code));
+ }
+ }
+ }
+
public void finishMediaUpdate() {
mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE);
}
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 630aaf9edafe..1c150f8a65ea 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -16,10 +16,11 @@
package com.android.server;
+import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
import static android.net.NetworkStats.IFACE_ALL;
import static android.net.NetworkStats.TAG_NONE;
import static android.net.NetworkStats.UID_ALL;
-import static android.Manifest.permission.MANAGE_NETWORK_POLICY;
+import static android.provider.Settings.Secure.NETSTATS_ENABLED;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -35,13 +36,14 @@ import android.os.Binder;
import android.os.INetworkManagementService;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.provider.Settings;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseBooleanArray;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
-
-import dalvik.system.BlockGuard;
+import com.google.android.collect.Sets;
import java.io.BufferedReader;
import java.io.DataInputStream;
@@ -54,6 +56,7 @@ import java.net.Inet4Address;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import java.util.concurrent.CountDownLatch;
@@ -117,6 +120,13 @@ class NetworkManagementService extends INetworkManagementService.Stub {
private ArrayList<INetworkManagementEventObserver> mObservers;
+ /** Set of interfaces with active quotas. */
+ private HashSet<String> mInterfaceQuota = Sets.newHashSet();
+ /** Set of UIDs with active reject rules. */
+ private SparseBooleanArray mUidRejectOnQuota = new SparseBooleanArray();
+
+ private boolean mBandwidthControlEnabled;
+
/**
* Constructs a new NetworkManagementService instance
*
@@ -155,6 +165,29 @@ class NetworkManagementService extends INetworkManagementService.Stub {
return new NetworkManagementService(context, procRoot);
}
+ public void systemReady() {
+
+ // only enable bandwidth control when support exists, and requested by
+ // system setting.
+ // TODO: eventually migrate to be always enabled
+ final boolean hasKernelSupport = new File("/proc/net/xt_qtaguid/ctrl").exists();
+ final boolean shouldEnable =
+ Settings.Secure.getInt(mContext.getContentResolver(), NETSTATS_ENABLED, 0) != 0;
+
+ mBandwidthControlEnabled = false;
+ if (hasKernelSupport && shouldEnable) {
+ Slog.d(TAG, "enabling bandwidth control");
+ try {
+ mConnector.doCommand("bandwidth enable");
+ mBandwidthControlEnabled = true;
+ } catch (NativeDaemonConnectorException e) {
+ Slog.e(TAG, "problem enabling bandwidth controls", e);
+ }
+ } else {
+ Slog.d(TAG, "not enabling bandwidth control");
+ }
+ }
+
public void registerObserver(INetworkManagementEventObserver obs) {
Slog.d(TAG, "Registering observer");
mObservers.add(obs);
@@ -913,7 +946,7 @@ class NetworkManagementService extends INetworkManagementService.Stub {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
- if (mProcStatsNetfilter.exists()) {
+ if (mBandwidthControlEnabled) {
return getNetworkStatsDetailNetfilter(UID_ALL);
} else {
return getNetworkStatsDetailUidstat(UID_ALL);
@@ -921,13 +954,103 @@ class NetworkManagementService extends INetworkManagementService.Stub {
}
@Override
+ public void setInterfaceQuota(String iface, long quota) {
+ mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+
+ // silently discard when control disabled
+ // TODO: eventually migrate to be always enabled
+ if (!mBandwidthControlEnabled) return;
+
+ synchronized (mInterfaceQuota) {
+ if (mInterfaceQuota.contains(iface)) {
+ // TODO: eventually consider throwing
+ return;
+ }
+
+ final StringBuilder command = new StringBuilder();
+ command.append("bandwidth setiquota ").append(iface).append(" ").append(quota);
+
+ try {
+ // TODO: add support for quota shared across interfaces
+ mConnector.doCommand(command.toString());
+ mInterfaceQuota.add(iface);
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException("Error communicating to native daemon", e);
+ }
+ }
+ }
+
+ @Override
+ public void removeInterfaceQuota(String iface) {
+ mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+
+ // silently discard when control disabled
+ // TODO: eventually migrate to be always enabled
+ if (!mBandwidthControlEnabled) return;
+
+ synchronized (mInterfaceQuota) {
+ if (!mInterfaceQuota.contains(iface)) {
+ // TODO: eventually consider throwing
+ return;
+ }
+
+ final StringBuilder command = new StringBuilder();
+ command.append("bandwidth removeiquota ").append(iface);
+
+ try {
+ // TODO: add support for quota shared across interfaces
+ mConnector.doCommand(command.toString());
+ mInterfaceQuota.remove(iface);
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException("Error communicating to native daemon", e);
+ }
+ }
+ }
+
+ @Override
+ public void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
+ mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
+
+ // silently discard when control disabled
+ // TODO: eventually migrate to be always enabled
+ if (!mBandwidthControlEnabled) return;
+
+ synchronized (mUidRejectOnQuota) {
+ final boolean oldRejectOnQuota = mUidRejectOnQuota.get(uid, false);
+ if (oldRejectOnQuota == rejectOnQuotaInterfaces) {
+ // TODO: eventually consider throwing
+ return;
+ }
+
+ final StringBuilder command = new StringBuilder();
+ command.append("bandwidth");
+ if (rejectOnQuotaInterfaces) {
+ command.append(" addnaughtyapps");
+ } else {
+ command.append(" removenaughtyapps");
+ }
+ command.append(" ").append(uid);
+
+ try {
+ mConnector.doCommand(command.toString());
+ if (rejectOnQuotaInterfaces) {
+ mUidRejectOnQuota.put(uid, true);
+ } else {
+ mUidRejectOnQuota.delete(uid);
+ }
+ } catch (NativeDaemonConnectorException e) {
+ throw new IllegalStateException("Error communicating to native daemon", e);
+ }
+ }
+ }
+
public NetworkStats getNetworkStatsUidDetail(int uid) {
if (Binder.getCallingUid() != uid) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
}
- if (mProcStatsNetfilter.exists()) {
+ if (mBandwidthControlEnabled) {
return getNetworkStatsDetailNetfilter(uid);
} else {
return getNetworkStatsDetailUidstat(uid);
@@ -958,7 +1081,8 @@ class NetworkManagementService extends INetworkManagementService.Stub {
try {
final String iface = parsed.get(KEY_IFACE);
- final int tag = BlockGuard.kernelToTag(parsed.get(KEY_TAG_HEX));
+ final int tag = NetworkManagementSocketTagger.kernelToTag(
+ parsed.get(KEY_TAG_HEX));
final int uid = Integer.parseInt(parsed.get(KEY_UID));
final long rx = Long.parseLong(parsed.get(KEY_RX));
final long tx = Long.parseLong(parsed.get(KEY_TX));
@@ -1066,12 +1190,6 @@ class NetworkManagementService extends INetworkManagementService.Stub {
return getInterfaceThrottle(iface, false);
}
- @Override
- public void setBandwidthControlEnabled(boolean enabled) {
- mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
- mConnector.doCommand(String.format("bandwidth %s", (enabled ? "enable" : "disable")));
- }
-
/**
* Split given line into {@link ArrayList}.
*/
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index cd68c6854153..8c7e279b7132 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -283,7 +283,8 @@ class ServerThread extends Thread {
try {
Slog.i(TAG, "NetworkPolicy Service");
networkPolicy = new NetworkPolicyManagerService(
- context, ActivityManagerService.self(), power, networkStats);
+ context, ActivityManagerService.self(), power,
+ networkStats, networkManagement);
ServiceManager.addService(Context.NETWORK_POLICY_SERVICE, networkPolicy);
} catch (Throwable e) {
Slog.e(TAG, "Failure starting NetworkPolicy Service", e);
@@ -522,6 +523,7 @@ class ServerThread extends Thread {
// These are needed to propagate to the runnable below.
final Context contextF = context;
final BatteryService batteryF = battery;
+ final NetworkManagementService networkManagementF = networkManagement;
final NetworkStatsService networkStatsF = networkStats;
final NetworkPolicyManagerService networkPolicyF = networkPolicy;
final ConnectivityService connectivityF = connectivity;
@@ -549,6 +551,7 @@ class ServerThread extends Thread {
startSystemUi(contextF);
if (batteryF != null) batteryF.systemReady();
+ if (networkManagementF != null) networkManagementF.systemReady();
if (networkStatsF != null) networkStatsF.systemReady();
if (networkPolicyF != null) networkPolicyF.systemReady();
if (connectivityF != null) connectivityF.systemReady();
diff --git a/services/java/com/android/server/WifiWatchdogService.java b/services/java/com/android/server/WifiWatchdogService.java
index 3ba9c14cf4d7..1356e2a9b23f 100644
--- a/services/java/com/android/server/WifiWatchdogService.java
+++ b/services/java/com/android/server/WifiWatchdogService.java
@@ -95,14 +95,14 @@ public class WifiWatchdogService {
private static final long MIN_SINGLE_DNS_CHECK_INTERVAL = 10 * 60 * 1000;
private static final long MIN_WALLED_GARDEN_INTERVAL = 15 * 60 * 1000;
- private static final int MAX_CHECKS_PER_SSID = 7;
- private static final int NUM_DNS_PINGS = 5;
+ private static final int MAX_CHECKS_PER_SSID = 9;
+ private static final int NUM_DNS_PINGS = 7;
private static double MIN_RESPONSE_RATE = 0.50;
// TODO : Adjust multiple DNS downward to 250 on repeated failure
// private static final int MULTI_DNS_PING_TIMEOUT_MS = 250;
- private static final int DNS_PING_TIMEOUT_MS = 1000;
+ private static final int DNS_PING_TIMEOUT_MS = 800;
private static final long DNS_PING_INTERVAL = 250;
private static final long BLACKLIST_FOLLOWUP_INTERVAL = 15 * 1000;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 4ec71c180e87..bf877f6e9d20 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -622,6 +622,11 @@ public final class ActivityManagerService extends ActivityManagerNative
}
return true;
}
+
+ @Override
+ protected String packageForFilter(BroadcastFilter filter) {
+ return filter.packageName;
+ }
};
/**
@@ -1825,6 +1830,8 @@ public final class ActivityManagerService extends ActivityManagerNative
// We already have the app running, or are waiting for it to
// come up (we have a pid but not yet its thread), so keep it.
if (DEBUG_PROCESSES) Slog.v(TAG, "App already running: " + app);
+ // If this is a new package in the process, add the package to the list
+ app.addPackage(info.packageName);
return app;
} else {
// An application record is attached to a previous process,
@@ -2278,7 +2285,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- return pir.sendInner(0, fillInIntent, resolvedType,
+ return pir.sendInner(0, fillInIntent, resolvedType, null,
null, resultTo, resultWho, requestCode, flagsMask, flagsValues);
}
@@ -4162,6 +4169,27 @@ public final class ActivityManagerService extends ActivityManagerNative
return null;
}
+ public boolean isIntentSenderTargetedToPackage(IIntentSender pendingResult) {
+ if (!(pendingResult instanceof PendingIntentRecord)) {
+ return false;
+ }
+ try {
+ PendingIntentRecord res = (PendingIntentRecord)pendingResult;
+ if (res.key.allIntents == null) {
+ return false;
+ }
+ for (int i=0; i<res.key.allIntents.length; i++) {
+ Intent intent = res.key.allIntents[i];
+ if (intent.getPackage() != null && intent.getComponent() != null) {
+ return false;
+ }
+ }
+ return true;
+ } catch (ClassCastException e) {
+ }
+ return false;
+ }
+
public void setProcessLimit(int max) {
enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
"setProcessLimit()");
@@ -9895,6 +9923,7 @@ public final class ActivityManagerService extends ActivityManagerNative
ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
if (app != null && app.thread != null) {
try {
+ app.addPackage(r.appInfo.packageName);
realStartServiceLocked(r, app);
return true;
} catch (RemoteException e) {
@@ -10945,7 +10974,7 @@ public final class ActivityManagerService extends ActivityManagerNative
mBroadcastsScheduled = true;
}
- public Intent registerReceiver(IApplicationThread caller,
+ public Intent registerReceiver(IApplicationThread caller, String callerPackage,
IIntentReceiver receiver, IntentFilter filter, String permission) {
synchronized(this) {
ProcessRecord callerApp = null;
@@ -10957,6 +10986,13 @@ public final class ActivityManagerService extends ActivityManagerNative
+ " (pid=" + Binder.getCallingPid()
+ ") when registering receiver " + receiver);
}
+ if (callerApp.info.uid != Process.SYSTEM_UID &&
+ !callerApp.pkgList.contains(callerPackage)) {
+ throw new SecurityException("Given caller package " + callerPackage
+ + " is not running in process " + callerApp);
+ }
+ } else {
+ callerPackage = null;
}
List allSticky = null;
@@ -11001,7 +11037,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
mRegisteredReceivers.put(receiver.asBinder(), rl);
}
- BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
+ BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, permission);
rl.add(bf);
if (!bf.debugCheck()) {
Slog.w(TAG, "==> For Dynamic broadast");
@@ -12155,6 +12191,7 @@ public final class ActivityManagerService extends ActivityManagerNative
info.activityInfo.applicationInfo.uid);
if (app != null && app.thread != null) {
try {
+ app.addPackage(info.activityInfo.packageName);
processCurBroadcastLocked(r, app);
return;
} catch (RemoteException e) {
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index b94ee587793c..b1da69f90326 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -652,6 +652,7 @@ final class ActivityStack {
if (app != null && app.thread != null) {
try {
+ app.addPackage(r.info.packageName);
realStartActivityLocked(r, app, andResume, checkConfig);
return;
} catch (RemoteException e) {
diff --git a/services/java/com/android/server/am/BroadcastFilter.java b/services/java/com/android/server/am/BroadcastFilter.java
index 2e784d30caa7..b49bc220ac03 100644
--- a/services/java/com/android/server/am/BroadcastFilter.java
+++ b/services/java/com/android/server/am/BroadcastFilter.java
@@ -25,12 +25,14 @@ import java.io.PrintWriter;
class BroadcastFilter extends IntentFilter {
// Back-pointer to the list this filter is in.
final ReceiverList receiverList;
+ final String packageName;
final String requiredPermission;
BroadcastFilter(IntentFilter _filter, ReceiverList _receiverList,
- String _requiredPermission) {
+ String _packageName, String _requiredPermission) {
super(_filter);
receiverList = _receiverList;
+ packageName = _packageName;
requiredPermission = _requiredPermission;
}
diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/java/com/android/server/am/PendingIntentRecord.java
index ee6e4204af39..8ed0cc11abd8 100644
--- a/services/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/java/com/android/server/am/PendingIntentRecord.java
@@ -177,13 +177,13 @@ class PendingIntentRecord extends IIntentSender.Stub {
}
public int send(int code, Intent intent, String resolvedType,
- IIntentReceiver finishedReceiver) {
+ IIntentReceiver finishedReceiver, String requiredPermission) {
return sendInner(code, intent, resolvedType, finishedReceiver,
- null, null, 0, 0, 0);
+ requiredPermission, null, null, 0, 0, 0);
}
int sendInner(int code, Intent intent, String resolvedType,
- IIntentReceiver finishedReceiver,
+ IIntentReceiver finishedReceiver, String requiredPermission,
IBinder resultTo, String resultWho, int requestCode,
int flagsMask, int flagsValues) {
synchronized(owner) {
@@ -246,8 +246,8 @@ class PendingIntentRecord extends IIntentSender.Stub {
// that the broadcast be delivered synchronously
owner.broadcastIntentInPackage(key.packageName, uid,
finalIntent, resolvedType,
- finishedReceiver, code, null, null, null,
- (finishedReceiver != null), false);
+ finishedReceiver, code, null, null,
+ requiredPermission, (finishedReceiver != null), false);
sendFinish = false;
} catch (RuntimeException e) {
Slog.w(ActivityManagerService.TAG,
diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java
index db3b61e5cb17..a8be916427f3 100644
--- a/services/java/com/android/server/connectivity/Vpn.java
+++ b/services/java/com/android/server/connectivity/Vpn.java
@@ -27,15 +27,23 @@ import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.net.INetworkManagementEventObserver;
+import android.net.LocalSocket;
+import android.net.LocalSocketAddress;
import android.os.Binder;
import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
+import android.os.Process;
+import android.os.SystemClock;
+import android.os.SystemProperties;
import android.util.Log;
import com.android.internal.R;
import com.android.internal.net.VpnConfig;
import com.android.server.ConnectivityService.VpnCallback;
+import java.io.OutputStream;
+import java.nio.charset.Charsets;
+import java.util.Arrays;
+
/**
* @hide
*/
@@ -49,7 +57,8 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
private String mPackageName;
private String mInterfaceName;
- private String mDnsPropertyPrefix;
+
+ private LegacyVpnRunner mLegacyVpnRunner;
public Vpn(Context context, VpnCallback callback) {
mContext = context;
@@ -68,11 +77,13 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
return mPackageName;
}
- // Check the permission of the caller.
- PackageManager pm = mContext.getPackageManager();
- VpnConfig.enforceCallingPackage(pm.getNameForUid(Binder.getCallingUid()));
+ // Only system user can call this method.
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("Unauthorized Caller");
+ }
// Check the permission of the given package.
+ PackageManager pm = mContext.getPackageManager();
if (packageName.isEmpty()) {
packageName = null;
} else if (pm.checkPermission(VPN, packageName) != PackageManager.PERMISSION_GRANTED) {
@@ -81,7 +92,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
// Reset the interface and hide the notification.
if (mInterfaceName != null) {
- nativeReset(mInterfaceName);
+ jniResetInterface(mInterfaceName);
mCallback.restore();
hideNotification();
mInterfaceName = null;
@@ -95,6 +106,12 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
mContext.sendBroadcast(intent);
}
+ // Stop legacy VPN if it has been started.
+ if (mLegacyVpnRunner != null) {
+ mLegacyVpnRunner.exit();
+ mLegacyVpnRunner = null;
+ }
+
Log.i(TAG, "Switched from " + mPackageName + " to " + packageName);
mPackageName = packageName;
return mPackageName;
@@ -110,7 +127,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
public void protect(ParcelFileDescriptor socket, String name) {
try {
mContext.enforceCallingPermission(VPN, "protect");
- nativeProtect(socket.getFd(), name);
+ jniProtectSocket(socket.getFd(), name);
} finally {
try {
socket.close();
@@ -123,7 +140,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
/**
* Configure a TUN interface and return its file descriptor.
*
- * @param configuration The parameters to configure the interface.
+ * @param config The parameters to configure the interface.
* @return The file descriptor of the interface.
*/
public synchronized ParcelFileDescriptor establish(VpnConfig config) {
@@ -142,18 +159,37 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
return null;
}
- // Create and configure the interface.
- ParcelFileDescriptor descriptor = ParcelFileDescriptor.adoptFd(
- nativeEstablish(config.mtu, config.addresses, config.routes));
+ // Load the label.
+ String label = app.loadLabel(pm).toString();
+
+ // Load the icon and convert it into a bitmap.
+ Drawable icon = app.loadIcon(pm);
+ Bitmap bitmap = null;
+ if (icon.getIntrinsicWidth() > 0 && icon.getIntrinsicHeight() > 0) {
+ int width = mContext.getResources().getDimensionPixelSize(
+ android.R.dimen.notification_large_icon_width);
+ int height = mContext.getResources().getDimensionPixelSize(
+ android.R.dimen.notification_large_icon_height);
+ icon.setBounds(0, 0, width, height);
+ bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ icon.draw(new Canvas(bitmap));
+ }
- // Replace the interface and abort if it fails.
+ // Create the interface and abort if any of the following steps fails.
+ ParcelFileDescriptor descriptor =
+ ParcelFileDescriptor.adoptFd(jniCreateInterface(config.mtu));
try {
- String interfaceName = nativeGetName(descriptor.getFd());
-
- if (mInterfaceName != null && !mInterfaceName.equals(interfaceName)) {
- nativeReset(mInterfaceName);
+ String name = jniGetInterfaceName(descriptor.getFd());
+ if (jniSetAddresses(name, config.addresses) < 1) {
+ throw new IllegalArgumentException("At least one address must be specified");
+ }
+ if (config.routes != null) {
+ jniSetRoutes(name, config.routes);
+ }
+ if (mInterfaceName != null && !mInterfaceName.equals(name)) {
+ jniResetInterface(mInterfaceName);
}
- mInterfaceName = interfaceName;
+ mInterfaceName = name;
} catch (RuntimeException e) {
try {
descriptor.close();
@@ -163,12 +199,15 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
throw e;
}
- String dnsServers = (config.dnsServers == null) ? "" : config.dnsServers.trim();
- mCallback.override(dnsServers.isEmpty() ? null : dnsServers.split(" "));
+ // Override DNS servers and search domains.
+ mCallback.override(config.dnsServers, config.searchDomains);
+ // Fill more values.
config.packageName = mPackageName;
config.interfaceName = mInterfaceName;
- showNotification(pm, app, config);
+
+ // Show the notification!
+ showNotification(config, label, bitmap);
return descriptor;
}
@@ -186,43 +225,28 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
// INetworkManagementEventObserver.Stub
public synchronized void interfaceRemoved(String name) {
- if (name.equals(mInterfaceName) && nativeCheck(name) == 0) {
+ if (name.equals(mInterfaceName) && jniCheckInterface(name) == 0) {
hideNotification();
- mInterfaceName = null;
mCallback.restore();
+ mInterfaceName = null;
}
}
- private void showNotification(PackageManager pm, ApplicationInfo app, VpnConfig config) {
+ private void showNotification(VpnConfig config, String label, Bitmap icon) {
NotificationManager nm = (NotificationManager)
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
if (nm != null) {
- // Load the icon and convert it into a bitmap.
- Drawable icon = app.loadIcon(pm);
- Bitmap bitmap = null;
- if (icon.getIntrinsicWidth() > 0 && icon.getIntrinsicHeight() > 0) {
- int width = mContext.getResources().getDimensionPixelSize(
- android.R.dimen.notification_large_icon_width);
- int height = mContext.getResources().getDimensionPixelSize(
- android.R.dimen.notification_large_icon_height);
- icon.setBounds(0, 0, width, height);
- bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
- icon.draw(new Canvas(bitmap));
- }
-
- // Load the label.
- String label = app.loadLabel(pm).toString();
-
- // Build the notification.
+ String title = (label == null) ? mContext.getString(R.string.vpn_title) :
+ mContext.getString(R.string.vpn_title_long, label);
String text = (config.sessionName == null) ? mContext.getString(R.string.vpn_text) :
mContext.getString(R.string.vpn_text_long, config.sessionName);
+
long identity = Binder.clearCallingIdentity();
Notification notification = new Notification.Builder(mContext)
.setSmallIcon(R.drawable.vpn_connected)
- .setLargeIcon(bitmap)
- .setTicker(mContext.getString(R.string.vpn_ticker, label))
- .setContentTitle(mContext.getString(R.string.vpn_title, label))
+ .setLargeIcon(icon)
+ .setContentTitle(title)
.setContentText(text)
.setContentIntent(VpnConfig.getIntentForNotification(mContext, config))
.setDefaults(Notification.DEFAULT_ALL)
@@ -244,9 +268,227 @@ public class Vpn extends INetworkManagementEventObserver.Stub {
}
}
- private native int nativeEstablish(int mtu, String addresses, String routes);
- private native String nativeGetName(int fd);
- private native void nativeReset(String name);
- private native int nativeCheck(String name);
- private native void nativeProtect(int fd, String name);
+ private native int jniCreateInterface(int mtu);
+ private native String jniGetInterfaceName(int fd);
+ private native int jniSetAddresses(String name, String addresses);
+ private native int jniSetRoutes(String name, String routes);
+ private native void jniResetInterface(String name);
+ private native int jniCheckInterface(String name);
+ private native void jniProtectSocket(int fd, String name);
+
+ /**
+ * Handle legacy VPN requests. This method stops the daemons and restart
+ * them if their arguments are not null. Heavy things are offloaded to
+ * another thread, so callers will not be blocked too long.
+ *
+ * @param raoocn The arguments to be passed to racoon.
+ * @param mtpd The arguments to be passed to mtpd.
+ */
+ public synchronized void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) {
+ // Stop the current VPN just like a normal VPN application.
+ prepare("");
+
+ // Legacy VPN does not have a package name.
+ config.packageName = null;
+
+ // Start a new runner and we are done!
+ mLegacyVpnRunner = new LegacyVpnRunner(config, racoon, mtpd);
+ mLegacyVpnRunner.start();
+ }
+
+ /**
+ * Bringing up a VPN connection takes time, and that is all this thread
+ * does. Here we have plenty of time. The only thing we need to take
+ * care of is responding to interruptions as soon as possible. Otherwise
+ * requests will be piled up. This can be done in a Handler as a state
+ * machine, but it is much easier to read in the current form.
+ */
+ private class LegacyVpnRunner extends Thread {
+ private static final String TAG = "LegacyVpnRunner";
+ private static final String NONE = "--";
+
+ private final VpnConfig mConfig;
+ private final String[] mDaemons;
+ private final String[][] mArguments;
+ private long mTimer = -1;
+
+ public LegacyVpnRunner(VpnConfig config, String[] racoon, String[] mtpd) {
+ super(TAG);
+ mConfig = config;
+ mDaemons = new String[] {"racoon", "mtpd"};
+ mArguments = new String[][] {racoon, mtpd};
+ }
+
+ public void exit() {
+ for (String daemon : mDaemons) {
+ SystemProperties.set("ctl.stop", daemon);
+ }
+ interrupt();
+ }
+
+ @Override
+ public void run() {
+ // Wait for the previous thread since it has been interrupted.
+ Log.v(TAG, "wait");
+ synchronized (TAG) {
+ Log.v(TAG, "begin");
+ execute();
+ Log.v(TAG, "end");
+ }
+ }
+
+ private void checkpoint(boolean yield) throws InterruptedException {
+ long now = SystemClock.elapsedRealtime();
+ if (mTimer == -1) {
+ mTimer = now;
+ Thread.sleep(1);
+ } else if (now - mTimer <= 30000) {
+ Thread.sleep(yield ? 200 : 1);
+ } else {
+ throw new InterruptedException("timeout");
+ }
+ }
+
+ private void execute() {
+ // Catch all exceptions so we can clean up few things.
+ try {
+ // Initialize the timer.
+ checkpoint(false);
+
+ // First stop the daemons.
+ for (String daemon : mDaemons) {
+ SystemProperties.set("ctl.stop", daemon);
+ }
+
+ // Wait for the daemons to stop.
+ for (String daemon : mDaemons) {
+ String key = "init.svc." + daemon;
+ while (!"stopped".equals(SystemProperties.get(key))) {
+ checkpoint(true);
+ }
+ }
+
+ // Reset the properties.
+ SystemProperties.set("vpn.dns", NONE);
+ SystemProperties.set("vpn.via", NONE);
+ while (!NONE.equals(SystemProperties.get("vpn.dns")) ||
+ !NONE.equals(SystemProperties.get("vpn.via"))) {
+ checkpoint(true);
+ }
+
+ // Check if we need to restart some daemons.
+ boolean restart = false;
+ for (String[] arguments : mArguments) {
+ restart = restart || (arguments != null);
+ }
+ if (!restart) {
+ return;
+ }
+
+ // Start the daemon with arguments.
+ for (int i = 0; i < mDaemons.length; ++i) {
+ String[] arguments = mArguments[i];
+ if (arguments == null) {
+ continue;
+ }
+
+ // Start the daemon.
+ String daemon = mDaemons[i];
+ SystemProperties.set("ctl.start", daemon);
+
+ // Wait for the daemon to start.
+ String key = "init.svc." + daemon;
+ while (!"running".equals(SystemProperties.get(key))) {
+ checkpoint(true);
+ }
+
+ // Create the control socket.
+ LocalSocket socket = new LocalSocket();
+ LocalSocketAddress address = new LocalSocketAddress(
+ daemon, LocalSocketAddress.Namespace.RESERVED);
+
+ // Wait for the socket to connect.
+ while (true) {
+ try {
+ socket.connect(address);
+ break;
+ } catch (Exception e) {
+ // ignore
+ }
+ checkpoint(true);
+ }
+ socket.setSoTimeout(500);
+
+ // Send over the arguments.
+ OutputStream out = socket.getOutputStream();
+ for (String argument : arguments) {
+ byte[] bytes = argument.getBytes(Charsets.UTF_8);
+ if (bytes.length >= 0xFFFF) {
+ throw new IllegalArgumentException("argument too large");
+ }
+ out.write(bytes.length >> 8);
+ out.write(bytes.length);
+ out.write(bytes);
+ checkpoint(false);
+ }
+
+ // Send End-Of-Arguments.
+ out.write(0xFF);
+ out.write(0xFF);
+ out.flush();
+ socket.close();
+ }
+
+ // Now here is the beast from the old days. We check few
+ // properties to figure out the current status. Ideally we
+ // can read things back from the sockets and get rid of the
+ // properties, but we have no time...
+ while (NONE.equals(SystemProperties.get("vpn.dns")) ||
+ NONE.equals(SystemProperties.get("vpn.via"))) {
+
+ // Check if a running daemon is dead.
+ for (int i = 0; i < mDaemons.length; ++i) {
+ String daemon = mDaemons[i];
+ if (mArguments[i] != null && !"running".equals(
+ SystemProperties.get("init.svc." + daemon))) {
+ throw new IllegalArgumentException(daemon + " is dead");
+ }
+ }
+ checkpoint(true);
+ }
+
+ // Now we are connected. Get the interface.
+ mConfig.interfaceName = SystemProperties.get("vpn.via");
+
+ // Get the DNS servers if they are not set in config.
+ if (mConfig.dnsServers == null || mConfig.dnsServers.size() == 0) {
+ String dnsServers = SystemProperties.get("vpn.dns").trim();
+ if (!dnsServers.isEmpty()) {
+ mConfig.dnsServers = Arrays.asList(dnsServers.split(" "));
+ }
+ }
+
+ // TODO: support routes and search domains for IPSec Mode-CFG.
+
+ // This is it! Here is the end of our journey!
+ synchronized (Vpn.this) {
+ // Check if the thread is interrupted while we are waiting.
+ checkpoint(false);
+
+ if (mConfig.routes != null) {
+ jniSetRoutes(mConfig.interfaceName, mConfig.routes);
+ }
+ mInterfaceName = mConfig.interfaceName;
+ mCallback.override(mConfig.dnsServers, mConfig.searchDomains);
+ showNotification(mConfig, null, null);
+ }
+ Log.i(TAG, "Connected!");
+ } catch (Exception e) {
+ Log.i(TAG, "Abort due to " + e.getMessage());
+ for (String daemon : mDaemons) {
+ SystemProperties.set("ctl.stop", daemon);
+ }
+ }
+ }
+ }
}
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
index 67e73f5fa10c..4fa3bda0b13f 100755
--- a/services/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -132,7 +132,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
private static final int GPS_CAPABILITY_MSB = 0x0000002;
private static final int GPS_CAPABILITY_MSA = 0x0000004;
private static final int GPS_CAPABILITY_SINGLE_SHOT = 0x0000008;
-
+ private static final int GPS_CAPABILITY_ON_DEMAND_TIME = 0x0000010;
// these need to match AGpsType enum in gps.h
private static final int AGPS_TYPE_SUPL = 1;
@@ -200,6 +200,9 @@ public class GpsLocationProvider implements LocationProviderInterface {
private boolean mInjectNtpTimePending = true;
private boolean mDownloadXtraDataPending = true;
+ // set to true if the GPS engine does not do on-demand NTP time requests
+ private boolean mPeriodicTimeInjection;
+
// true if GPS is navigating
private boolean mNavigating;
@@ -549,10 +552,12 @@ public class GpsLocationProvider implements LocationProviderInterface {
delay = RETRY_INTERVAL;
}
- // send delayed message for next NTP injection
- // since this is delayed and not urgent we do not hold a wake lock here
- mHandler.removeMessages(INJECT_NTP_TIME);
- mHandler.sendMessageDelayed(Message.obtain(mHandler, INJECT_NTP_TIME), delay);
+ if (mPeriodicTimeInjection) {
+ // send delayed message for next NTP injection
+ // since this is delayed and not urgent we do not hold a wake lock here
+ mHandler.removeMessages(INJECT_NTP_TIME);
+ mHandler.sendMessageDelayed(Message.obtain(mHandler, INJECT_NTP_TIME), delay);
+ }
}
private void handleDownloadXtraData() {
@@ -1305,6 +1310,11 @@ public class GpsLocationProvider implements LocationProviderInterface {
*/
private void setEngineCapabilities(int capabilities) {
mEngineCapabilities = capabilities;
+
+ if (!hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME) && !mPeriodicTimeInjection) {
+ mPeriodicTimeInjection = true;
+ requestUtcTime();
+ }
}
/**
@@ -1438,6 +1448,14 @@ public class GpsLocationProvider implements LocationProviderInterface {
}
/**
+ * Called from native code to request utc time info
+ */
+
+ private void requestUtcTime() {
+ sendMessage(INJECT_NTP_TIME, 0, null);
+ }
+
+ /**
* Called from native code to request reference location info
*/
diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java
index 12d3ed8b4dc5..2a17cbe7afda 100644
--- a/services/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -25,6 +25,7 @@ import static android.Manifest.permission.READ_PHONE_STATE;
import static android.content.Intent.ACTION_UID_REMOVED;
import static android.content.Intent.EXTRA_UID;
import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
+import static android.net.ConnectivityManager.*;
import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicy.WARNING_DISABLED;
@@ -57,6 +58,8 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
@@ -71,6 +74,7 @@ import android.net.NetworkTemplate;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.INetworkManagementService;
import android.os.IPowerManager;
import android.os.Message;
import android.os.RemoteCallbackList;
@@ -109,6 +113,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import libcore.io.IoUtils;
@@ -156,6 +161,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private final IActivityManager mActivityManager;
private final IPowerManager mPowerManager;
private final INetworkStatsService mNetworkStats;
+ private final INetworkManagementService mNetworkManagement;
private final TrustedTime mTime;
private IConnectivityManager mConnManager;
@@ -164,6 +170,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private final Object mRulesLock = new Object();
private boolean mScreenOn;
+ private boolean mBackgroundData;
/** Current policy for network templates. */
private ArrayList<NetworkPolicy> mNetworkPolicy = Lists.newArrayList();
@@ -192,11 +199,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// TODO: keep whitelist of system-critical services that should never have
// rules enforced, such as system, phone, and radio UIDs.
+ // TODO: watch for package added broadcast to catch new UIDs.
+
public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
- IPowerManager powerManager, INetworkStatsService networkStats) {
+ IPowerManager powerManager, INetworkStatsService networkStats,
+ INetworkManagementService networkManagement) {
// TODO: move to using cached NtpTrustedTime
- this(context, activityManager, powerManager, networkStats, new NtpTrustedTime(),
- getSystemDir());
+ this(context, activityManager, powerManager, networkStats, networkManagement,
+ new NtpTrustedTime(), getSystemDir());
}
private static File getSystemDir() {
@@ -204,12 +214,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
public NetworkPolicyManagerService(Context context, IActivityManager activityManager,
- IPowerManager powerManager, INetworkStatsService networkStats, TrustedTime time,
- File systemDir) {
+ IPowerManager powerManager, INetworkStatsService networkStats,
+ INetworkManagementService networkManagement,
+ TrustedTime time, File systemDir) {
mContext = checkNotNull(context, "missing context");
mActivityManager = checkNotNull(activityManager, "missing activityManager");
mPowerManager = checkNotNull(powerManager, "missing powerManager");
mNetworkStats = checkNotNull(networkStats, "missing networkStats");
+ mNetworkManagement = checkNotNull(networkManagement, "missing networkManagement");
mTime = checkNotNull(time, "missing TrustedTime");
mHandlerThread = new HandlerThread(TAG);
@@ -235,6 +247,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
updateScreenOn();
+ updateBackgroundData(true);
try {
mActivityManager.registerProcessObserver(mProcessObserver);
@@ -260,11 +273,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final IntentFilter removedFilter = new IntentFilter(ACTION_UID_REMOVED);
mContext.registerReceiver(mRemovedReceiver, removedFilter, null, mHandler);
- // listen for warning polling events; currently dispatched by
+ // listen for stats update events
final IntentFilter statsFilter = new IntentFilter(ACTION_NETWORK_STATS_UPDATED);
mContext.registerReceiver(
mStatsReceiver, statsFilter, READ_NETWORK_USAGE_HISTORY, mHandler);
+ // listen for changes to background data flag
+ final IntentFilter bgFilter = new IntentFilter(ACTION_BACKGROUND_DATA_SETTING_CHANGED);
+ mContext.registerReceiver(mBgReceiver, bgFilter, CONNECTIVITY_INTERNAL, mHandler);
+
}
private IProcessObserver mProcessObserver = new IProcessObserver.Stub() {
@@ -347,6 +364,22 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
};
/**
+ * Receiver that watches for
+ * {@link #ACTION_BACKGROUND_DATA_SETTING_CHANGED}.
+ */
+ private BroadcastReceiver mBgReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // on background handler thread, and verified CONNECTIVITY_INTERNAL
+ // permission above.
+
+ synchronized (mRulesLock) {
+ updateBackgroundData(false);
+ }
+ }
+ };
+
+ /**
* Check {@link NetworkPolicy} against current {@link INetworkStatsService}
* to show visible notifications as needed.
*/
@@ -559,7 +592,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis()
: System.currentTimeMillis();
- mMeteredIfaces.clear();
+ final HashSet<String> newMeteredIfaces = Sets.newHashSet();
// apply each policy that we found ifaces for; compute remaining data
// based on current cycle and historical stats, and push to kernel.
@@ -589,14 +622,28 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
if (policy.limitBytes != NetworkPolicy.LIMIT_DISABLED) {
// remaining "quota" is based on usage in current cycle
final long quota = Math.max(0, policy.limitBytes - total);
- //kernelSetIfacesQuota(ifaces, quota);
+
+ if (ifaces.length > 1) {
+ // TODO: switch to shared quota once NMS supports
+ Slog.w(TAG, "shared quota unsupported; generating rule for each iface");
+ }
for (String iface : ifaces) {
- mMeteredIfaces.add(iface);
+ removeInterfaceQuota(iface);
+ setInterfaceQuota(iface, quota);
+ newMeteredIfaces.add(iface);
}
}
}
+ // remove quota on any trailing interfaces
+ for (String iface : mMeteredIfaces) {
+ if (!newMeteredIfaces.contains(iface)) {
+ removeInterfaceQuota(iface);
+ }
+ }
+ mMeteredIfaces = newMeteredIfaces;
+
final String[] meteredIfaces = mMeteredIfaces.toArray(new String[mMeteredIfaces.size()]);
mHandler.obtainMessage(MSG_METERED_IFACES_CHANGED, meteredIfaces).sendToTarget();
}
@@ -924,6 +971,21 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
+ private void updateBackgroundData(boolean systemReady) {
+ synchronized (mRulesLock) {
+ try {
+ mBackgroundData = mConnManager.getBackgroundDataSetting();
+ } catch (RemoteException e) {
+ }
+ if (systemReady && mBackgroundData) {
+ // typical behavior of background enabled during systemReady;
+ // no need to clear rules for all UIDs.
+ } else {
+ updateRulesForBackgroundDataLocked();
+ }
+ }
+ }
+
/**
* Update rules that might be changed by {@link #mScreenOn} value.
*/
@@ -938,6 +1000,33 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
+ /**
+ * Update rules that might be changed by {@link #mBackgroundData} value.
+ */
+ private void updateRulesForBackgroundDataLocked() {
+ // update rules for all installed applications
+ final PackageManager pm = mContext.getPackageManager();
+ final List<ApplicationInfo> apps = pm.getInstalledApplications(0);
+ for (ApplicationInfo app : apps) {
+ updateRulesForUidLocked(app.uid);
+ }
+
+ // and catch system UIDs
+ // TODO: keep in sync with android_filesystem_config.h
+ for (int uid = 1000; uid <= 1025; uid++) {
+ updateRulesForUidLocked(uid);
+ }
+ for (int uid = 2000; uid <= 2002; uid++) {
+ updateRulesForUidLocked(uid);
+ }
+ for (int uid = 3000; uid <= 3007; uid++) {
+ updateRulesForUidLocked(uid);
+ }
+ for (int uid = 9998; uid <= 9999; uid++) {
+ updateRulesForUidLocked(uid);
+ }
+ }
+
private void updateRulesForUidLocked(int uid) {
final int uidPolicy = getUidPolicy(uid);
final boolean uidForeground = isUidForeground(uid);
@@ -948,14 +1037,21 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// uid in background, and policy says to block metered data
uidRules = RULE_REJECT_METERED;
}
+ if (!uidForeground && !mBackgroundData) {
+ // uid in background, and global background disabled
+ uidRules = RULE_REJECT_METERED;
+ }
// TODO: only dispatch when rules actually change
- // record rule locally to dispatch to new listeners
- mUidRules.put(uid, uidRules);
+ if (uidRules == RULE_ALLOW_ALL) {
+ mUidRules.delete(uid);
+ } else {
+ mUidRules.put(uid, uidRules);
+ }
final boolean rejectMetered = (uidRules & RULE_REJECT_METERED) != 0;
- //kernelSetUidRejectPaid(uid, rejectPaid);
+ setUidNetworkRules(uid, rejectMetered);
// dispatch changed rule to existing listeners
mHandler.obtainMessage(MSG_RULES_CHANGED, uid, uidRules).sendToTarget();
@@ -1003,6 +1099,36 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
};
+ private void setInterfaceQuota(String iface, long quota) {
+ try {
+ mNetworkManagement.setInterfaceQuota(iface, quota);
+ } catch (IllegalStateException e) {
+ Slog.e(TAG, "problem setting interface quota", e);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "problem setting interface quota", e);
+ }
+ }
+
+ private void removeInterfaceQuota(String iface) {
+ try {
+ mNetworkManagement.removeInterfaceQuota(iface);
+ } catch (IllegalStateException e) {
+ Slog.e(TAG, "problem removing interface quota", e);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "problem removing interface quota", e);
+ }
+ }
+
+ private void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces) {
+ try {
+ mNetworkManagement.setUidNetworkRules(uid, rejectOnQuotaInterfaces);
+ } catch (IllegalStateException e) {
+ Slog.e(TAG, "problem setting uid rules", e);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "problem setting uid rules", e);
+ }
+ }
+
private String getActiveSubscriberId() {
final TelephonyManager telephony = (TelephonyManager) mContext.getSystemService(
Context.TELEPHONY_SERVICE);
diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java
index 7610a1181d60..b4bd17690605 100644
--- a/services/java/com/android/server/net/NetworkStatsService.java
+++ b/services/java/com/android/server/net/NetworkStatsService.java
@@ -134,7 +134,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
* Settings that can be changed externally.
*/
public interface NetworkStatsSettings {
- public boolean getEnabled();
public long getPollInterval();
public long getPersistThreshold();
public long getNetworkBucketDuration();
@@ -207,20 +206,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
public void systemReady() {
- if (mSettings.getEnabled()) {
- try {
- // enable low-level bandwidth stats and control
- // TODO: consider shipping with this enabled by default
- mNetworkManager.setBandwidthControlEnabled(true);
- } catch (RemoteException e) {
- Slog.e(TAG, "problem talking to netd while enabling bandwidth controls", e);
- } catch (NativeDaemonConnectorException ndce) {
- Slog.e(TAG, "problem enabling bandwidth controls", ndce);
- }
- } else {
- Slog.w(TAG, "detailed network stats disabled");
- }
-
synchronized (mStatsLock) {
// read historical network stats from disk, since policy service
// might need them right away. we delay loading detailed UID stats
@@ -389,6 +374,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
}
}
+ @Override
+ public void forceUpdate() {
+ mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
+
+ synchronized (mStatsLock) {
+ performPollLocked(true, false);
+ }
+ }
+
/**
* Receiver that watches for {@link IConnectivityManager} to claim network
* interfaces. Used to associate {@link TelephonyManager#getSubscriberId()}
@@ -905,6 +899,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
argSet.add(arg);
}
+ final boolean fullHistory = argSet.contains("full");
+
synchronized (mStatsLock) {
// TODO: remove this testing code, since it corrupts stats
if (argSet.contains("generate")) {
@@ -930,7 +926,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
for (NetworkIdentitySet ident : mNetworkStats.keySet()) {
final NetworkStatsHistory history = mNetworkStats.get(ident);
pw.print(" ident="); pw.println(ident.toString());
- history.dump(" ", pw);
+ history.dump(" ", pw, fullHistory);
}
if (argSet.contains("detail")) {
@@ -950,7 +946,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
final NetworkStatsHistory history = uidStats.valueAt(i);
pw.print(" UID="); pw.print(uid);
pw.print(" tag="); pw.println(tag);
- history.dump(" ", pw);
+ history.dump(" ", pw, fullHistory);
}
}
}
@@ -1058,15 +1054,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
return Settings.Secure.getLong(mResolver, name, def);
}
- public boolean getEnabled() {
- if (!new File("/proc/net/xt_qtaguid/ctrl").exists()) {
- Slog.w(TAG, "kernel does not support bandwidth control");
- return false;
- }
- // TODO: once things stabilize, enable by default.
- // For now: ./vendor/google/tools/override-gservices secure:netstats_enabled=1
- return Settings.Secure.getInt(mResolver, NETSTATS_ENABLED, 0) != 0;
- }
public long getPollInterval() {
return getSecureLong(NETSTATS_POLL_INTERVAL, 15 * MINUTE_IN_MILLIS);
}
diff --git a/services/java/com/android/server/pm/Installer.java b/services/java/com/android/server/pm/Installer.java
index d10aa97b23ad..11ccd60e566c 100644
--- a/services/java/com/android/server/pm/Installer.java
+++ b/services/java/com/android/server/pm/Installer.java
@@ -307,7 +307,7 @@ class Installer {
}
public int getSizeInfo(String pkgName, String apkPath, String fwdLockApkPath,
- PackageStats pStats) {
+ String asecPath, PackageStats pStats) {
StringBuilder builder = new StringBuilder("getsize");
builder.append(' ');
builder.append(pkgName);
@@ -315,17 +315,20 @@ class Installer {
builder.append(apkPath);
builder.append(' ');
builder.append(fwdLockApkPath != null ? fwdLockApkPath : "!");
+ builder.append(' ');
+ builder.append(asecPath != null ? asecPath : "!");
String s = transaction(builder.toString());
String res[] = s.split(" ");
- if ((res == null) || (res.length != 4)) {
+ if ((res == null) || (res.length != 5)) {
return -1;
}
try {
pStats.codeSize = Long.parseLong(res[1]);
pStats.dataSize = Long.parseLong(res[2]);
pStats.cacheSize = Long.parseLong(res[3]);
+ pStats.externalCodeSize = Long.parseLong(res[4]);
return Integer.parseInt(res[0]);
} catch (NumberFormatException e) {
return -1;
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 5a9dae9d0ab6..ea5d26b99056 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -75,6 +75,7 @@ import android.os.Bundle;
import android.os.Environment;
import android.os.FileObserver;
import android.os.FileUtils;
+import android.os.FileUtils.FileStatus;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
@@ -156,7 +157,6 @@ public class PackageManagerService extends IPackageManager.Stub {
private static final int RADIO_UID = Process.PHONE_UID;
private static final int LOG_UID = Process.LOG_UID;
private static final int NFC_UID = Process.NFC_UID;
- private static final int KEYCHAIN_UID = Process.KEYCHAIN_UID;
static final int FIRST_APPLICATION_UID =
Process.FIRST_APPLICATION_UID;
static final int MAX_APPLICATION_UIDS = 1000;
@@ -760,10 +760,6 @@ public class PackageManagerService extends IPackageManager.Stub {
MULTIPLE_APPLICATION_UIDS
? NFC_UID : FIRST_APPLICATION_UID,
ApplicationInfo.FLAG_SYSTEM);
- mSettings.addSharedUserLPw("android.uid.keychain",
- MULTIPLE_APPLICATION_UIDS
- ? KEYCHAIN_UID : FIRST_APPLICATION_UID,
- ApplicationInfo.FLAG_SYSTEM);
String separateProcesses = SystemProperties.get("debug.separate_processes");
if (separateProcesses != null && separateProcesses.length() > 0) {
@@ -4887,8 +4883,7 @@ public class PackageManagerService extends IPackageManager.Stub {
private final IPackageStatsObserver mObserver;
- public MeasureParams(PackageStats stats, boolean success,
- IPackageStatsObserver observer) {
+ public MeasureParams(PackageStats stats, boolean success, IPackageStatsObserver observer) {
mObserver = observer;
mStats = stats;
mSuccess = success;
@@ -5480,6 +5475,17 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
+ /**
+ * Extract the MountService "container ID" from the full code path of an
+ * .apk.
+ */
+ static String cidFromCodePath(String fullCodePath) {
+ int eidx = fullCodePath.lastIndexOf("/");
+ String subStr1 = fullCodePath.substring(0, eidx);
+ int sidx = subStr1.lastIndexOf("/");
+ return subStr1.substring(sidx+1, eidx);
+ }
+
class SdInstallArgs extends InstallArgs {
static final String RES_FILE_NAME = "pkg.apk";
@@ -6831,6 +6837,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
PackageParser.Package p;
boolean dataOnly = false;
+ String asecPath = null;
synchronized (mPackages) {
p = mPackages.get(packageName);
if(p == null) {
@@ -6842,6 +6849,12 @@ public class PackageManagerService extends IPackageManager.Stub {
}
p = ps.pkg;
}
+ if (p != null && isExternal(p)) {
+ String secureContainerId = cidFromCodePath(p.applicationInfo.sourceDir);
+ if (secureContainerId != null) {
+ asecPath = PackageHelper.getSdFilesystem(secureContainerId);
+ }
+ }
}
String publicSrcDir = null;
if(!dataOnly) {
@@ -6850,10 +6863,13 @@ public class PackageManagerService extends IPackageManager.Stub {
Slog.w(TAG, "Package " + packageName + " has no applicationInfo.");
return false;
}
- publicSrcDir = isForwardLocked(p) ? applicationInfo.publicSourceDir : null;
+ if (isForwardLocked(p)) {
+ publicSrcDir = applicationInfo.publicSourceDir;
+ }
}
if (mInstaller != null) {
- int res = mInstaller.getSizeInfo(packageName, p.mPath, publicSrcDir, pStats);
+ int res = mInstaller.getSizeInfo(packageName, p.mPath, publicSrcDir,
+ asecPath, pStats);
if (res < 0) {
return false;
} else {
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index 918f1b6b8355..13a76b379264 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -45,7 +45,6 @@ import android.os.storage.StorageVolume;
import android.os.SystemProperties;
import android.os.UEventObserver;
import android.provider.Settings;
-import android.util.Log;
import android.util.Slog;
import java.io.File;
@@ -62,7 +61,7 @@ import java.util.List;
public class UsbDeviceManager {
private static final String TAG = UsbDeviceManager.class.getSimpleName();
- private static final boolean LOG = false;
+ private static final boolean DEBUG = false;
private static final String USB_STATE_MATCH =
"DEVPATH=/devices/virtual/android_usb/android0";
@@ -93,18 +92,9 @@ public class UsbDeviceManager {
private final UsbSettingsManager mSettingsManager;
private NotificationManager mNotificationManager;
private final boolean mHasUsbAccessory;
-
- // for USB connected notification
- private boolean mUsbNotificationShown;
private boolean mUseUsbNotification;
- private Notification mUsbNotification;
-
- // for adb connected notification
- private boolean mAdbNotificationShown;
- private Notification mAdbNotification;
private boolean mAdbEnabled;
-
private class AdbSettingsObserver extends ContentObserver {
public AdbSettingsObserver() {
super(null);
@@ -117,115 +107,20 @@ public class UsbDeviceManager {
}
}
- private void updateUsbNotification(boolean connected) {
- if (mNotificationManager == null || !mUseUsbNotification) return;
- if (connected) {
- if (!mUsbNotificationShown) {
- Resources r = mContext.getResources();
- CharSequence title = r.getText(
- com.android.internal.R.string.usb_preferences_notification_title);
- CharSequence message = r.getText(
- com.android.internal.R.string.usb_preferece_notification_message);
-
- if (mUsbNotification == null) {
- mUsbNotification = new Notification();
- mUsbNotification.icon = com.android.internal.R.drawable.stat_sys_data_usb;
- mUsbNotification.when = 0;
- mUsbNotification.flags = Notification.FLAG_ONGOING_EVENT;
- mUsbNotification.tickerText = title;
- mUsbNotification.defaults = 0; // please be quiet
- mUsbNotification.sound = null;
- mUsbNotification.vibrate = null;
- }
-
- Intent intent = new Intent();
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
- Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- intent.setClassName("com.android.systemui",
- "com.android.systemui.usb.UsbPreferenceActivity");
- PendingIntent pi = PendingIntent.getActivity(mContext, 0,
- intent, 0);
-
- mUsbNotification.setLatestEventInfo(mContext, title, message, pi);
-
- mUsbNotificationShown = true;
- mNotificationManager.notify(
- com.android.internal.R.string.usb_preferences_notification_title,
- mUsbNotification);
- }
-
- } else if (mUsbNotificationShown) {
- mUsbNotificationShown = false;
- mNotificationManager.cancel(
- com.android.internal.R.string.usb_preferences_notification_title);
- }
- }
-
- private void updateAdbNotification(boolean adbEnabled) {
- if (mNotificationManager == null) return;
- if (adbEnabled) {
- if ("0".equals(SystemProperties.get("persist.adb.notify"))) return;
-
- if (!mAdbNotificationShown) {
- Resources r = mContext.getResources();
- CharSequence title = r.getText(
- com.android.internal.R.string.adb_active_notification_title);
- CharSequence message = r.getText(
- com.android.internal.R.string.adb_active_notification_message);
-
- if (mAdbNotification == null) {
- mAdbNotification = new Notification();
- mAdbNotification.icon = com.android.internal.R.drawable.stat_sys_adb;
- mAdbNotification.when = 0;
- mAdbNotification.flags = Notification.FLAG_ONGOING_EVENT;
- mAdbNotification.tickerText = title;
- mAdbNotification.defaults = 0; // please be quiet
- mAdbNotification.sound = null;
- mAdbNotification.vibrate = null;
- }
-
- Intent intent = new Intent(
- Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
- Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- // Note: we are hard-coding the component because this is
- // an important security UI that we don't want anyone
- // intercepting.
- intent.setComponent(new ComponentName("com.android.settings",
- "com.android.settings.DevelopmentSettings"));
- PendingIntent pi = PendingIntent.getActivity(mContext, 0,
- intent, 0);
-
- mAdbNotification.setLatestEventInfo(mContext, title, message, pi);
-
- mAdbNotificationShown = true;
- mNotificationManager.notify(
- com.android.internal.R.string.adb_active_notification_title,
- mAdbNotification);
- }
- } else if (mAdbNotificationShown) {
- mAdbNotificationShown = false;
- mNotificationManager.cancel(
- com.android.internal.R.string.adb_active_notification_title);
- }
- }
-
/*
* Listens for uevent messages from the kernel to monitor the USB state
*/
private final UEventObserver mUEventObserver = new UEventObserver() {
@Override
public void onUEvent(UEventObserver.UEvent event) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Slog.v(TAG, "USB UEVENT: " + event.toString());
- }
+ if (DEBUG) Slog.v(TAG, "USB UEVENT: " + event.toString());
String state = event.get("USB_STATE");
String accessory = event.get("ACCESSORY");
if (state != null) {
mHandler.updateState(state);
} else if ("START".equals(accessory)) {
- Slog.d(TAG, "got accessory start");
+ if (DEBUG) Slog.d(TAG, "got accessory start");
setCurrentFunction(UsbManager.USB_FUNCTION_ACCESSORY, false);
}
}
@@ -319,16 +214,32 @@ public class UsbDeviceManager {
private String mDefaultFunctions;
private UsbAccessory mCurrentAccessory;
private boolean mDeferAccessoryAttached;
+ private int mUsbNotificationId;
+ private boolean mAdbNotificationShown;
+
+ private static final int NOTIFICATION_NONE = 0;
+ private static final int NOTIFICATION_MTP = 1;
+ private static final int NOTIFICATION_PTP = 2;
+ private static final int NOTIFICATION_INSTALLER = 3;
+ private static final int NOTIFICATION_ADB = 4;
public UsbHandler() {
- // Read initial USB state
try {
+ // sanity check the sys.usb.config system property
+ // this may be necessary if we crashed while switching USB configurations
+ String config = SystemProperties.get("sys.usb.config", "none");
+ if (config.equals("none")) {
+ String persistConfig = SystemProperties.get("persist.sys.usb.config", "none");
+ Slog.w(TAG, "resetting config to persistent property: " + persistConfig);
+ SystemProperties.set("sys.usb.config", persistConfig);
+ }
+
+ // Read initial USB state
mCurrentFunctions = FileUtils.readTextFile(
new File(FUNCTIONS_PATH), 0, null).trim();
mDefaultFunctions = mCurrentFunctions;
String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
updateState(state);
-
mAdbEnabled = containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_ADB);
// Upgrade step for previous versions that used persist.service.adb.enable
@@ -414,12 +325,12 @@ public class UsbDeviceManager {
} catch (InterruptedException e) {
}
}
- Log.e(TAG, "waitForState(" + state + ") FAILED");
+ Slog.e(TAG, "waitForState(" + state + ") FAILED");
return false;
}
private boolean setUsbConfig(String config) {
- Log.d(TAG, "setUsbConfig(" + config + ")");
+ if (DEBUG) Slog.d(TAG, "setUsbConfig(" + config + ")");
// set the new configuration
SystemProperties.set("sys.usb.config", config);
return waitForState(config);
@@ -428,7 +339,7 @@ public class UsbDeviceManager {
private void doSetCurrentFunctions(String functions) {
if (!mCurrentFunctions.equals(functions)) {
if (!setUsbConfig("none") || !setUsbConfig(functions)) {
- Log.e(TAG, "Failed to switch USB configuration to " + functions);
+ Slog.e(TAG, "Failed to switch USB configuration to " + functions);
// revert to previous configuration if we fail
setUsbConfig(mCurrentFunctions);
} else {
@@ -438,6 +349,7 @@ public class UsbDeviceManager {
}
private void setAdbEnabled(boolean enable) {
+ if (DEBUG) Slog.d(TAG, "setAdbEnabled: " + enable);
if (enable != mAdbEnabled) {
mAdbEnabled = enable;
String functions;
@@ -449,7 +361,7 @@ public class UsbDeviceManager {
functions = removeFunction(mDefaultFunctions, UsbManager.USB_FUNCTION_ADB);
}
setCurrentFunction(functions, true);
- updateAdbNotification(mAdbEnabled && mConnected);
+ updateAdbNotification();
}
}
@@ -469,7 +381,7 @@ public class UsbDeviceManager {
String[] strings = nativeGetAccessoryStrings();
if (strings != null) {
mCurrentAccessory = new UsbAccessory(strings);
- Log.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
+ Slog.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
// defer accessoryAttached if system is not ready
if (mSystemReady) {
mSettingsManager.accessoryAttached(mCurrentAccessory);
@@ -477,12 +389,12 @@ public class UsbDeviceManager {
mDeferAccessoryAttached = true;
}
} else {
- Log.e(TAG, "nativeGetAccessoryStrings failed");
+ Slog.e(TAG, "nativeGetAccessoryStrings failed");
}
} else if (!mConnected) {
// make sure accessory mode is off
// and restore default functions
- Log.d(TAG, "exited USB accessory mode");
+ Slog.d(TAG, "exited USB accessory mode");
setEnabledFunctions(mDefaultFunctions);
if (mCurrentAccessory != null) {
@@ -517,8 +429,8 @@ public class UsbDeviceManager {
case MSG_UPDATE_STATE:
mConnected = (msg.arg1 == 1);
mConfigured = (msg.arg2 == 1);
- updateUsbNotification(mConnected);
- updateAdbNotification(mAdbEnabled && mConnected);
+ updateUsbNotification();
+ updateAdbNotification();
if (containsFunction(mCurrentFunctions,
UsbManager.USB_FUNCTION_ACCESSORY)) {
updateCurrentAccessory();
@@ -562,8 +474,8 @@ public class UsbDeviceManager {
}
break;
case MSG_SYSTEM_READY:
- updateUsbNotification(mConnected);
- updateAdbNotification(mAdbEnabled && mConnected);
+ updateUsbNotification();
+ updateAdbNotification();
updateUsbState();
if (mCurrentAccessory != null && mDeferAccessoryAttached) {
mSettingsManager.accessoryAttached(mCurrentAccessory);
@@ -576,6 +488,105 @@ public class UsbDeviceManager {
return mCurrentAccessory;
}
+ private void updateUsbNotification() {
+ if (mNotificationManager == null || !mUseUsbNotification) return;
+ if (mConnected) {
+ Resources r = mContext.getResources();
+ CharSequence title = null;
+ int id = NOTIFICATION_NONE;
+ if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MTP)) {
+ title = r.getText(
+ com.android.internal.R.string.usb_mtp_notification_title);
+ id = NOTIFICATION_MTP;
+ } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_PTP)) {
+ title = r.getText(
+ com.android.internal.R.string.usb_ptp_notification_title);
+ id = NOTIFICATION_PTP;
+ } else if (containsFunction(mCurrentFunctions,
+ UsbManager.USB_FUNCTION_MASS_STORAGE)) {
+ title = r.getText(
+ com.android.internal.R.string.usb_cd_installer_notification_title);
+ id = NOTIFICATION_INSTALLER;
+ } else {
+ Slog.e(TAG, "No known USB function in updateUsbNotification");
+ }
+ if (id != mUsbNotificationId) {
+ // clear notification if title needs changing
+ if (mUsbNotificationId != NOTIFICATION_NONE) {
+ mNotificationManager.cancel(mUsbNotificationId);
+ mUsbNotificationId = NOTIFICATION_NONE;
+ }
+ }
+ if (mUsbNotificationId == NOTIFICATION_NONE) {
+ CharSequence message = r.getText(
+ com.android.internal.R.string.usb_notification_message);
+
+ Notification notification = new Notification();
+ notification.icon = com.android.internal.R.drawable.stat_sys_data_usb;
+ notification.when = 0;
+ notification.flags = Notification.FLAG_ONGOING_EVENT;
+ notification.tickerText = title;
+ notification.defaults = 0; // please be quiet
+ notification.sound = null;
+ notification.vibrate = null;
+
+ Intent intent = new Intent();
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
+ Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ intent.setClassName("com.android.systemui",
+ "com.android.systemui.usb.UsbPreferenceActivity");
+ PendingIntent pi = PendingIntent.getActivity(mContext, 0,
+ intent, 0);
+ notification.setLatestEventInfo(mContext, title, message, pi);
+ mNotificationManager.notify(id, notification);
+ mUsbNotificationId = id;
+ }
+
+ } else if (mUsbNotificationId != NOTIFICATION_NONE) {
+ mNotificationManager.cancel(mUsbNotificationId);
+ mUsbNotificationId = NOTIFICATION_NONE;
+ }
+ }
+
+ private void updateAdbNotification() {
+ if (mNotificationManager == null) return;
+ if (mAdbEnabled && mConnected) {
+ if ("0".equals(SystemProperties.get("persist.adb.notify"))) return;
+
+ if (!mAdbNotificationShown) {
+ Resources r = mContext.getResources();
+ CharSequence title = r.getText(
+ com.android.internal.R.string.adb_active_notification_title);
+ CharSequence message = r.getText(
+ com.android.internal.R.string.adb_active_notification_message);
+
+ Notification notification = new Notification();
+ notification.icon = com.android.internal.R.drawable.stat_sys_adb;
+ notification.when = 0;
+ notification.flags = Notification.FLAG_ONGOING_EVENT;
+ notification.tickerText = title;
+ notification.defaults = 0; // please be quiet
+ notification.sound = null;
+ notification.vibrate = null;
+
+ Intent intent = new Intent(
+ Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
+ Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ intent.setComponent(new ComponentName("com.android.settings",
+ "com.android.settings.DevelopmentSettings"));
+ PendingIntent pi = PendingIntent.getActivity(mContext, 0,
+ intent, 0);
+ notification.setLatestEventInfo(mContext, title, message, pi);
+ mAdbNotificationShown = true;
+ mNotificationManager.notify(NOTIFICATION_ADB, notification);
+ }
+ } else if (mAdbNotificationShown) {
+ mAdbNotificationShown = false;
+ mNotificationManager.cancel(NOTIFICATION_ADB);
+ }
+ }
+
public void dump(FileDescriptor fd, PrintWriter pw) {
pw.println(" USB Device State:");
pw.println(" Current Functions: " + mCurrentFunctions);
@@ -608,6 +619,7 @@ public class UsbDeviceManager {
}
public void setCurrentFunction(String function, boolean makeDefault) {
+ if (DEBUG) Slog.d(TAG, "setCurrentFunction(" + function + ") default: " + makeDefault);
mHandler.sendMessage(MSG_SET_CURRENT_FUNCTION, function, makeDefault);
}
diff --git a/services/java/com/android/server/usb/UsbHostManager.java b/services/java/com/android/server/usb/UsbHostManager.java
index 923b0494f597..0a0ff598d7d8 100644
--- a/services/java/com/android/server/usb/UsbHostManager.java
+++ b/services/java/com/android/server/usb/UsbHostManager.java
@@ -37,7 +37,6 @@ import android.os.Parcelable;
import android.os.ParcelFileDescriptor;
import android.os.UEventObserver;
import android.provider.Settings;
-import android.util.Log;
import android.util.Slog;
import java.io.File;
@@ -112,7 +111,7 @@ public class UsbHostManager {
synchronized (mLock) {
if (mDevices.get(deviceName) != null) {
- Log.w(TAG, "device already on mDevices list: " + deviceName);
+ Slog.w(TAG, "device already on mDevices list: " + deviceName);
return;
}
@@ -148,7 +147,7 @@ public class UsbHostManager {
} catch (Exception e) {
// beware of index out of bound exceptions, which might happen if
// a device does not set bNumEndpoints correctly
- Log.e(TAG, "error parsing USB descriptors", e);
+ Slog.e(TAG, "error parsing USB descriptors", e);
return;
}
diff --git a/services/java/com/android/server/usb/UsbSettingsManager.java b/services/java/com/android/server/usb/UsbSettingsManager.java
index 911367711faf..0baafbb2bf72 100644
--- a/services/java/com/android/server/usb/UsbSettingsManager.java
+++ b/services/java/com/android/server/usb/UsbSettingsManager.java
@@ -35,7 +35,7 @@ import android.hardware.usb.UsbManager;
import android.os.Binder;
import android.os.FileUtils;
import android.os.Process;
-import android.util.Log;
+import android.util.Slog;
import android.util.SparseBooleanArray;
import android.util.Xml;
@@ -62,6 +62,7 @@ import java.util.List;
class UsbSettingsManager {
private static final String TAG = "UsbSettingsManager";
+ private static final boolean DEBUG = false;
private static final File sSettingsFile = new File("/data/system/usb_device_manager.xml");
private final Context mContext;
@@ -410,9 +411,9 @@ class UsbSettingsManager {
}
}
} catch (FileNotFoundException e) {
- Log.w(TAG, "settings file not found");
+ if (DEBUG) Slog.d(TAG, "settings file not found");
} catch (Exception e) {
- Log.e(TAG, "error reading settings file, deleting to start fresh", e);
+ Slog.e(TAG, "error reading settings file, deleting to start fresh", e);
sSettingsFile.delete();
} finally {
if (stream != null) {
@@ -428,7 +429,7 @@ class UsbSettingsManager {
FileOutputStream fos = null;
try {
FileOutputStream fstr = new FileOutputStream(sSettingsFile);
- Log.d(TAG, "writing settings to " + fstr);
+ if (DEBUG) Slog.d(TAG, "writing settings to " + fstr);
BufferedOutputStream str = new BufferedOutputStream(fstr);
FastXmlSerializer serializer = new FastXmlSerializer();
serializer.setOutput(str, "utf-8");
@@ -457,7 +458,7 @@ class UsbSettingsManager {
FileUtils.sync(fstr);
str.close();
} catch (Exception e) {
- Log.e(TAG, "error writing settings file, deleting to start fresh", e);
+ Slog.e(TAG, "error writing settings file, deleting to start fresh", e);
sSettingsFile.delete();
}
}
@@ -472,7 +473,7 @@ class UsbSettingsManager {
try {
parser = ai.loadXmlMetaData(mPackageManager, metaDataName);
if (parser == null) {
- Log.w(TAG, "no meta-data for " + info);
+ Slog.w(TAG, "no meta-data for " + info);
return false;
}
@@ -494,7 +495,7 @@ class UsbSettingsManager {
XmlUtils.nextElement(parser);
}
} catch (Exception e) {
- Log.w(TAG, "Unable to load component info " + info.toString(), e);
+ Slog.w(TAG, "Unable to load component info " + info.toString(), e);
} finally {
if (parser != null) parser.close();
}
@@ -553,7 +554,7 @@ class UsbSettingsManager {
Intent intent = new Intent(UsbManager.ACTION_USB_DEVICE_DETACHED);
intent.putExtra(UsbManager.EXTRA_DEVICE, device);
- Log.d(TAG, "usbDeviceRemoved, sending " + intent);
+ if (DEBUG) Slog.d(TAG, "usbDeviceRemoved, sending " + intent);
mContext.sendBroadcast(intent);
}
@@ -604,7 +605,7 @@ class UsbSettingsManager {
try {
mContext.startActivity(dialogIntent);
} catch (ActivityNotFoundException e) {
- Log.e(TAG, "unable to start UsbAccessoryUriActivity");
+ Slog.e(TAG, "unable to start UsbAccessoryUriActivity");
}
}
}
@@ -652,7 +653,7 @@ class UsbSettingsManager {
defaultRI.activityInfo.name));
mContext.startActivity(intent);
} catch (ActivityNotFoundException e) {
- Log.e(TAG, "startActivity failed", e);
+ Slog.e(TAG, "startActivity failed", e);
}
} else {
Intent resolverIntent = new Intent();
@@ -679,7 +680,7 @@ class UsbSettingsManager {
try {
mContext.startActivity(resolverIntent);
} catch (ActivityNotFoundException e) {
- Log.e(TAG, "unable to start activity " + resolverIntent);
+ Slog.e(TAG, "unable to start activity " + resolverIntent);
}
}
}
@@ -733,7 +734,7 @@ class UsbSettingsManager {
XmlUtils.nextElement(parser);
}
} catch (Exception e) {
- Log.w(TAG, "Unable to load component info " + aInfo.toString(), e);
+ Slog.w(TAG, "Unable to load component info " + aInfo.toString(), e);
} finally {
if (parser != null) parser.close();
}
@@ -751,7 +752,7 @@ class UsbSettingsManager {
info = mPackageManager.getPackageInfo(packageName,
PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA);
} catch (NameNotFoundException e) {
- Log.e(TAG, "handlePackageUpdate could not find package " + packageName, e);
+ Slog.e(TAG, "handlePackageUpdate could not find package " + packageName, e);
return;
}
@@ -831,7 +832,7 @@ class UsbSettingsManager {
try {
mContext.startActivity(intent);
} catch (ActivityNotFoundException e) {
- Log.e(TAG, "unable to start UsbPermissionActivity");
+ Slog.e(TAG, "unable to start UsbPermissionActivity");
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -847,7 +848,7 @@ class UsbSettingsManager {
try {
pi.send(mContext, 0, intent);
} catch (PendingIntent.CanceledException e) {
- Log.w(TAG, "requestPermission PendingIntent was cancelled");
+ if (DEBUG) Slog.d(TAG, "requestPermission PendingIntent was cancelled");
}
return;
}
@@ -867,7 +868,7 @@ class UsbSettingsManager {
try {
pi.send(mContext, 0, intent);
} catch (PendingIntent.CanceledException e) {
- Log.w(TAG, "requestPermission PendingIntent was cancelled");
+ if (DEBUG) Slog.d(TAG, "requestPermission PendingIntent was cancelled");
}
return;
}
diff --git a/services/jni/com_android_server_connectivity_Vpn.cpp b/services/jni/com_android_server_connectivity_Vpn.cpp
index ae7fbfef80db..62d7636321c0 100644
--- a/services/jni/com_android_server_connectivity_Vpn.cpp
+++ b/services/jni/com_android_server_connectivity_Vpn.cpp
@@ -42,6 +42,9 @@
namespace android
{
+static int inet4 = -1;
+static int inet6 = -1;
+
static inline in_addr_t *as_in_addr(sockaddr *sa) {
return &((sockaddr_in *)sa)->sin_addr.s_addr;
}
@@ -51,11 +54,9 @@ static inline in_addr_t *as_in_addr(sockaddr *sa) {
#define SYSTEM_ERROR -1
#define BAD_ARGUMENT -2
-static int create_interface(int mtu, char *name, int *index)
+static int create_interface(int mtu)
{
- int tun = open("/dev/tun", O_RDWR);
- int inet4 = socket(AF_INET, SOCK_DGRAM, 0);
- int flags;
+ int tun = open("/dev/tun", O_RDWR | O_NONBLOCK);
ifreq ifr4;
memset(&ifr4, 0, sizeof(ifr4));
@@ -81,38 +82,45 @@ static int create_interface(int mtu, char *name, int *index)
goto error;
}
- // Get interface index.
- if (ioctl(inet4, SIOGIFINDEX, &ifr4)) {
- LOGE("Cannot get index of %s: %s", ifr4.ifr_name, strerror(errno));
- goto error;
- }
-
- // Make it non-blocking.
- flags = fcntl(tun, F_GETFL, 0);
- if (flags == -1 || fcntl(tun, F_SETFL, flags | O_NONBLOCK)) {
- LOGE("Cannot set non-blocking on %s: %s", ifr4.ifr_name, strerror(errno));
- goto error;
- }
-
- strcpy(name, ifr4.ifr_name);
- *index = ifr4.ifr_ifindex;
- close(inet4);
return tun;
error:
close(tun);
- close(inet4);
return SYSTEM_ERROR;
}
-static int set_addresses(const char *name, int index, const char *addresses)
+static int get_interface_name(char *name, int tun)
+{
+ ifreq ifr4;
+ if (ioctl(tun, TUNGETIFF, &ifr4)) {
+ LOGE("Cannot get interface name: %s", strerror(errno));
+ return SYSTEM_ERROR;
+ }
+ strncpy(name, ifr4.ifr_name, IFNAMSIZ);
+ return 0;
+}
+
+static int get_interface_index(const char *name)
+{
+ ifreq ifr4;
+ strncpy(ifr4.ifr_name, name, IFNAMSIZ);
+ if (ioctl(inet4, SIOGIFINDEX, &ifr4)) {
+ LOGE("Cannot get index of %s: %s", name, strerror(errno));
+ return SYSTEM_ERROR;
+ }
+ return ifr4.ifr_ifindex;
+}
+
+static int set_addresses(const char *name, const char *addresses)
{
- int inet4 = socket(AF_INET, SOCK_DGRAM, 0);
- int inet6 = socket(AF_INET6, SOCK_DGRAM, 0);
+ int index = get_interface_index(name);
+ if (index < 0) {
+ return index;
+ }
ifreq ifr4;
memset(&ifr4, 0, sizeof(ifr4));
- strcpy(ifr4.ifr_name, name);
+ strncpy(ifr4.ifr_name, name, IFNAMSIZ);
ifr4.ifr_addr.sa_family = AF_INET;
in6_ifreq ifr6;
@@ -121,7 +129,6 @@ static int set_addresses(const char *name, int index, const char *addresses)
char address[65];
int prefix;
-
int chars;
int count = 0;
@@ -164,7 +171,7 @@ static int set_addresses(const char *name, int index, const char *addresses)
break;
}
}
- LOGV("Address added on %s: %s/%d", name, address, prefix);
+ LOGD("Address added on %s: %s/%d", name, address, prefix);
++count;
}
@@ -177,15 +184,15 @@ static int set_addresses(const char *name, int index, const char *addresses)
count = BAD_ARGUMENT;
}
- close(inet4);
- close(inet6);
return count;
}
-static int set_routes(const char *name, int index, const char *routes)
+static int set_routes(const char *name, const char *routes)
{
- int inet4 = socket(AF_INET, SOCK_DGRAM, 0);
- int inet6 = socket(AF_INET6, SOCK_DGRAM, 0);
+ int index = get_interface_index(name);
+ if (index < 0) {
+ return index;
+ }
rtentry rt4;
memset(&rt4, 0, sizeof(rt4));
@@ -201,7 +208,6 @@ static int set_routes(const char *name, int index, const char *routes)
char address[65];
int prefix;
-
int chars;
int count = 0;
@@ -211,32 +217,50 @@ static int set_routes(const char *name, int index, const char *routes)
if (strchr(address, ':')) {
// Add an IPv6 route.
if (inet_pton(AF_INET6, address, &rt6.rtmsg_dst) != 1 ||
- prefix < 1 || prefix > 128) {
+ prefix < 0 || prefix > 128) {
count = BAD_ARGUMENT;
break;
}
- rt6.rtmsg_dst_len = prefix;
+ rt6.rtmsg_dst_len = prefix ? prefix : 1;
if (ioctl(inet6, SIOCADDRT, &rt6) && errno != EEXIST) {
count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
break;
}
+
+ if (!prefix) {
+ // Split the route instead of replacing the default route.
+ rt6.rtmsg_dst.s6_addr[0] ^= 0x80;
+ if (ioctl(inet6, SIOCADDRT, &rt6) && errno != EEXIST) {
+ count = SYSTEM_ERROR;
+ break;
+ }
+ }
} else {
// Add an IPv4 route.
if (inet_pton(AF_INET, address, as_in_addr(&rt4.rt_dst)) != 1 ||
- prefix < 1 || prefix > 32) {
+ prefix < 0 || prefix > 32) {
count = BAD_ARGUMENT;
break;
}
- in_addr_t mask = prefix ? (~0 << (32 - prefix)) : 0;
+ in_addr_t mask = prefix ? (~0 << (32 - prefix)) : 0x80000000;
*as_in_addr(&rt4.rt_genmask) = htonl(mask);
if (ioctl(inet4, SIOCADDRT, &rt4) && errno != EEXIST) {
count = (errno == EINVAL) ? BAD_ARGUMENT : SYSTEM_ERROR;
break;
}
+
+ if (!prefix) {
+ // Split the route instead of replacing the default route.
+ *as_in_addr(&rt4.rt_dst) ^= htonl(0x80000000);
+ if (ioctl(inet4, SIOCADDRT, &rt4) && errno != EEXIST) {
+ count = SYSTEM_ERROR;
+ break;
+ }
+ }
}
- LOGV("Route added on %s: %s/%d", name, address, prefix);
+ LOGD("Route added on %s: %s/%d", name, address, prefix);
++count;
}
@@ -250,43 +274,24 @@ static int set_routes(const char *name, int index, const char *routes)
count = BAD_ARGUMENT;
}
- close(inet4);
- close(inet6);
return count;
}
-static int get_interface_name(char *name, int tun)
-{
- ifreq ifr4;
- if (ioctl(tun, TUNGETIFF, &ifr4)) {
- LOGE("Cannot get interface name: %s", strerror(errno));
- return SYSTEM_ERROR;
- }
- strcpy(name, ifr4.ifr_name);
- return 0;
-}
-
static int reset_interface(const char *name)
{
- int inet4 = socket(AF_INET, SOCK_DGRAM, 0);
-
ifreq ifr4;
- ifr4.ifr_flags = 0;
strncpy(ifr4.ifr_name, name, IFNAMSIZ);
+ ifr4.ifr_flags = 0;
if (ioctl(inet4, SIOCSIFFLAGS, &ifr4) && errno != ENODEV) {
LOGE("Cannot reset %s: %s", name, strerror(errno));
- close(inet4);
return SYSTEM_ERROR;
}
- close(inet4);
return 0;
}
static int check_interface(const char *name)
{
- int inet4 = socket(AF_INET, SOCK_DGRAM, 0);
-
ifreq ifr4;
strncpy(ifr4.ifr_name, name, IFNAMSIZ);
ifr4.ifr_flags = 0;
@@ -294,7 +299,6 @@ static int check_interface(const char *name)
if (ioctl(inet4, SIOCGIFFLAGS, &ifr4) && errno != ENODEV) {
LOGE("Cannot check %s: %s", name, strerror(errno));
}
- close(inet4);
return ifr4.ifr_flags;
}
@@ -318,86 +322,108 @@ static void throwException(JNIEnv *env, int error, const char *message)
}
}
-static jint establish(JNIEnv *env, jobject thiz,
- jint mtu, jstring jAddresses, jstring jRoutes)
+static jint createInterface(JNIEnv *env, jobject thiz, jint mtu)
{
- char name[IFNAMSIZ];
- int index;
- int tun = create_interface(mtu, name, &index);
+ int tun = create_interface(mtu);
if (tun < 0) {
throwException(env, tun, "Cannot create interface");
return -1;
}
- LOGD("%s is created", name);
+ return tun;
+}
- const char *addresses;
- const char *routes;
- int count;
+static jstring getInterfaceName(JNIEnv *env, jobject thiz, jint tun)
+{
+ char name[IFNAMSIZ];
+ if (get_interface_name(name, tun) < 0) {
+ throwException(env, SYSTEM_ERROR, "Cannot get interface name");
+ return NULL;
+ }
+ return env->NewStringUTF(name);
+}
- // Addresses are required.
+static jint setAddresses(JNIEnv *env, jobject thiz, jstring jName,
+ jstring jAddresses)
+{
+ const char *name = NULL;
+ const char *addresses = NULL;
+ int count = -1;
+
+ name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
+ if (!name) {
+ jniThrowNullPointerException(env, "name");
+ goto error;
+ }
addresses = jAddresses ? env->GetStringUTFChars(jAddresses, NULL) : NULL;
if (!addresses) {
- jniThrowNullPointerException(env, "address");
+ jniThrowNullPointerException(env, "addresses");
goto error;
}
- count = set_addresses(name, index, addresses);
- env->ReleaseStringUTFChars(jAddresses, addresses);
- if (count <= 0) {
+ count = set_addresses(name, addresses);
+ if (count < 0) {
throwException(env, count, "Cannot set address");
- goto error;
+ count = -1;
}
- LOGD("Configured %d address(es) on %s", count, name);
-
- // Routes are optional.
- routes = jRoutes ? env->GetStringUTFChars(jRoutes, NULL) : NULL;
- if (routes) {
- count = set_routes(name, index, routes);
- env->ReleaseStringUTFChars(jRoutes, routes);
- if (count < 0) {
- throwException(env, count, "Cannot set route");
- goto error;
- }
- LOGD("Configured %d route(s) on %s", count, name);
- }
-
- return tun;
error:
- close(tun);
- LOGD("%s is destroyed", name);
- return -1;
+ if (name) {
+ env->ReleaseStringUTFChars(jName, name);
+ }
+ if (addresses) {
+ env->ReleaseStringUTFChars(jAddresses, addresses);
+ }
+ return count;
}
-static jstring getName(JNIEnv *env, jobject thiz, jint fd)
+static jint setRoutes(JNIEnv *env, jobject thiz, jstring jName,
+ jstring jRoutes)
{
- char name[IFNAMSIZ];
- if (get_interface_name(name, fd) < 0) {
- throwException(env, SYSTEM_ERROR, "Cannot get interface name");
- return NULL;
+ const char *name = NULL;
+ const char *routes = NULL;
+ int count = -1;
+
+ name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
+ if (!name) {
+ jniThrowNullPointerException(env, "name");
+ goto error;
}
- return env->NewStringUTF(name);
+ routes = jRoutes ? env->GetStringUTFChars(jRoutes, NULL) : NULL;
+ if (!routes) {
+ jniThrowNullPointerException(env, "routes");
+ goto error;
+ }
+ count = set_routes(name, routes);
+ if (count < 0) {
+ throwException(env, count, "Cannot set route");
+ count = -1;
+ }
+
+error:
+ if (name) {
+ env->ReleaseStringUTFChars(jName, name);
+ }
+ if (routes) {
+ env->ReleaseStringUTFChars(jRoutes, routes);
+ }
+ return count;
}
-static void reset(JNIEnv *env, jobject thiz, jstring jName)
+static void resetInterface(JNIEnv *env, jobject thiz, jstring jName)
{
- const char *name = jName ?
- env->GetStringUTFChars(jName, NULL) : NULL;
+ const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
if (!name) {
jniThrowNullPointerException(env, "name");
return;
}
if (reset_interface(name) < 0) {
throwException(env, SYSTEM_ERROR, "Cannot reset interface");
- } else {
- LOGD("%s is deactivated", name);
}
env->ReleaseStringUTFChars(jName, name);
}
-static jint check(JNIEnv *env, jobject thiz, jstring jName)
+static jint checkInterface(JNIEnv *env, jobject thiz, jstring jName)
{
- const char *name = jName ?
- env->GetStringUTFChars(jName, NULL) : NULL;
+ const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
if (!name) {
jniThrowNullPointerException(env, "name");
return 0;
@@ -407,10 +433,9 @@ static jint check(JNIEnv *env, jobject thiz, jstring jName)
return flags;
}
-static void protect(JNIEnv *env, jobject thiz, jint fd, jstring jName)
+static void protectSocket(JNIEnv *env, jobject thiz, jint fd, jstring jName)
{
- const char *name = jName ?
- env->GetStringUTFChars(jName, NULL) : NULL;
+ const char *name = jName ? env->GetStringUTFChars(jName, NULL) : NULL;
if (!name) {
jniThrowNullPointerException(env, "name");
return;
@@ -424,15 +449,23 @@ static void protect(JNIEnv *env, jobject thiz, jint fd, jstring jName)
//------------------------------------------------------------------------------
static JNINativeMethod gMethods[] = {
- {"nativeEstablish", "(ILjava/lang/String;Ljava/lang/String;)I", (void *)establish},
- {"nativeGetName", "(I)Ljava/lang/String;", (void *)getName},
- {"nativeReset", "(Ljava/lang/String;)V", (void *)reset},
- {"nativeCheck", "(Ljava/lang/String;)I", (void *)check},
- {"nativeProtect", "(ILjava/lang/String;)V", (void *)protect},
+ {"jniCreateInterface", "(I)I", (void *)createInterface},
+ {"jniGetInterfaceName", "(I)Ljava/lang/String;", (void *)getInterfaceName},
+ {"jniSetAddresses", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setAddresses},
+ {"jniSetRoutes", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setRoutes},
+ {"jniResetInterface", "(Ljava/lang/String;)V", (void *)resetInterface},
+ {"jniCheckInterface", "(Ljava/lang/String;)I", (void *)checkInterface},
+ {"jniProtectSocket", "(ILjava/lang/String;)V", (void *)protectSocket},
};
int register_android_server_connectivity_Vpn(JNIEnv *env)
{
+ if (inet4 == -1) {
+ inet4 = socket(AF_INET, SOCK_DGRAM, 0);
+ }
+ if (inet6 == -1) {
+ inet6 = socket(AF_INET6, SOCK_DGRAM, 0);
+ }
return jniRegisterNativeMethods(env, "com/android/server/connectivity/Vpn",
gMethods, NELEM(gMethods));
}
diff --git a/services/jni/com_android_server_location_GpsLocationProvider.cpp b/services/jni/com_android_server_location_GpsLocationProvider.cpp
index 6d4ad9ac4a88..87ffcba240da 100755
--- a/services/jni/com_android_server_location_GpsLocationProvider.cpp
+++ b/services/jni/com_android_server_location_GpsLocationProvider.cpp
@@ -42,6 +42,7 @@ static jmethodID method_xtraDownloadRequest;
static jmethodID method_reportNiNotification;
static jmethodID method_requestRefLocation;
static jmethodID method_requestSetID;
+static jmethodID method_requestUtcTime;
static const GpsInterface* sGpsInterface = NULL;
static const GpsXtraInterface* sGpsXtraInterface = NULL;
@@ -122,6 +123,13 @@ static void release_wakelock_callback()
release_wake_lock(WAKE_LOCK_NAME);
}
+static void request_utc_time_callback()
+{
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ env->CallVoidMethod(mCallbacksObj, method_requestUtcTime);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
static pthread_t create_thread_callback(const char* name, void (*start)(void *), void* arg)
{
return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg);
@@ -137,6 +145,7 @@ GpsCallbacks sGpsCallbacks = {
acquire_wakelock_callback,
release_wakelock_callback,
create_thread_callback,
+ request_utc_time_callback,
};
static void xtra_download_request_callback()
@@ -232,6 +241,7 @@ static void android_location_GpsLocationProvider_class_init_native(JNIEnv* env,
"(IIIIILjava/lang/String;Ljava/lang/String;IILjava/lang/String;)V");
method_requestRefLocation = env->GetMethodID(clazz,"requestRefLocation","(I)V");
method_requestSetID = env->GetMethodID(clazz,"requestSetID","(I)V");
+ method_requestUtcTime = env->GetMethodID(clazz,"requestUtcTime","()V");
err = hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
if (err == 0) {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f0b19f26e93e..685613efef09 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -78,7 +78,6 @@ const String16 sDump("android.permission.DUMP");
SurfaceFlinger::SurfaceFlinger()
: BnSurfaceComposer(), Thread(false),
mTransactionFlags(0),
- mTransactionCount(0),
mResizeTransationPending(false),
mLayersRemoved(false),
mBootTime(systemTime()),
@@ -385,13 +384,11 @@ bool SurfaceFlinger::threadLoop()
handleConsoleEvents();
}
- if (LIKELY(mTransactionCount == 0)) {
- // if we're in a global transaction, don't do anything.
- const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
- uint32_t transactionFlags = peekTransactionFlags(mask);
- if (LIKELY(transactionFlags)) {
- handleTransaction(transactionFlags);
- }
+ // if we're in a global transaction, don't do anything.
+ const uint32_t mask = eTransactionNeeded | eTraversalNeeded;
+ uint32_t transactionFlags = peekTransactionFlags(mask);
+ if (UNLIKELY(transactionFlags)) {
+ handleTransaction(transactionFlags);
}
// post surfaces (if needed)
@@ -1176,28 +1173,33 @@ uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags)
return old;
}
-void SurfaceFlinger::openGlobalTransaction()
-{
- android_atomic_inc(&mTransactionCount);
-}
-void SurfaceFlinger::closeGlobalTransaction()
-{
- if (android_atomic_dec(&mTransactionCount) == 1) {
- signalEvent();
+void SurfaceFlinger::setTransactionState(const Vector<ComposerState>& state) {
+ Mutex::Autolock _l(mStateLock);
- // if there is a transaction with a resize, wait for it to
- // take effect before returning.
- Mutex::Autolock _l(mStateLock);
- while (mResizeTransationPending) {
- status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
- if (CC_UNLIKELY(err != NO_ERROR)) {
- // just in case something goes wrong in SF, return to the
- // called after a few seconds.
- LOGW_IF(err == TIMED_OUT, "closeGlobalTransaction timed out!");
- mResizeTransationPending = false;
- break;
- }
+ uint32_t flags = 0;
+ const size_t count = state.size();
+ for (size_t i=0 ; i<count ; i++) {
+ const ComposerState& s(state[i]);
+ sp<Client> client( static_cast<Client *>(s.client.get()) );
+ flags |= setClientStateLocked(client, s.state);
+ }
+ if (flags) {
+ setTransactionFlags(flags);
+ }
+
+ signalEvent();
+
+ // if there is a transaction with a resize, wait for it to
+ // take effect before returning.
+ while (mResizeTransationPending) {
+ status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
+ if (CC_UNLIKELY(err != NO_ERROR)) {
+ // just in case something goes wrong in SF, return to the
+ // called after a few seconds.
+ LOGW_IF(err == TIMED_OUT, "closeGlobalTransaction timed out!");
+ mResizeTransationPending = false;
+ break;
}
}
}
@@ -1393,60 +1395,52 @@ status_t SurfaceFlinger::destroySurface(const wp<LayerBaseClient>& layer)
return err;
}
-status_t SurfaceFlinger::setClientState(
+uint32_t SurfaceFlinger::setClientStateLocked(
const sp<Client>& client,
- int32_t count,
- const layer_state_t* states)
+ const layer_state_t& s)
{
- Mutex::Autolock _l(mStateLock);
uint32_t flags = 0;
- for (int i=0 ; i<count ; i++) {
- const layer_state_t& s(states[i]);
- sp<LayerBaseClient> layer(client->getLayerUser(s.surface));
- if (layer != 0) {
- const uint32_t what = s.what;
- if (what & ePositionChanged) {
- if (layer->setPosition(s.x, s.y))
- flags |= eTraversalNeeded;
- }
- if (what & eLayerChanged) {
- ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
- if (layer->setLayer(s.z)) {
- mCurrentState.layersSortedByZ.removeAt(idx);
- mCurrentState.layersSortedByZ.add(layer);
- // we need traversal (state changed)
- // AND transaction (list changed)
- flags |= eTransactionNeeded|eTraversalNeeded;
- }
- }
- if (what & eSizeChanged) {
- if (layer->setSize(s.w, s.h)) {
- flags |= eTraversalNeeded;
- mResizeTransationPending = true;
- }
- }
- if (what & eAlphaChanged) {
- if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f)))
- flags |= eTraversalNeeded;
- }
- if (what & eMatrixChanged) {
- if (layer->setMatrix(s.matrix))
- flags |= eTraversalNeeded;
- }
- if (what & eTransparentRegionChanged) {
- if (layer->setTransparentRegionHint(s.transparentRegion))
- flags |= eTraversalNeeded;
+ sp<LayerBaseClient> layer(client->getLayerUser(s.surface));
+ if (layer != 0) {
+ const uint32_t what = s.what;
+ if (what & ePositionChanged) {
+ if (layer->setPosition(s.x, s.y))
+ flags |= eTraversalNeeded;
+ }
+ if (what & eLayerChanged) {
+ ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
+ if (layer->setLayer(s.z)) {
+ mCurrentState.layersSortedByZ.removeAt(idx);
+ mCurrentState.layersSortedByZ.add(layer);
+ // we need traversal (state changed)
+ // AND transaction (list changed)
+ flags |= eTransactionNeeded|eTraversalNeeded;
}
- if (what & eVisibilityChanged) {
- if (layer->setFlags(s.flags, s.mask))
- flags |= eTraversalNeeded;
+ }
+ if (what & eSizeChanged) {
+ if (layer->setSize(s.w, s.h)) {
+ flags |= eTraversalNeeded;
+ mResizeTransationPending = true;
}
}
+ if (what & eAlphaChanged) {
+ if (layer->setAlpha(uint8_t(255.0f*s.alpha+0.5f)))
+ flags |= eTraversalNeeded;
+ }
+ if (what & eMatrixChanged) {
+ if (layer->setMatrix(s.matrix))
+ flags |= eTraversalNeeded;
+ }
+ if (what & eTransparentRegionChanged) {
+ if (layer->setTransparentRegionHint(s.transparentRegion))
+ flags |= eTraversalNeeded;
+ }
+ if (what & eVisibilityChanged) {
+ if (layer->setFlags(s.flags, s.mask))
+ flags |= eTraversalNeeded;
+ }
}
- if (flags) {
- setTransactionFlags(flags);
- }
- return NO_ERROR;
+ return flags;
}
void SurfaceFlinger::screenReleased(int dpy)
@@ -1588,8 +1582,7 @@ status_t SurfaceFlinger::onTransact(
{
switch (code) {
case CREATE_CONNECTION:
- case OPEN_GLOBAL_TRANSACTION:
- case CLOSE_GLOBAL_TRANSACTION:
+ case SET_TRANSACTION_STATE:
case SET_ORIENTATION:
case FREEZE_DISPLAY:
case UNFREEZE_DISPLAY:
@@ -1806,10 +1799,10 @@ status_t SurfaceFlinger::electronBeamOffAnimationImplLocked()
const GLfloat h = hw_h - (hw_h * v);
const GLfloat x = (hw_w - w) * 0.5f;
const GLfloat y = (hw_h - h) * 0.5f;
- vtx[0] = x; vtx[1] = y;
- vtx[2] = x; vtx[3] = y + h;
- vtx[4] = x + w; vtx[5] = y + h;
- vtx[6] = x + w; vtx[7] = y;
+ vtx[0] = x; vtx[1] = y + h;
+ vtx[2] = x; vtx[3] = y;
+ vtx[4] = x + w; vtx[5] = y;
+ vtx[6] = x + w; vtx[7] = y + h;
}
};
@@ -1824,10 +1817,10 @@ status_t SurfaceFlinger::electronBeamOffAnimationImplLocked()
const GLfloat h = 1.0f;
const GLfloat x = (hw_w - w) * 0.5f;
const GLfloat y = (hw_h - h) * 0.5f;
- vtx[0] = x; vtx[1] = y;
- vtx[2] = x; vtx[3] = y + h;
- vtx[4] = x + w; vtx[5] = y + h;
- vtx[6] = x + w; vtx[7] = y;
+ vtx[0] = x; vtx[1] = y + h;
+ vtx[2] = x; vtx[3] = y;
+ vtx[4] = x + w; vtx[5] = y;
+ vtx[6] = x + w; vtx[7] = y + h;
}
};
@@ -2469,9 +2462,6 @@ sp<ISurface> Client::createSurface(
status_t Client::destroySurface(SurfaceID sid) {
return mFlinger->removeSurface(this, sid);
}
-status_t Client::setState(int32_t count, const layer_state_t* states) {
- return mFlinger->setClientState(this, count, states);
-}
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 45f80aedc24a..b49fa363e62f 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -70,14 +70,12 @@ public:
sp<LayerBaseClient> getLayerUser(int32_t i) const;
private:
-
// ISurfaceComposerClient interface
virtual sp<ISurface> createSurface(
surface_data_t* params, const String8& name,
DisplayID display, uint32_t w, uint32_t h,PixelFormat format,
uint32_t flags);
virtual status_t destroySurface(SurfaceID surfaceId);
- virtual status_t setState(int32_t count, const layer_state_t* states);
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
@@ -168,8 +166,7 @@ public:
virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc();
virtual sp<IMemoryHeap> getCblk() const;
virtual void bootFinished();
- virtual void openGlobalTransaction();
- virtual void closeGlobalTransaction();
+ virtual void setTransactionState(const Vector<ComposerState>& state);
virtual status_t freezeDisplay(DisplayID dpy, uint32_t flags);
virtual status_t unfreezeDisplay(DisplayID dpy, uint32_t flags);
virtual int setOrientation(DisplayID dpy, int orientation, uint32_t flags);
@@ -220,8 +217,7 @@ private:
status_t removeSurface(const sp<Client>& client, SurfaceID sid);
status_t destroySurface(const wp<LayerBaseClient>& layer);
- status_t setClientState(const sp<Client>& client,
- int32_t count, const layer_state_t* states);
+ uint32_t setClientStateLocked(const sp<Client>& client, const layer_state_t& s);
class LayerVector : public SortedVector< sp<LayerBase> > {
public:
@@ -337,7 +333,6 @@ private:
mutable Mutex mStateLock;
State mCurrentState;
volatile int32_t mTransactionFlags;
- volatile int32_t mTransactionCount;
Condition mTransactionCV;
SortedVector< sp<LayerBase> > mLayerPurgatory;
bool mResizeTransationPending;
diff --git a/services/surfaceflinger/tests/resize/resize.cpp b/services/surfaceflinger/tests/resize/resize.cpp
index 18c54b3f8419..56b2a8f1cb03 100644
--- a/services/surfaceflinger/tests/resize/resize.cpp
+++ b/services/surfaceflinger/tests/resize/resize.cpp
@@ -43,9 +43,9 @@ int main(int argc, char** argv)
PIXEL_FORMAT_RGB_565);
- client->openTransaction();
+ SurfaceComposerClient::openGlobalTransaction();
surface->setLayer(100000);
- client->closeTransaction();
+ SurfaceComposerClient::closeGlobalTransaction();
Surface::SurfaceInfo info;
surface->lock(&info);
@@ -57,9 +57,9 @@ int main(int argc, char** argv)
android_memset16((uint16_t*)info.bits, 0x07E0, bpr*info.h);
surface->unlockAndPost();
- client->openTransaction();
+ SurfaceComposerClient::openGlobalTransaction();
surface->setSize(320, 240);
- client->closeTransaction();
+ SurfaceComposerClient::closeGlobalTransaction();
IPCThreadState::self()->joinThreadPool();
diff --git a/services/surfaceflinger/tests/surface/surface.cpp b/services/surfaceflinger/tests/surface/surface.cpp
index 5265f919536b..8e1c3fe322b4 100644
--- a/services/surfaceflinger/tests/surface/surface.cpp
+++ b/services/surfaceflinger/tests/surface/surface.cpp
@@ -39,9 +39,9 @@ int main(int argc, char** argv)
sp<SurfaceControl> surfaceControl = client->createSurface(
getpid(), 0, 160, 240, PIXEL_FORMAT_RGB_565);
- client->openTransaction();
+ SurfaceComposerClient::openGlobalTransaction();
surfaceControl->setLayer(100000);
- client->closeTransaction();
+ SurfaceComposerClient::closeGlobalTransaction();
// pretend it went cross-process
Parcel parcel;
diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
index 8b752ee47468..ac7cb5afd53a 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java
@@ -16,8 +16,8 @@
package com.android.server;
-import static dalvik.system.BlockGuard.kernelToTag;
-import static dalvik.system.BlockGuard.tagToKernel;
+import static com.android.server.NetworkManagementSocketTagger.kernelToTag;
+import static com.android.server.NetworkManagementSocketTagger.tagToKernel;
import android.content.res.Resources;
import android.net.NetworkStats;
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index 324e89600294..b4ac987fc541 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -56,6 +56,7 @@ import android.net.NetworkState;
import android.net.NetworkStats;
import android.net.NetworkTemplate;
import android.os.Binder;
+import android.os.INetworkManagementService;
import android.os.IPowerManager;
import android.test.AndroidTestCase;
import android.test.mock.MockPackageManager;
@@ -95,6 +96,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
private IActivityManager mActivityManager;
private IPowerManager mPowerManager;
private INetworkStatsService mStatsService;
+ private INetworkManagementService mNetworkManagement;
private INetworkPolicyListener mPolicyListener;
private TrustedTime mTime;
private IConnectivityManager mConnManager;
@@ -150,13 +152,15 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
mActivityManager = createMock(IActivityManager.class);
mPowerManager = createMock(IPowerManager.class);
mStatsService = createMock(INetworkStatsService.class);
+ mNetworkManagement = createMock(INetworkManagementService.class);
mPolicyListener = createMock(INetworkPolicyListener.class);
mTime = createMock(TrustedTime.class);
mConnManager = createMock(IConnectivityManager.class);
mNotifManager = createMock(INotificationManager.class);
mService = new NetworkPolicyManagerService(
- mServiceContext, mActivityManager, mPowerManager, mStatsService, mTime, mPolicyDir);
+ mServiceContext, mActivityManager, mPowerManager, mStatsService,
+ mNetworkManagement, mTime, mPolicyDir);
mService.bindConnectivityManager(mConnManager);
mService.bindNotificationManager(mNotifManager);
@@ -175,6 +179,9 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
expect(mPowerManager.isScreenOn()).andReturn(true).atLeastOnce();
expectTime(System.currentTimeMillis());
+ // default behavior is background data enabled
+ expect(mConnManager.getBackgroundDataSetting()).andReturn(true);
+
replay();
mService.systemReady();
verifyAndReset();
@@ -253,6 +260,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
public void testScreenChangesRules() throws Exception {
Future<Void> future;
+ expectSetUidNetworkRules(UID_A, false);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true);
@@ -260,6 +268,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
verifyAndReset();
// push strict policy for foreground uid, verify ALLOW rule
+ expectSetUidNetworkRules(UID_A, false);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
@@ -268,6 +277,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
// now turn screen off and verify REJECT rule
expect(mPowerManager.isScreenOn()).andReturn(false).atLeastOnce();
+ expectSetUidNetworkRules(UID_A, true);
future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
replay();
mServiceContext.sendBroadcast(new Intent(Intent.ACTION_SCREEN_OFF));
@@ -276,6 +286,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
// and turn screen back on, verify ALLOW rule restored
expect(mPowerManager.isScreenOn()).andReturn(true).atLeastOnce();
+ expectSetUidNetworkRules(UID_A, false);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
mServiceContext.sendBroadcast(new Intent(Intent.ACTION_SCREEN_ON));
@@ -286,6 +297,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
public void testPolicyNone() throws Exception {
Future<Void> future;
+ expectSetUidNetworkRules(UID_A, false);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true);
@@ -293,6 +305,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
verifyAndReset();
// POLICY_NONE should RULE_ALLOW in foreground
+ expectSetUidNetworkRules(UID_A, false);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
mService.setUidPolicy(UID_A, POLICY_NONE);
@@ -300,6 +313,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
verifyAndReset();
// POLICY_NONE should RULE_ALLOW in background
+ expectSetUidNetworkRules(UID_A, false);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
@@ -311,6 +325,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
Future<Void> future;
// POLICY_REJECT should RULE_ALLOW in background
+ expectSetUidNetworkRules(UID_A, true);
future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
replay();
mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
@@ -318,6 +333,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
verifyAndReset();
// POLICY_REJECT should RULE_ALLOW in foreground
+ expectSetUidNetworkRules(UID_A, false);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, true);
@@ -325,6 +341,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
verifyAndReset();
// POLICY_REJECT should RULE_REJECT in background
+ expectSetUidNetworkRules(UID_A, true);
future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
replay();
mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
@@ -336,6 +353,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
Future<Void> future;
// POLICY_NONE should have RULE_ALLOW in background
+ expectSetUidNetworkRules(UID_A, false);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
mProcessObserver.onForegroundActivitiesChanged(PID_1, UID_A, false);
@@ -344,6 +362,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
verifyAndReset();
// adding POLICY_REJECT should cause RULE_REJECT
+ expectSetUidNetworkRules(UID_A, true);
future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
replay();
mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
@@ -351,6 +370,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
verifyAndReset();
// removing POLICY_REJECT should return us to RULE_ALLOW
+ expectSetUidNetworkRules(UID_A, false);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
mService.setUidPolicy(UID_A, POLICY_NONE);
@@ -431,8 +451,9 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, TIME_MAR_10))
.andReturn(stats).atLeastOnce();
- // expect that quota remaining should be 1536 bytes
- // TODO: write up NetworkManagementService mock
+ // TODO: consider making strongly ordered mock
+ expectRemoveInterfaceQuota(TEST_IFACE);
+ expectSetInterfaceQuota(TEST_IFACE, 1536L);
expectClearNotifications();
future = expectMeteredIfacesChanged(TEST_IFACE);
@@ -447,6 +468,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
Future<Void> future;
// POLICY_REJECT should RULE_REJECT in background
+ expectSetUidNetworkRules(UID_A, true);
future = expectRulesChanged(UID_A, RULE_REJECT_METERED);
replay();
mService.setUidPolicy(UID_A, POLICY_REJECT_METERED_BACKGROUND);
@@ -454,6 +476,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
verifyAndReset();
// uninstall should clear RULE_REJECT
+ expectSetUidNetworkRules(UID_A, false);
future = expectRulesChanged(UID_A, RULE_ALLOW_ALL);
replay();
final Intent intent = new Intent(ACTION_UID_REMOVED);
@@ -494,6 +517,22 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
expectLastCall().anyTimes();
}
+ private void expectSetInterfaceQuota(String iface, long quota) throws Exception {
+ mNetworkManagement.setInterfaceQuota(iface, quota);
+ expectLastCall().atLeastOnce();
+ }
+
+ private void expectRemoveInterfaceQuota(String iface) throws Exception {
+ mNetworkManagement.removeInterfaceQuota(iface);
+ expectLastCall().atLeastOnce();
+ }
+
+ private void expectSetUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces)
+ throws Exception {
+ mNetworkManagement.setUidNetworkRules(uid, rejectOnQuotaInterfaces);
+ expectLastCall().atLeastOnce();
+ }
+
private Future<Void> expectRulesChanged(int uid, int policy) throws Exception {
final FutureAnswer future = new FutureAnswer();
mPolicyListener.onUidRulesChanged(eq(uid), eq(policy));
@@ -526,14 +565,14 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase {
}
private void replay() {
- EasyMock.replay(mActivityManager, mPowerManager, mStatsService, mPolicyListener, mTime,
- mConnManager, mNotifManager);
+ EasyMock.replay(mActivityManager, mPowerManager, mStatsService, mPolicyListener,
+ mNetworkManagement, mTime, mConnManager, mNotifManager);
}
private void verifyAndReset() {
- EasyMock.verify(mActivityManager, mPowerManager, mStatsService, mPolicyListener, mTime,
- mConnManager, mNotifManager);
- EasyMock.reset(mActivityManager, mPowerManager, mStatsService, mPolicyListener, mTime,
- mConnManager, mNotifManager);
+ EasyMock.verify(mActivityManager, mPowerManager, mStatsService, mPolicyListener,
+ mNetworkManagement, mTime, mConnManager, mNotifManager);
+ EasyMock.reset(mActivityManager, mPowerManager, mStatsService, mPolicyListener,
+ mNetworkManagement, mTime, mConnManager, mNotifManager);
}
}
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
index 903f2b0b6f66..f2c28bb538c8 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
@@ -610,9 +610,6 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
mAlarmManager.setInexactRepeating(
eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), isA(PendingIntent.class));
expectLastCall().atLeastOnce();
-
- mNetManager.setBandwidthControlEnabled(true);
- expectLastCall().atLeastOnce();
}
private void expectNetworkState(NetworkState... state) throws Exception {
@@ -633,7 +630,6 @@ public class NetworkStatsServiceTest extends AndroidTestCase {
private void expectSettings(long persistThreshold, long bucketDuration, long maxHistory)
throws Exception {
- expect(mSettings.getEnabled()).andReturn(true).anyTimes();
expect(mSettings.getPollInterval()).andReturn(HOUR_IN_MILLIS).anyTimes();
expect(mSettings.getPersistThreshold()).andReturn(persistThreshold).anyTimes();
expect(mSettings.getNetworkBucketDuration()).andReturn(bucketDuration).anyTimes();
diff --git a/telephony/java/android/telephony/PhoneNumberFormattingTextWatcher.java b/telephony/java/android/telephony/PhoneNumberFormattingTextWatcher.java
index dea67f35bfde..ffabb7b6e72e 100644
--- a/telephony/java/android/telephony/PhoneNumberFormattingTextWatcher.java
+++ b/telephony/java/android/telephony/PhoneNumberFormattingTextWatcher.java
@@ -94,9 +94,6 @@ public class PhoneNumberFormattingTextWatcher implements TextWatcher {
*/
public PhoneNumberFormattingTextWatcher(String countryCode) {
if (countryCode == null) throw new IllegalArgumentException();
- // TODO: remove this once CountryDetector.detectCountry().getCountryIso() is fixed to always
- // return uppercase. Tracked at b/4941319.
- countryCode = countryCode.toUpperCase(Locale.ENGLISH);
mFormatter = PhoneNumberUtil.getInstance().getAsYouTypeFormatter(countryCode);
}
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index fce7cdc82440..2f010e57b161 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -473,8 +473,8 @@ public class ServiceState implements Parcelable {
+ " EmergOnly=" + mIsEmergencyOnly);
}
- public void setStateOutOfService() {
- mState = STATE_OUT_OF_SERVICE;
+ private void setNullState(int state) {
+ mState = state;
mRoaming = false;
mOperatorAlphaLong = null;
mOperatorAlphaShort = null;
@@ -491,23 +491,12 @@ public class ServiceState implements Parcelable {
mIsEmergencyOnly = false;
}
- // TODO - can't this be combined with the above method?
+ public void setStateOutOfService() {
+ setNullState(STATE_OUT_OF_SERVICE);
+ }
+
public void setStateOff() {
- mState = STATE_POWER_OFF;
- mRoaming = false;
- mOperatorAlphaLong = null;
- mOperatorAlphaShort = null;
- mOperatorNumeric = null;
- mIsManualNetworkSelection = false;
- mRadioTechnology = 0;
- mCssIndicator = false;
- mNetworkId = -1;
- mSystemId = -1;
- mCdmaRoamingIndicator = -1;
- mCdmaDefaultRoamingIndicator = -1;
- mCdmaEriIconIndex = -1;
- mCdmaEriIconMode = -1;
- mIsEmergencyOnly = false;
+ setNullState(STATE_POWER_OFF);
}
public void setState(int state) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 184d665d0579..66120a171dd9 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -191,10 +191,6 @@ public class TelephonyManager {
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
public String getDeviceId() {
- if (!isVoiceCapable()) {
- return null;
- }
-
try {
return getSubscriberInfo().getDeviceId();
} catch (RemoteException ex) {
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index ab93e2a90ea9..68e0045eda45 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -526,16 +526,6 @@ public class CallerInfo {
+ countryIso);
}
- // Temp workaround: The current libphonenumber library requires
- // the countryIso to be uppercase (e.g. "US") but the
- // detector.detectCountry().getCountryIso() call currently returns
- // "us". Passing "us" to util.parse() will just result in a
- // NumberParseException.
- // So force the countryIso to uppercase for now.
- // TODO: remove this once getCountryIso() is fixed to always
- // return uppercase.
- countryIso = countryIso.toUpperCase();
-
PhoneNumber pn = null;
try {
if (VDBG) Log.v(TAG, "parsing '" + number
diff --git a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
index 910905aa4543..aa7568b108f8 100644
--- a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
+++ b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
@@ -21,6 +21,7 @@ import android.net.LinkProperties;
import android.os.Bundle;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.telephony.ServiceState;
import android.telephony.TelephonyManager;
import android.util.Log;
@@ -55,8 +56,13 @@ public class DefaultPhoneNotifier implements PhoneNotifier {
}
public void notifyServiceState(Phone sender) {
+ ServiceState ss = sender.getServiceState();
+ if (ss == null) {
+ ss = new ServiceState();
+ ss.setStateOutOfService();
+ }
try {
- mRegistry.notifyServiceState(sender.getServiceState());
+ mRegistry.notifyServiceState(ss);
} catch (RemoteException ex) {
// system process is dead
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 5fc0bf9b51e2..a6b131a91106 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -556,6 +556,9 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
if (DBG) log("onDataConnectionAttached: start polling notify attached");
startNetStatPoll();
notifyDataConnection(Phone.REASON_DATA_ATTACHED);
+ } else {
+ // update APN availability so that APN can be enabled.
+ notifyDataAvailability(Phone.REASON_DATA_ATTACHED);
}
setupDataOnReadyApns(Phone.REASON_DATA_ATTACHED);
@@ -785,13 +788,13 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
Message msg = obtainMessage(EVENT_DISCONNECT_DONE, apnContext);
apnContext.getDataConnection().tearDown(apnContext.getReason(), msg);
apnContext.setState(State.DISCONNECTING);
- } else {
- // apn is connected but no reference to dcac.
- // Should not be happen, but reset the state in case.
- apnContext.setState(State.IDLE);
- mPhone.notifyDataConnection(apnContext.getReason(),
- apnContext.getApnType());
}
+ } else {
+ // apn is connected but no reference to dcac.
+ // Should not be happen, but reset the state in case.
+ apnContext.setState(State.IDLE);
+ mPhone.notifyDataConnection(apnContext.getReason(),
+ apnContext.getApnType());
}
}
} else {
@@ -1528,13 +1531,16 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
createAllApnList();
if (mRadioAvailable) {
if (DBG) log("onRecordsLoaded: notifying data availability");
- notifyDataAvailability(null);
+ notifyDataAvailability(Phone.REASON_SIM_LOADED);
}
setupDataOnReadyApns(Phone.REASON_SIM_LOADED);
}
@Override
protected void onSetDependencyMet(String apnType, boolean met) {
+ // don't allow users to tweak hipri to work around default dependency not met
+ if (Phone.APN_TYPE_HIPRI.equals(apnType)) return;
+
ApnContext apnContext = mApnContexts.get(apnType);
if (apnContext == null) {
loge("onSetDependencyMet: ApnContext not found in onSetDependencyMet(" +
@@ -1542,6 +1548,11 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
return;
}
applyNewState(apnContext, apnContext.isEnabled(), met);
+ if (Phone.APN_TYPE_DEFAULT.equals(apnType)) {
+ // tie actions on default to similar actions on HIPRI regarding dependencyMet
+ apnContext = mApnContexts.get(Phone.APN_TYPE_HIPRI);
+ if (apnContext != null) applyNewState(apnContext, apnContext.isEnabled(), met);
+ }
}
private void applyNewState(ApnContext apnContext, boolean enabled, boolean met) {
@@ -1627,11 +1638,17 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
@Override
protected void onRoamingOff() {
if (DBG) log("onRoamingOff");
+ // Notify data availability so APN can be enabled.
+ notifyDataAvailability(Phone.REASON_ROAMING_OFF);
+
setupDataOnReadyApns(Phone.REASON_ROAMING_OFF);
}
@Override
protected void onRoamingOn() {
+ // Notify data availability so APN can be enabled.
+ notifyDataAvailability(Phone.REASON_ROAMING_ON);
+
if (getDataOnRoamingEnabled()) {
if (DBG) log("onRoamingOn: setup data on roaming");
setupDataOnReadyApns(Phone.REASON_ROAMING_ON);
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
index c4a6f53dc34a..6e9d0f9da62d 100644
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
@@ -502,16 +502,17 @@ public class PhoneNumberUtilsTest extends AndroidTestCase {
@SmallTest
public void testFormatNumberToE164() {
- assertEquals("+16502910000", PhoneNumberUtils.formatNumberToE164("650 2910000", "us"));
- assertNull(PhoneNumberUtils.formatNumberToE164("1234567", "us"));
- assertEquals("+18004664114", PhoneNumberUtils.formatNumberToE164("800-GOOG-114", "us"));
+ // Note: ISO 3166-1 only allows upper case country codes.
+ assertEquals("+16502910000", PhoneNumberUtils.formatNumberToE164("650 2910000", "US"));
+ assertNull(PhoneNumberUtils.formatNumberToE164("1234567", "US"));
+ assertEquals("+18004664114", PhoneNumberUtils.formatNumberToE164("800-GOOG-114", "US"));
}
@SmallTest
public void testFormatNumber() {
- assertEquals("(650) 291-0000", PhoneNumberUtils.formatNumber("650 2910000", "us"));
- assertEquals("123-4567", PhoneNumberUtils.formatNumber("1234567", "us"));
- assertEquals("(800) 466-4114", PhoneNumberUtils.formatNumber("800-GOOG-114", "us"));
+ assertEquals("(650) 291-0000", PhoneNumberUtils.formatNumber("650 2910000", "US"));
+ assertEquals("123-4567", PhoneNumberUtils.formatNumber("1234567", "US"));
+ assertEquals("(800) 466-4114", PhoneNumberUtils.formatNumber("800-GOOG-114", "US"));
}
diff --git a/tests/GridLayoutTest/res/layout/grid3.xml b/tests/GridLayoutTest/res/layout/grid3.xml
index ba911c269e4e..536be7eefa03 100644
--- a/tests/GridLayoutTest/res/layout/grid3.xml
+++ b/tests/GridLayoutTest/res/layout/grid3.xml
@@ -66,8 +66,8 @@
<Space
android:layout_row="4"
android:layout_column="2"
- android:layout_rowWeight="1"
- android:layout_columnWeight="1"
+ android:layout_heightSpec="canStretch"
+ android:layout_widthSpec="canStretch"
/>
<Button
diff --git a/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java b/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
index e010a007529f..cba98c2b7538 100644
--- a/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
+++ b/tests/GridLayoutTest/src/com/android/test/layout/Activity2.java
@@ -97,8 +97,8 @@ public class Activity2 extends Activity {
Space v = new Space(context);
{
LayoutParams lp = new LayoutParams(row5, col3);
- lp.rowWeight = 1;
- lp.columnWeight = 1;
+ lp.widthSpec = CAN_STRETCH;
+ lp.heightSpec = CAN_STRETCH;
vg.addView(v, lp);
}
}
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 7aa0617a702a..873414338fd3 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -31,6 +31,15 @@
android:hardwareAccelerated="true">
<activity
+ android:name="TimeDialogActivity"
+ android:label="_TimeDialog">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <activity
android:name="OpaqueActivity"
android:label="_Opaque">
<intent-filter>
@@ -494,8 +503,7 @@
<activity
android:name="Animated3dActivity"
- android:label="_Animated 3d"
- android:theme="@android:style/Theme.Translucent.NoTitleBar">
+ android:label="_Animated 3d">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TimeDialogActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TimeDialogActivity.java
new file mode 100644
index 000000000000..9e3e950f0850
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TimeDialogActivity.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.app.TimePickerDialog;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.Button;
+import android.widget.FrameLayout;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class TimeDialogActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ FrameLayout layout = new FrameLayout(this);
+ Button b = new Button(this);
+ b.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT,
+ FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.CENTER));
+ b.setText("Show dialog");
+ b.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ new TimePickerDialog(TimeDialogActivity.this, null, 12, 12, true).show();
+ }
+ });
+ layout.addView(b);
+
+ setContentView(layout);
+ }
+}
diff --git a/tests/RenderScriptTests/PerfTest/AndroidManifest.xml b/tests/RenderScriptTests/PerfTest/AndroidManifest.xml
index aafd176838b9..cc6039685736 100644
--- a/tests/RenderScriptTests/PerfTest/AndroidManifest.xml
+++ b/tests/RenderScriptTests/PerfTest/AndroidManifest.xml
@@ -9,8 +9,7 @@
android:icon="@drawable/test_pattern">
<uses-library android:name="android.test.runner" />
<activity android:name="RsBench"
- android:label="RsBenchmark"
- android:theme="@android:style/Theme.Black.NoTitleBar">
+ android:label="RsBenchmark">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
diff --git a/tests/RenderScriptTests/PerfTest/res/menu/loader_menu.xml b/tests/RenderScriptTests/PerfTest/res/menu/loader_menu.xml
new file mode 100644
index 000000000000..823467758827
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/res/menu/loader_menu.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/benchmark_mode"
+ android:title="@string/benchmark_mode" />
+ <item android:id="@+id/debug_mode"
+ android:title="@string/debug_mode" />
+</menu>
diff --git a/tests/RenderScriptTests/PerfTest/res/values/strings.xml b/tests/RenderScriptTests/PerfTest/res/values/strings.xml
new file mode 100644
index 000000000000..627ac212db8d
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/res/values/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+* Copyright (C) 2011 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <skip />
+ <string name="benchmark_mode">Benchmark Mode</string>
+ <string name="debug_mode">Debug Mode</string>
+</resources>
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBench.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBench.java
index d7393f8065cd..b336a4d03550 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBench.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBench.java
@@ -31,10 +31,14 @@ import android.provider.Settings.System;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
+import android.view.MenuInflater;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.ListView;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.widget.Toast;
import java.lang.Runtime;
@@ -77,4 +81,37 @@ public class RsBench extends Activity {
super.onPause();
mView.pause();
}
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.loader_menu, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ // Handle item selection
+ switch (item.getItemId()) {
+ case R.id.benchmark_mode:
+ mView.setBenchmarkMode();
+ return true;
+ case R.id.debug_mode:
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle("Pick a Test");
+ builder.setItems(mView.getTestNames(),
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int item) {
+ Toast.makeText(getApplicationContext(),
+ "Switching to: " + mView.getTestNames()[item],
+ Toast.LENGTH_SHORT).show();
+ mView.setDebugMode(item);
+ }
+ });
+ builder.show();
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
}
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
index c706286df685..c375be5e58bc 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java
@@ -84,12 +84,6 @@ public class RsBenchRS {
private Resources mRes;
private RenderScriptGL mRS;
- private Sampler mLinearClamp;
- private Sampler mLinearWrap;
- private Sampler mMipLinearWrap;
- private Sampler mNearestClamp;
- private Sampler mNearesWrap;
-
private ProgramStore mProgStoreBlendNoneDepth;
private ProgramStore mProgStoreBlendNone;
private ProgramStore mProgStoreBlendAlpha;
@@ -115,10 +109,6 @@ public class RsBenchRS {
private ScriptField_FragentShaderConstants3_s mFSConstPixel;
- private ProgramRaster mCullBack;
- private ProgramRaster mCullFront;
- private ProgramRaster mCullNone;
-
private Allocation mTexTorus;
private Allocation mTexOpaque;
private Allocation mTexTransparent;
@@ -143,6 +133,8 @@ public class RsBenchRS {
private ScriptC_rsbench mScript;
+ private ScriptC_text_test mTextScript;
+ private ScriptC_torus_test mTorusScript;
private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options();
@@ -310,6 +302,7 @@ public class RsBenchRS {
mProgStoreBlendAdd = BLEND_ADD_DEPTH_NONE(mRS);
mScript.set_gProgStoreBlendNoneDepth(mProgStoreBlendNoneDepth);
+
mScript.set_gProgStoreBlendNone(mProgStoreBlendNone);
mScript.set_gProgStoreBlendAlpha(mProgStoreBlendAlpha);
mScript.set_gProgStoreBlendAdd(mProgStoreBlendAdd);
@@ -330,22 +323,24 @@ public class RsBenchRS {
texBuilder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
mProgFragmentTexture = texBuilder.create();
- mProgFragmentTexture.bindSampler(mLinearClamp, 0);
+ mProgFragmentTexture.bindSampler(Sampler.CLAMP_LINEAR(mRS), 0);
ProgramFragmentFixedFunction.Builder colBuilder = new ProgramFragmentFixedFunction.Builder(mRS);
colBuilder.setVaryingColor(false);
mProgFragmentColor = colBuilder.create();
mScript.set_gProgFragmentColor(mProgFragmentColor);
+
mScript.set_gProgFragmentTexture(mProgFragmentTexture);
+
// For Galaxy live wallpaper drawing
ProgramFragmentFixedFunction.Builder builder = new ProgramFragmentFixedFunction.Builder(mRS);
builder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
ProgramFragmentFixedFunction.Builder.Format.RGB, 0);
ProgramFragment pfb = builder.create();
- pfb.bindSampler(mNearesWrap, 0);
+ pfb.bindSampler(Sampler.WRAP_NEAREST(mRS), 0);
mScript.set_gPFBackground(pfb);
builder = new ProgramFragmentFixedFunction.Builder(mRS);
@@ -354,7 +349,7 @@ public class RsBenchRS {
ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
builder.setVaryingColor(true);
ProgramFragment pfs = builder.create();
- pfs.bindSampler(mMipLinearWrap, 0);
+ pfs.bindSampler(Sampler.WRAP_LINEAR_MIP_LINEAR(mRS), 0);
mScript.set_gPFStars(pfs);
}
@@ -404,6 +399,7 @@ public class RsBenchRS {
mScript.set_gProgVertex(mProgVertex);
+
// For galaxy live wallpaper
mPvStarAlloc = new ScriptField_VpConsts(mRS, 1);
mScript.bind_vpConstants(mPvStarAlloc);
@@ -447,13 +443,11 @@ public class RsBenchRS {
private void initCustomShaders() {
mVSConst = new ScriptField_VertexShaderConstants_s(mRS, 1);
mFSConst = new ScriptField_FragentShaderConstants_s(mRS, 1);
- mScript.bind_gVSConstants(mVSConst);
- mScript.bind_gFSConstants(mFSConst);
+
mVSConstPixel = new ScriptField_VertexShaderConstants3_s(mRS, 1);
mFSConstPixel = new ScriptField_FragentShaderConstants3_s(mRS, 1);
- mScript.bind_gVSConstPixel(mVSConstPixel);
- mScript.bind_gFSConstPixel(mFSConstPixel);
+
// Initialize the shader builder
ProgramVertex.Builder pvbCustom = new ProgramVertex.Builder(mRS);
@@ -506,11 +500,7 @@ public class RsBenchRS {
}
mProgFragmentMultitex = pfbCustom.create();
- mScript.set_gProgVertexCustom(mProgVertexCustom);
- mScript.set_gProgFragmentCustom(mProgFragmentCustom);
- mScript.set_gProgVertexPixelLight(mProgVertexPixelLight);
- mScript.set_gProgVertexPixelLightMove(mProgVertexPixelLightMove);
- mScript.set_gProgFragmentPixelLight(mProgFragmentPixelLight);
+
mScript.set_gProgFragmentMultitex(mProgFragmentMultitex);
}
@@ -587,39 +577,22 @@ public class RsBenchRS {
Log.e("rs", "could not load model");
} else {
mTorus = (Mesh)entry.getObject();
- mScript.set_gTorusMesh(mTorus);
}
createParticlesMesh();
}
private void initSamplers() {
- Sampler.Builder bs = new Sampler.Builder(mRS);
- bs.setMinification(Sampler.Value.LINEAR);
- bs.setMagnification(Sampler.Value.LINEAR);
- bs.setWrapS(Sampler.Value.WRAP);
- bs.setWrapT(Sampler.Value.WRAP);
- mLinearWrap = bs.create();
-
- mLinearClamp = Sampler.CLAMP_LINEAR(mRS);
- mNearestClamp = Sampler.CLAMP_NEAREST(mRS);
- mMipLinearWrap = Sampler.WRAP_LINEAR_MIP_LINEAR(mRS);
- mNearesWrap = Sampler.WRAP_NEAREST(mRS);
-
- mScript.set_gLinearClamp(mLinearClamp);
- mScript.set_gLinearWrap(mLinearWrap);
- mScript.set_gMipLinearWrap(mMipLinearWrap);
- mScript.set_gNearestClamp(mNearestClamp);
+ mScript.set_gLinearClamp(Sampler.CLAMP_LINEAR(mRS));
+ mScript.set_gLinearWrap(Sampler.WRAP_LINEAR(mRS));
+ mScript.set_gMipLinearWrap(Sampler.WRAP_LINEAR_MIP_LINEAR(mRS));
+ mScript.set_gNearestClamp(Sampler.CLAMP_NEAREST(mRS));
}
private void initProgramRaster() {
- mCullBack = ProgramRaster.CULL_BACK(mRS);
- mCullFront = ProgramRaster.CULL_FRONT(mRS);
- mCullNone = ProgramRaster.CULL_NONE(mRS);
-
- mScript.set_gCullBack(mCullBack);
- mScript.set_gCullFront(mCullFront);
- mScript.set_gCullNone(mCullNone);
+ mScript.set_gCullBack(ProgramRaster.CULL_BACK(mRS));
+ mScript.set_gCullFront(ProgramRaster.CULL_FRONT(mRS));
+ mScript.set_gCullNone(ProgramRaster.CULL_NONE(mRS));
}
private int strlen(byte[] array) {
@@ -645,9 +618,47 @@ public class RsBenchRS {
}
}
+ public void setDebugMode(int num) {
+ mScript.invoke_setDebugMode(num);
+ }
+
+ public void setBenchmarkMode() {
+ mScript.invoke_setBenchmarkMode();
+ }
+
+ void initTextScript() {
+ mTextScript = new ScriptC_text_test(mRS, mRes, R.raw.text_test);
+ mTextScript.set_gFontSans(mFontSans);
+ mTextScript.set_gFontSerif(mFontSerif);
+ }
+
+ void initTorusScript() {
+ mTorusScript = new ScriptC_torus_test(mRS, mRes, R.raw.torus_test);
+ mTorusScript.set_gCullFront(ProgramRaster.CULL_FRONT(mRS));
+ mTorusScript.set_gCullBack(ProgramRaster.CULL_BACK(mRS));
+ mTorusScript.set_gLinearClamp(Sampler.CLAMP_LINEAR(mRS));
+ mTorusScript.set_gTorusMesh(mTorus);
+ mTorusScript.set_gTexTorus(mTexTorus);
+ mTorusScript.set_gProgVertexCustom(mProgVertexCustom);
+ mTorusScript.set_gProgFragmentCustom(mProgFragmentCustom);
+ mTorusScript.set_gProgVertexPixelLight(mProgVertexPixelLight);
+ mTorusScript.set_gProgVertexPixelLightMove(mProgVertexPixelLightMove);
+ mTorusScript.set_gProgFragmentPixelLight(mProgFragmentPixelLight);
+ mTorusScript.bind_gVSConstPixel(mVSConstPixel);
+ mTorusScript.bind_gFSConstPixel(mFSConstPixel);
+ mTorusScript.bind_gVSConstants(mVSConst);
+ mTorusScript.bind_gFSConstants(mFSConst);
+ mTorusScript.set_gProgVertex(mProgVertex);
+ mTorusScript.set_gProgFragmentTexture(mProgFragmentTexture);
+ mTorusScript.set_gProgFragmentColor(mProgFragmentColor);
+ mTorusScript.set_gProgStoreBlendNoneDepth(mProgStoreBlendNoneDepth);
+ }
+
private void initRS() {
mScript = new ScriptC_rsbench(mRS, mRes, R.raw.rsbench);
+
+
mRS.setMessageHandler(mRsMessage);
mMaxModes = mScript.get_gMaxModes();
@@ -709,6 +720,13 @@ public class RsBenchRS {
mSampleListViewAllocs.copyAll();
mScript.bind_gListViewText(mSampleListViewAllocs);
+ initTextScript();
+ initTorusScript();
+
+ mScript.set_gFontScript(mTextScript);
+ mScript.set_gTorusScript(mTorusScript);
+ mScript.set_gDummyAlloc(Allocation.createSized(mRS, Element.I32(mRS), 1));
+
mRS.bindRootScript(mScript);
}
}
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchView.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchView.java
index 2882b931c589..61aa3e129395 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchView.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchView.java
@@ -105,4 +105,16 @@ public class RsBenchView extends RSSurfaceView {
public boolean testIsFinished() {
return mRender.testIsFinished();
}
+
+ void setBenchmarkMode() {
+ mRender.setBenchmarkMode();
+ }
+
+ void setDebugMode(int num) {
+ mRender.setDebugMode(num);
+ }
+
+ String[] getTestNames() {
+ return mRender.mTestNames;
+ }
}
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
index bb81862e4e30..eaafe1db3d40 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs
@@ -18,6 +18,7 @@
#include "rs_graphics.rsh"
#include "shader_def.rsh"
+#include "subtest_def.rsh"
/* Message sent from script to renderscript */
const int RS_MSG_TEST_DONE = 100;
@@ -98,7 +99,6 @@ ListAllocs *gListViewText;
rs_mesh g10by10Mesh;
rs_mesh g100by100Mesh;
rs_mesh gWbyHMesh;
-rs_mesh gTorusMesh;
rs_mesh gSingleMesh;
rs_font gFontSans;
@@ -115,25 +115,15 @@ rs_program_raster gCullBack;
rs_program_raster gCullFront;
rs_program_raster gCullNone;
-// Custom vertex shader compunents
-VertexShaderConstants *gVSConstants;
-FragentShaderConstants *gFSConstants;
-VertexShaderConstants3 *gVSConstPixel;
-FragentShaderConstants3 *gFSConstPixel;
// Export these out to easily set the inputs to shader
VertexShaderInputs *gVSInputs;
-// Custom shaders we use for lighting
-rs_program_vertex gProgVertexCustom;
-rs_program_fragment gProgFragmentCustom;
-rs_program_vertex gProgVertexPixelLight;
-rs_program_vertex gProgVertexPixelLightMove;
-rs_program_fragment gProgFragmentPixelLight;
+
rs_program_fragment gProgFragmentMultitex;
rs_allocation gRenderBufferColor;
rs_allocation gRenderBufferDepth;
-float gDt = 0;
+static float gDt = 0;
void init() {
}
@@ -141,16 +131,6 @@ void init() {
static int gRenderSurfaceW;
static int gRenderSurfaceH;
-static const char *sampleText = "This is a sample of small text for performace";
-// Offsets for multiple layer of text
-static int textOffsets[] = { 0, 0, -5, -5, 5, 5, -8, -8, 8, 8};
-static float textColors[] = {1.0f, 1.0f, 1.0f, 1.0f,
- 0.5f, 0.7f, 0.5f, 1.0f,
- 0.7f, 0.5f, 0.5f, 1.0f,
- 0.5f, 0.5f, 0.7f, 1.0f,
- 0.5f, 0.6f, 0.7f, 1.0f,
-};
-
/**
* Methods to draw the galaxy live wall paper
*/
@@ -291,40 +271,16 @@ static void setupOffscreenTarget() {
rsgBindDepthTarget(gRenderBufferDepth);
}
-static void displayFontSamples(int fillNum) {
+rs_script gFontScript;
+rs_script gTorusScript;
+rs_allocation gDummyAlloc;
- rs_font fonts[5];
- fonts[0] = gFontSans;
- fonts[1] = gFontSerif;
- fonts[2] = gFontSans;
- fonts[3] = gFontSerif;
- fonts[4] = gFontSans;
-
- uint width = gRenderSurfaceW;
- uint height = gRenderSurfaceH;
- int left = 0, right = 0, top = 0, bottom = 0;
- rsgMeasureText(sampleText, &left, &right, &top, &bottom);
-
- int textHeight = top - bottom;
- int textWidth = right - left;
- int numVerticalLines = height / textHeight;
- int yPos = top;
-
- int xOffset = 0, yOffset = 0;
- for(int fillI = 0; fillI < fillNum; fillI ++) {
- rsgBindFont(fonts[fillI]);
- xOffset = textOffsets[fillI * 2];
- yOffset = textOffsets[fillI * 2 + 1];
- float *colPtr = textColors + fillI * 4;
- rsgFontColor(colPtr[0], colPtr[1], colPtr[2], colPtr[3]);
- for (int h = 0; h < 4; h ++) {
- yPos = top + yOffset;
- for (int v = 0; v < numVerticalLines; v ++) {
- rsgDrawText(sampleText, xOffset + textWidth * h, yPos);
- yPos += textHeight;
- }
- }
- }
+static void displayFontSamples(int fillNum) {
+ TestData testData;
+ testData.renderSurfaceW = gRenderSurfaceW;
+ testData.renderSurfaceH = gRenderSurfaceH;
+ testData.user = fillNum;
+ rsForEach(gFontScript, gDummyAlloc, gDummyAlloc, &testData);
}
static void bindProgramVertexOrtho() {
@@ -555,212 +511,37 @@ static void displayLiveWallPaper(int wResolution, int hResolution) {
drawMeshInPage(2.0f*gRenderSurfaceW, 0, wResolution, hResolution);
}
-static float gTorusRotation = 0;
-static void updateModelMatrix(rs_matrix4x4 *matrix, void *buffer) {
- if (buffer == 0) {
- rsgProgramVertexLoadModelMatrix(matrix);
- } else {
- rsgAllocationSyncAll(rsGetAllocation(buffer));
- }
-}
-
-static void drawToruses(int numMeshes, rs_matrix4x4 *matrix, void *buffer) {
-
- if (numMeshes == 1) {
- rsMatrixLoadTranslate(matrix, 0.0f, 0.0f, -7.5f);
- rsMatrixRotate(matrix, gTorusRotation, 1.0f, 0.0f, 0.0f);
- updateModelMatrix(matrix, buffer);
- rsgDrawMesh(gTorusMesh);
- return;
- }
-
- if (numMeshes == 2) {
- rsMatrixLoadTranslate(matrix, -1.6f, 0.0f, -7.5f);
- rsMatrixRotate(matrix, gTorusRotation, 1.0f, 0.0f, 0.0f);
- updateModelMatrix(matrix, buffer);
- rsgDrawMesh(gTorusMesh);
-
- rsMatrixLoadTranslate(matrix, 1.6f, 0.0f, -7.5f);
- rsMatrixRotate(matrix, gTorusRotation, 1.0f, 0.0f, 0.0f);
- updateModelMatrix(matrix, buffer);
- rsgDrawMesh(gTorusMesh);
- return;
- }
-
- float startX = -5.0f;
- float startY = -1.5f;
- float startZ = -15.0f;
- float dist = 3.2f;
-
- for (int h = 0; h < 4; h ++) {
- for (int v = 0; v < 2; v ++) {
- // Position our model on the screen
- rsMatrixLoadTranslate(matrix, startX + dist * h, startY + dist * v, startZ);
- rsMatrixRotate(matrix, gTorusRotation, 1.0f, 0.0f, 0.0f);
- updateModelMatrix(matrix, buffer);
- rsgDrawMesh(gTorusMesh);
- }
- }
-}
-
// Quick hack to get some geometry numbers
static void displaySimpleGeoSamples(bool useTexture, int numMeshes) {
- rsgBindProgramVertex(gProgVertex);
- rsgBindProgramRaster(gCullBack);
- // Setup the projection matrix with 30 degree field of view
- rs_matrix4x4 proj;
- float aspect = (float)gRenderSurfaceW / (float)gRenderSurfaceH;
- rsMatrixLoadPerspective(&proj, 30.0f, aspect, 0.1f, 100.0f);
- rsgProgramVertexLoadProjectionMatrix(&proj);
-
- // Fragment shader with texture
- rsgBindProgramStore(gProgStoreBlendNoneDepth);
- if (useTexture) {
- rsgBindProgramFragment(gProgFragmentTexture);
- } else {
- rsgBindProgramFragment(gProgFragmentColor);
- rsgProgramFragmentConstantColor(gProgFragmentColor, 0.1, 0.7, 0.1, 1);
- }
- rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
- rsgBindTexture(gProgFragmentTexture, 0, gTexTorus);
-
- // Apply a rotation to our mesh
- gTorusRotation += 50.0f * gDt;
- if (gTorusRotation > 360.0f) {
- gTorusRotation -= 360.0f;
- }
-
- rs_matrix4x4 matrix;
- drawToruses(numMeshes, &matrix, 0);
-}
-
-float gLight0Rotation = 0;
-float gLight1Rotation = 0;
-
-static void setupCustomShaderLights() {
- float4 light0Pos = {-5.0f, 5.0f, -10.0f, 1.0f};
- float4 light1Pos = {2.0f, 5.0f, 15.0f, 1.0f};
- float4 light0DiffCol = {0.9f, 0.7f, 0.7f, 1.0f};
- float4 light0SpecCol = {0.9f, 0.6f, 0.6f, 1.0f};
- float4 light1DiffCol = {0.5f, 0.5f, 0.9f, 1.0f};
- float4 light1SpecCol = {0.5f, 0.5f, 0.9f, 1.0f};
-
- gLight0Rotation += 50.0f * gDt;
- if (gLight0Rotation > 360.0f) {
- gLight0Rotation -= 360.0f;
- }
- gLight1Rotation -= 50.0f * gDt;
- if (gLight1Rotation > 360.0f) {
- gLight1Rotation -= 360.0f;
- }
-
- rs_matrix4x4 l0Mat;
- rsMatrixLoadRotate(&l0Mat, gLight0Rotation, 1.0f, 0.0f, 0.0f);
- light0Pos = rsMatrixMultiply(&l0Mat, light0Pos);
- rs_matrix4x4 l1Mat;
- rsMatrixLoadRotate(&l1Mat, gLight1Rotation, 0.0f, 0.0f, 1.0f);
- light1Pos = rsMatrixMultiply(&l1Mat, light1Pos);
-
- // Set light 0 properties
- gVSConstants->light0_Posision = light0Pos;
- gVSConstants->light0_Diffuse = 1.0f;
- gVSConstants->light0_Specular = 0.5f;
- gVSConstants->light0_CosinePower = 10.0f;
- // Set light 1 properties
- gVSConstants->light1_Posision = light1Pos;
- gVSConstants->light1_Diffuse = 1.0f;
- gVSConstants->light1_Specular = 0.7f;
- gVSConstants->light1_CosinePower = 25.0f;
- rsgAllocationSyncAll(rsGetAllocation(gVSConstants));
-
- // Update fragment shader constants
- // Set light 0 colors
- gFSConstants->light0_DiffuseColor = light0DiffCol;
- gFSConstants->light0_SpecularColor = light0SpecCol;
- // Set light 1 colors
- gFSConstants->light1_DiffuseColor = light1DiffCol;
- gFSConstants->light1_SpecularColor = light1SpecCol;
- rsgAllocationSyncAll(rsGetAllocation(gFSConstants));
-
- // Set light 0 properties for per pixel lighting
- gFSConstPixel->light0_Posision = light0Pos;
- gFSConstPixel->light0_Diffuse = 1.0f;
- gFSConstPixel->light0_Specular = 0.5f;
- gFSConstPixel->light0_CosinePower = 10.0f;
- gFSConstPixel->light0_DiffuseColor = light0DiffCol;
- gFSConstPixel->light0_SpecularColor = light0SpecCol;
- // Set light 1 properties
- gFSConstPixel->light1_Posision = light1Pos;
- gFSConstPixel->light1_Diffuse = 1.0f;
- gFSConstPixel->light1_Specular = 0.7f;
- gFSConstPixel->light1_CosinePower = 25.0f;
- gFSConstPixel->light1_DiffuseColor = light1DiffCol;
- gFSConstPixel->light1_SpecularColor = light1SpecCol;
- rsgAllocationSyncAll(rsGetAllocation(gFSConstPixel));
+ TestData testData;
+ testData.renderSurfaceW = gRenderSurfaceW;
+ testData.renderSurfaceH = gRenderSurfaceH;
+ testData.dt = gDt;
+ testData.user = 0;
+ testData.user1 = useTexture ? 1 : 0;
+ testData.user2 = numMeshes;
+ rsForEach(gTorusScript, gDummyAlloc, gDummyAlloc, &testData);
}
static void displayCustomShaderSamples(int numMeshes) {
-
- // Update vertex shader constants
- // Load model matrix
- // Apply a rotation to our mesh
- gTorusRotation += 50.0f * gDt;
- if (gTorusRotation > 360.0f) {
- gTorusRotation -= 360.0f;
- }
-
- // Setup the projection matrix
- float aspect = (float)gRenderSurfaceW / (float)gRenderSurfaceH;
- rsMatrixLoadPerspective(&gVSConstants->proj, 30.0f, aspect, 0.1f, 100.0f);
- setupCustomShaderLights();
-
- rsgBindProgramVertex(gProgVertexCustom);
-
- // Fragment shader with texture
- rsgBindProgramStore(gProgStoreBlendNoneDepth);
- rsgBindProgramFragment(gProgFragmentCustom);
- rsgBindSampler(gProgFragmentCustom, 0, gLinearClamp);
- rsgBindTexture(gProgFragmentCustom, 0, gTexTorus);
-
- // Use back face culling
- rsgBindProgramRaster(gCullBack);
-
- drawToruses(numMeshes, &gVSConstants->model, gVSConstants);
+ TestData testData;
+ testData.renderSurfaceW = gRenderSurfaceW;
+ testData.renderSurfaceH = gRenderSurfaceH;
+ testData.dt = gDt;
+ testData.user = 1;
+ testData.user1 = numMeshes;
+ rsForEach(gTorusScript, gDummyAlloc, gDummyAlloc, &testData);
}
static void displayPixelLightSamples(int numMeshes, bool heavyVertex) {
-
- // Update vertex shader constants
- // Load model matrix
- // Apply a rotation to our mesh
- gTorusRotation += 30.0f * gDt;
- if (gTorusRotation > 360.0f) {
- gTorusRotation -= 360.0f;
- }
-
- gVSConstPixel->time = rsUptimeMillis()*0.005;
-
- // Setup the projection matrix
- float aspect = (float)gRenderSurfaceW / (float)gRenderSurfaceH;
- rsMatrixLoadPerspective(&gVSConstPixel->proj, 30.0f, aspect, 0.1f, 100.0f);
- setupCustomShaderLights();
-
- if (heavyVertex) {
- rsgBindProgramVertex(gProgVertexPixelLightMove);
- } else {
- rsgBindProgramVertex(gProgVertexPixelLight);
- }
-
- // Fragment shader with texture
- rsgBindProgramStore(gProgStoreBlendNoneDepth);
- rsgBindProgramFragment(gProgFragmentPixelLight);
- rsgBindSampler(gProgFragmentPixelLight, 0, gLinearClamp);
- rsgBindTexture(gProgFragmentPixelLight, 0, gTexTorus);
-
- // Use back face culling
- rsgBindProgramRaster(gCullBack);
-
- drawToruses(numMeshes, &gVSConstPixel->model, gVSConstPixel);
+ TestData testData;
+ testData.renderSurfaceW = gRenderSurfaceW;
+ testData.renderSurfaceH = gRenderSurfaceH;
+ testData.dt = gDt;
+ testData.user = 2;
+ testData.user1 = numMeshes;
+ testData.user2 = heavyVertex ? 1 : 0;
+ rsForEach(gTorusScript, gDummyAlloc, gDummyAlloc, &testData);
}
static void displayMultitextureSample(bool blend, int quadCount) {
@@ -862,6 +643,20 @@ static const char *testNames[] = {
"UI test with live wallpaper",
};
+static bool gIsDebugMode = false;
+void setDebugMode(int testNumber) {
+ gIsDebugMode = true;
+ benchMode = testNumber;
+ rsgClearAllRenderTargets();
+}
+
+void setBenchmarkMode() {
+ gIsDebugMode = false;
+ benchMode = 0;
+ runningLoops = 0;
+}
+
+
void getTestName(int testIndex) {
int bufferLen = rsAllocationGetDimX(rsGetAllocation(gStringBuffer));
if (testIndex >= gMaxModes) {
@@ -932,7 +727,7 @@ static void runTest(int index) {
displaySingletexFill(true, 10);
break;
case 18:
- displayMultitextureSample(true, 8);
+ displayMultitextureSample(true, 10);
break;
case 19:
displayPixelLightSamples(1, false);
@@ -992,14 +787,7 @@ static void drawOffscreenResult(int posX, int posY, int width, int height) {
startX + width, startY, 0, 1, 1);
}
-int root(void) {
- gRenderSurfaceW = rsgGetWidth();
- gRenderSurfaceH = rsgGetHeight();
- rsgClearColor(0.2f, 0.2f, 0.2f, 1.0f);
- rsgClearDepth(1.0f);
- if(!checkInit()) {
- return 1;
- }
+static void benchmark() {
gDt = 1.0f / 60.0f;
@@ -1045,8 +833,6 @@ int root(void) {
benchMode ++;
- gTorusRotation = 0;
-
if (benchMode == gMaxModes) {
rsSendToClientBlocking(RS_MSG_RESULTS_READY, gResultBuffer, gMaxModes*sizeof(float));
benchMode = 0;
@@ -1058,5 +844,30 @@ int root(void) {
sendMsgFlag = true;
}
}
+
+}
+
+static void debug() {
+ gDt = rsGetDt();
+
+ rsgFinish();
+ runTest(benchMode);
+}
+
+int root(void) {
+ gRenderSurfaceW = rsgGetWidth();
+ gRenderSurfaceH = rsgGetHeight();
+ rsgClearColor(0.2f, 0.2f, 0.2f, 1.0f);
+ rsgClearDepth(1.0f);
+ if(!checkInit()) {
+ return 1;
+ }
+
+ if (gIsDebugMode) {
+ debug();
+ } else {
+ benchmark();
+ }
+
return 1;
}
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/subtest_def.rsh b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/subtest_def.rsh
new file mode 100644
index 000000000000..b635373b2afa
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/subtest_def.rsh
@@ -0,0 +1,28 @@
+// Copyright (C) 2011 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.perftest)
+
+typedef struct TestData_s {
+ int renderSurfaceW;
+ int renderSurfaceH;
+ float dt;
+ int user;
+ int user1;
+ int user2;
+ int user3;
+} TestData;
+
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/text_test.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/text_test.rs
new file mode 100644
index 000000000000..0df6b3590bd5
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/text_test.rs
@@ -0,0 +1,82 @@
+// Copyright (C) 2011 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.perftest)
+
+#include "rs_graphics.rsh"
+#include "subtest_def.rsh"
+
+rs_font gFontSans;
+rs_font gFontSerif;
+
+void init() {
+}
+
+static int gRenderSurfaceW = 1280;
+static int gRenderSurfaceH = 720;
+
+static const char *sampleText = "This is a sample of small text for performace";
+// Offsets for multiple layer of text
+static int textOffsets[] = { 0, 0, -5, -5, 5, 5, -8, -8, 8, 8};
+static float textColors[] = {1.0f, 1.0f, 1.0f, 1.0f,
+ 0.5f, 0.7f, 0.5f, 1.0f,
+ 0.7f, 0.5f, 0.5f, 1.0f,
+ 0.5f, 0.5f, 0.7f, 1.0f,
+ 0.5f, 0.6f, 0.7f, 1.0f,
+};
+
+static void displayFontSamples(int fillNum) {
+
+ rs_font fonts[5];
+ fonts[0] = gFontSans;
+ fonts[1] = gFontSerif;
+ fonts[2] = gFontSans;
+ fonts[3] = gFontSerif;
+ fonts[4] = gFontSans;
+
+ uint width = gRenderSurfaceW;
+ uint height = gRenderSurfaceH;
+ int left = 0, right = 0, top = 0, bottom = 0;
+ rsgMeasureText(sampleText, &left, &right, &top, &bottom);
+
+ int textHeight = top - bottom;
+ int textWidth = right - left;
+ int numVerticalLines = height / textHeight;
+ int yPos = top;
+
+ int xOffset = 0, yOffset = 0;
+ for(int fillI = 0; fillI < fillNum; fillI ++) {
+ rsgBindFont(fonts[fillI]);
+ xOffset = textOffsets[fillI * 2];
+ yOffset = textOffsets[fillI * 2 + 1];
+ float *colPtr = textColors + fillI * 4;
+ rsgFontColor(colPtr[0], colPtr[1], colPtr[2], colPtr[3]);
+ for (int h = 0; h < 4; h ++) {
+ yPos = top + yOffset;
+ for (int v = 0; v < numVerticalLines; v ++) {
+ rsgDrawText(sampleText, xOffset + textWidth * h, yPos);
+ yPos += textHeight;
+ }
+ }
+ }
+}
+
+void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) {
+ TestData *testData = (TestData*)usrData;
+ gRenderSurfaceW = testData->renderSurfaceW;
+ gRenderSurfaceH = testData->renderSurfaceH;
+ displayFontSamples(testData->user);
+}
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/torus_test.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/torus_test.rs
new file mode 100644
index 000000000000..26d56807f6f2
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/torus_test.rs
@@ -0,0 +1,283 @@
+// Copyright (C) 2011 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma version(1)
+
+#pragma rs java_package_name(com.android.perftest)
+
+#include "rs_graphics.rsh"
+#include "subtest_def.rsh"
+#include "shader_def.rsh"
+
+rs_program_vertex gProgVertex;
+rs_program_fragment gProgFragmentColor;
+rs_program_fragment gProgFragmentTexture;
+
+rs_program_store gProgStoreBlendNoneDepth;
+rs_mesh gTorusMesh;
+
+rs_program_raster gCullBack;
+rs_program_raster gCullFront;
+
+// Custom vertex shader compunents
+VertexShaderConstants *gVSConstants;
+FragentShaderConstants *gFSConstants;
+VertexShaderConstants3 *gVSConstPixel;
+FragentShaderConstants3 *gFSConstPixel;
+
+// Custom shaders we use for lighting
+rs_program_vertex gProgVertexCustom;
+rs_program_fragment gProgFragmentCustom;
+
+rs_sampler gLinearClamp;
+rs_allocation gTexTorus;
+
+rs_program_vertex gProgVertexPixelLight;
+rs_program_vertex gProgVertexPixelLightMove;
+rs_program_fragment gProgFragmentPixelLight;
+
+static float gDt = 0.0f;
+
+static int gRenderSurfaceW;
+static int gRenderSurfaceH;
+
+
+static float gTorusRotation = 0;
+static void updateModelMatrix(rs_matrix4x4 *matrix, void *buffer) {
+ if (buffer == 0) {
+ rsgProgramVertexLoadModelMatrix(matrix);
+ } else {
+ rsgAllocationSyncAll(rsGetAllocation(buffer));
+ }
+}
+
+static void drawToruses(int numMeshes, rs_matrix4x4 *matrix, void *buffer) {
+
+ if (numMeshes == 1) {
+ rsMatrixLoadTranslate(matrix, 0.0f, 0.0f, -7.5f);
+ rsMatrixRotate(matrix, gTorusRotation, 1.0f, 0.0f, 0.0f);
+ updateModelMatrix(matrix, buffer);
+ rsgDrawMesh(gTorusMesh);
+ return;
+ }
+
+ if (numMeshes == 2) {
+ rsMatrixLoadTranslate(matrix, -1.6f, 0.0f, -7.5f);
+ rsMatrixRotate(matrix, gTorusRotation, 1.0f, 0.0f, 0.0f);
+ updateModelMatrix(matrix, buffer);
+ rsgDrawMesh(gTorusMesh);
+
+ rsMatrixLoadTranslate(matrix, 1.6f, 0.0f, -7.5f);
+ rsMatrixRotate(matrix, gTorusRotation, 1.0f, 0.0f, 0.0f);
+ updateModelMatrix(matrix, buffer);
+ rsgDrawMesh(gTorusMesh);
+ return;
+ }
+
+ float startX = -5.0f;
+ float startY = -1.5f;
+ float startZ = -15.0f;
+ float dist = 3.2f;
+
+ for (int h = 0; h < 4; h ++) {
+ for (int v = 0; v < 2; v ++) {
+ // Position our model on the screen
+ rsMatrixLoadTranslate(matrix, startX + dist * h, startY + dist * v, startZ);
+ rsMatrixRotate(matrix, gTorusRotation, 1.0f, 0.0f, 0.0f);
+ updateModelMatrix(matrix, buffer);
+ rsgDrawMesh(gTorusMesh);
+ }
+ }
+}
+
+
+// Quick hack to get some geometry numbers
+static void displaySimpleGeoSamples(bool useTexture, int numMeshes) {
+ rsgBindProgramVertex(gProgVertex);
+ rsgBindProgramRaster(gCullBack);
+ // Setup the projection matrix with 30 degree field of view
+ rs_matrix4x4 proj;
+ float aspect = (float)gRenderSurfaceW / (float)gRenderSurfaceH;
+ rsMatrixLoadPerspective(&proj, 30.0f, aspect, 0.1f, 100.0f);
+ rsgProgramVertexLoadProjectionMatrix(&proj);
+
+ // Fragment shader with texture
+ rsgBindProgramStore(gProgStoreBlendNoneDepth);
+ if (useTexture) {
+ rsgBindProgramFragment(gProgFragmentTexture);
+ } else {
+ rsgBindProgramFragment(gProgFragmentColor);
+ rsgProgramFragmentConstantColor(gProgFragmentColor, 0.1, 0.7, 0.1, 1);
+ }
+ rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
+ rsgBindTexture(gProgFragmentTexture, 0, gTexTorus);
+
+ // Apply a rotation to our mesh
+ gTorusRotation += 50.0f * gDt;
+ if (gTorusRotation > 360.0f) {
+ gTorusRotation -= 360.0f;
+ }
+
+ rs_matrix4x4 matrix;
+ drawToruses(numMeshes, &matrix, 0);
+}
+
+float gLight0Rotation = 0;
+float gLight1Rotation = 0;
+
+static void setupCustomShaderLights() {
+ float4 light0Pos = {-5.0f, 5.0f, -10.0f, 1.0f};
+ float4 light1Pos = {2.0f, 5.0f, 15.0f, 1.0f};
+ float4 light0DiffCol = {0.9f, 0.7f, 0.7f, 1.0f};
+ float4 light0SpecCol = {0.9f, 0.6f, 0.6f, 1.0f};
+ float4 light1DiffCol = {0.5f, 0.5f, 0.9f, 1.0f};
+ float4 light1SpecCol = {0.5f, 0.5f, 0.9f, 1.0f};
+
+ gLight0Rotation += 50.0f * gDt;
+ if (gLight0Rotation > 360.0f) {
+ gLight0Rotation -= 360.0f;
+ }
+ gLight1Rotation -= 50.0f * gDt;
+ if (gLight1Rotation > 360.0f) {
+ gLight1Rotation -= 360.0f;
+ }
+
+ rs_matrix4x4 l0Mat;
+ rsMatrixLoadRotate(&l0Mat, gLight0Rotation, 1.0f, 0.0f, 0.0f);
+ light0Pos = rsMatrixMultiply(&l0Mat, light0Pos);
+ rs_matrix4x4 l1Mat;
+ rsMatrixLoadRotate(&l1Mat, gLight1Rotation, 0.0f, 0.0f, 1.0f);
+ light1Pos = rsMatrixMultiply(&l1Mat, light1Pos);
+
+ // Set light 0 properties
+ gVSConstants->light0_Posision = light0Pos;
+ gVSConstants->light0_Diffuse = 1.0f;
+ gVSConstants->light0_Specular = 0.5f;
+ gVSConstants->light0_CosinePower = 10.0f;
+ // Set light 1 properties
+ gVSConstants->light1_Posision = light1Pos;
+ gVSConstants->light1_Diffuse = 1.0f;
+ gVSConstants->light1_Specular = 0.7f;
+ gVSConstants->light1_CosinePower = 25.0f;
+ rsgAllocationSyncAll(rsGetAllocation(gVSConstants));
+
+ // Update fragment shader constants
+ // Set light 0 colors
+ gFSConstants->light0_DiffuseColor = light0DiffCol;
+ gFSConstants->light0_SpecularColor = light0SpecCol;
+ // Set light 1 colors
+ gFSConstants->light1_DiffuseColor = light1DiffCol;
+ gFSConstants->light1_SpecularColor = light1SpecCol;
+ rsgAllocationSyncAll(rsGetAllocation(gFSConstants));
+
+ // Set light 0 properties for per pixel lighting
+ gFSConstPixel->light0_Posision = light0Pos;
+ gFSConstPixel->light0_Diffuse = 1.0f;
+ gFSConstPixel->light0_Specular = 0.5f;
+ gFSConstPixel->light0_CosinePower = 10.0f;
+ gFSConstPixel->light0_DiffuseColor = light0DiffCol;
+ gFSConstPixel->light0_SpecularColor = light0SpecCol;
+ // Set light 1 properties
+ gFSConstPixel->light1_Posision = light1Pos;
+ gFSConstPixel->light1_Diffuse = 1.0f;
+ gFSConstPixel->light1_Specular = 0.7f;
+ gFSConstPixel->light1_CosinePower = 25.0f;
+ gFSConstPixel->light1_DiffuseColor = light1DiffCol;
+ gFSConstPixel->light1_SpecularColor = light1SpecCol;
+ rsgAllocationSyncAll(rsGetAllocation(gFSConstPixel));
+}
+
+static void displayCustomShaderSamples(int numMeshes) {
+
+ // Update vertex shader constants
+ // Load model matrix
+ // Apply a rotation to our mesh
+ gTorusRotation += 50.0f * gDt;
+ if (gTorusRotation > 360.0f) {
+ gTorusRotation -= 360.0f;
+ }
+
+ // Setup the projection matrix
+ float aspect = (float)gRenderSurfaceW / (float)gRenderSurfaceH;
+ rsMatrixLoadPerspective(&gVSConstants->proj, 30.0f, aspect, 0.1f, 100.0f);
+ setupCustomShaderLights();
+
+ rsgBindProgramVertex(gProgVertexCustom);
+
+ // Fragment shader with texture
+ rsgBindProgramStore(gProgStoreBlendNoneDepth);
+ rsgBindProgramFragment(gProgFragmentCustom);
+ rsgBindSampler(gProgFragmentCustom, 0, gLinearClamp);
+ rsgBindTexture(gProgFragmentCustom, 0, gTexTorus);
+
+ // Use back face culling
+ rsgBindProgramRaster(gCullBack);
+
+ drawToruses(numMeshes, &gVSConstants->model, gVSConstants);
+}
+
+static void displayPixelLightSamples(int numMeshes, bool heavyVertex) {
+
+ // Update vertex shader constants
+ // Load model matrix
+ // Apply a rotation to our mesh
+ gTorusRotation += 30.0f * gDt;
+ if (gTorusRotation > 360.0f) {
+ gTorusRotation -= 360.0f;
+ }
+
+ gVSConstPixel->time = rsUptimeMillis()*0.005;
+
+ // Setup the projection matrix
+ float aspect = (float)gRenderSurfaceW / (float)gRenderSurfaceH;
+ rsMatrixLoadPerspective(&gVSConstPixel->proj, 30.0f, aspect, 0.1f, 100.0f);
+ setupCustomShaderLights();
+
+ if (heavyVertex) {
+ rsgBindProgramVertex(gProgVertexPixelLightMove);
+ } else {
+ rsgBindProgramVertex(gProgVertexPixelLight);
+ }
+
+ // Fragment shader with texture
+ rsgBindProgramStore(gProgStoreBlendNoneDepth);
+ rsgBindProgramFragment(gProgFragmentPixelLight);
+ rsgBindSampler(gProgFragmentPixelLight, 0, gLinearClamp);
+ rsgBindTexture(gProgFragmentPixelLight, 0, gTexTorus);
+
+ // Use back face culling
+ rsgBindProgramRaster(gCullBack);
+
+ drawToruses(numMeshes, &gVSConstPixel->model, gVSConstPixel);
+}
+
+
+void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) {
+ TestData *testData = (TestData*)usrData;
+ gRenderSurfaceW = testData->renderSurfaceW;
+ gRenderSurfaceH = testData->renderSurfaceH;
+ gDt = testData->dt;
+
+ switch(testData->user) {
+ case 0:
+ displaySimpleGeoSamples(testData->user1 == 1 ? true : false, testData->user2);
+ break;
+ case 1:
+ displayCustomShaderSamples(testData->user1);
+ break;
+ case 2:
+ displayPixelLightSamples(testData->user1, testData->user2 == 1 ? true : false);
+ break;
+ }
+}
diff --git a/voip/java/com/android/server/sip/SipService.java b/voip/java/com/android/server/sip/SipService.java
index 3b0f54606233..47863bd46dfe 100644
--- a/voip/java/com/android/server/sip/SipService.java
+++ b/voip/java/com/android/server/sip/SipService.java
@@ -756,21 +756,20 @@ public final class SipService extends ISipService.Stub {
}
}
- private class IntervalMeasurementProcess implements
+ private class IntervalMeasurementProcess implements Runnable,
SipSessionGroup.KeepAliveProcessCallback {
private static final String TAG = "SipKeepAliveInterval";
private static final int MAX_INTERVAL = 120; // in seconds
- private static final int MIN_INTERVAL = 10; // in seconds
+ private static final int MIN_INTERVAL = 5; // in seconds
private static final int PASS_THRESHOLD = 10;
private static final int MAX_RETRY_COUNT = 5;
+ private static final int NAT_MEASUREMENT_RETRY_INTERVAL = 120; // in seconds
private SipSessionGroupExt mGroup;
private SipSessionGroup.SipSessionImpl mSession;
- private boolean mRunning;
- private int mMinInterval = 10; // in seconds
+ private int mMinInterval = DEFAULT_KEEPALIVE_INTERVAL; // in seconds
private int mMaxInterval;
private int mInterval;
private int mPassCount = 0;
- private int mErrorCount = 0;
public IntervalMeasurementProcess(SipProfile localProfile, int maxInterval) {
mMaxInterval = (maxInterval < 0) ? MAX_INTERVAL : maxInterval;
@@ -788,8 +787,6 @@ public final class SipService extends ISipService.Stub {
// TODO: remove this line once SipWakeupTimer can better handle
// variety of timeout values
mGroup.setWakeupTimer(new SipWakeupTimer(mContext, mExecutor));
- mSession = (SipSessionGroup.SipSessionImpl)
- mGroup.createSession(null);
} catch (Exception e) {
Log.w(TAG, "start interval measurement error: " + e);
}
@@ -797,6 +794,11 @@ public final class SipService extends ISipService.Stub {
public void start() {
synchronized (SipService.this) {
+ Log.d(TAG, "start measurement w interval=" + mInterval);
+ if (mSession == null) {
+ mSession = (SipSessionGroup.SipSessionImpl)
+ mGroup.createSession(null);
+ }
try {
mSession.startKeepAliveProcess(mInterval, this);
} catch (SipException e) {
@@ -807,14 +809,23 @@ public final class SipService extends ISipService.Stub {
public void stop() {
synchronized (SipService.this) {
- mSession.stopKeepAliveProcess();
+ if (mSession != null) {
+ mSession.stopKeepAliveProcess();
+ mSession = null;
+ }
+ mTimer.cancel(this);
}
}
private void restart() {
synchronized (SipService.this) {
+ // Return immediately if the measurement process is stopped
+ if (mSession == null) return;
+
+ Log.d(TAG, "restart measurement w interval=" + mInterval);
try {
mSession.stopKeepAliveProcess();
+ mPassCount = 0;
mSession.startKeepAliveProcess(mInterval, this);
} catch (SipException e) {
Log.e(TAG, "restart()", e);
@@ -826,8 +837,6 @@ public final class SipService extends ISipService.Stub {
@Override
public void onResponse(boolean portChanged) {
synchronized (SipService.this) {
- mErrorCount = 0;
-
if (!portChanged) {
if (++mPassCount != PASS_THRESHOLD) return;
// update the interval, since the current interval is good to
@@ -853,7 +862,6 @@ public final class SipService extends ISipService.Stub {
} else {
// calculate the new interval and continue.
mInterval = (mMaxInterval + mMinInterval) / 2;
- mPassCount = 0;
if (DEBUG) {
Log.d(TAG, "current interval: " + mKeepAliveInterval
+ ", test new interval: " + mInterval);
@@ -866,22 +874,32 @@ public final class SipService extends ISipService.Stub {
// SipSessionGroup.KeepAliveProcessCallback
@Override
public void onError(int errorCode, String description) {
+ Log.w(TAG, "interval measurement error: " + description);
+ restartLater();
+ }
+
+ // timeout handler
+ @Override
+ public void run() {
+ mTimer.cancel(this);
+ restart();
+ }
+
+ private void restartLater() {
synchronized (SipService.this) {
- Log.w(TAG, "interval measurement error: " + description);
- if (++mErrorCount < MAX_RETRY_COUNT) {
- Log.w(TAG, " retry count = " + mErrorCount);
- mPassCount = 0;
- restart();
- } else {
- Log.w(TAG, " max retry count reached; measurement aborted");
- }
+ int interval = NAT_MEASUREMENT_RETRY_INTERVAL;
+ Log.d(TAG, "Retry measurement " + interval + "s later.");
+ mTimer.cancel(this);
+ mTimer.set(interval * 1000, this);
}
}
}
private class AutoRegistrationProcess extends SipSessionAdapter
implements Runnable, SipSessionGroup.KeepAliveProcessCallback {
+ private static final int MIN_KEEPALIVE_SUCCESS_COUNT = 10;
private String TAG = "SipAudoReg";
+
private SipSessionGroup.SipSessionImpl mSession;
private SipSessionGroup.SipSessionImpl mKeepAliveSession;
private SipSessionListenerProxy mProxy = new SipSessionListenerProxy();
@@ -892,6 +910,8 @@ public final class SipService extends ISipService.Stub {
private String mErrorMessage;
private boolean mRunning = false;
+ private int mKeepAliveSuccessCount = 0;
+
private String getAction() {
return toString();
}
@@ -915,18 +935,56 @@ public final class SipService extends ISipService.Stub {
}
}
+ private void startKeepAliveProcess(int interval) {
+ Log.d(TAG, "start keepalive w interval=" + interval);
+ if (mKeepAliveSession == null) {
+ mKeepAliveSession = mSession.duplicate();
+ } else {
+ mKeepAliveSession.stopKeepAliveProcess();
+ }
+ try {
+ mKeepAliveSession.startKeepAliveProcess(interval, this);
+ } catch (SipException e) {
+ Log.e(TAG, "failed to start keepalive w interval=" + interval,
+ e);
+ }
+ }
+
+ private void stopKeepAliveProcess() {
+ if (mKeepAliveSession != null) {
+ mKeepAliveSession.stopKeepAliveProcess();
+ mKeepAliveSession = null;
+ }
+ mKeepAliveSuccessCount = 0;
+ }
+
// SipSessionGroup.KeepAliveProcessCallback
@Override
public void onResponse(boolean portChanged) {
synchronized (SipService.this) {
if (portChanged) {
- restartPortMappingLifetimeMeasurement(
- mSession.getLocalProfile(), getKeepAliveInterval());
+ int interval = getKeepAliveInterval();
+ if (mKeepAliveSuccessCount < MIN_KEEPALIVE_SUCCESS_COUNT) {
+ Log.i(TAG, "keepalive doesn't work with interval "
+ + interval + ", past success count="
+ + mKeepAliveSuccessCount);
+ if (interval > DEFAULT_KEEPALIVE_INTERVAL) {
+ restartPortMappingLifetimeMeasurement(
+ mSession.getLocalProfile(), interval);
+ mKeepAliveSuccessCount = 0;
+ }
+ } else {
+ Log.i(TAG, "keep keepalive going with interval "
+ + interval + ", past success count="
+ + mKeepAliveSuccessCount);
+ mKeepAliveSuccessCount /= 2;
+ }
} else {
// Start keep-alive interval measurement on the first
// successfully kept-alive SipSessionGroup
startPortMappingLifetimeMeasurement(
mSession.getLocalProfile());
+ mKeepAliveSuccessCount++;
}
if (!mRunning || !portChanged) return;
@@ -960,10 +1018,7 @@ public final class SipService extends ISipService.Stub {
}
mTimer.cancel(this);
- if (mKeepAliveSession != null) {
- mKeepAliveSession.stopKeepAliveProcess();
- mKeepAliveSession = null;
- }
+ stopKeepAliveProcess();
mRegistered = false;
setListener(mProxy.getListener());
@@ -975,12 +1030,8 @@ public final class SipService extends ISipService.Stub {
if (DEBUGV) {
Log.v(TAG, "restart keepalive w interval=" + newInterval);
}
- mKeepAliveSession.stopKeepAliveProcess();
- try {
- mKeepAliveSession.startKeepAliveProcess(newInterval, this);
- } catch (SipException e) {
- Log.e(TAG, "onKeepAliveIntervalChanged()", e);
- }
+ mKeepAliveSuccessCount = 0;
+ startKeepAliveProcess(newInterval);
}
}
@@ -1105,14 +1156,7 @@ public final class SipService extends ISipService.Stub {
SipProfile localProfile = mSession.getLocalProfile();
if ((mKeepAliveSession == null) && (isBehindNAT(mLocalIp)
|| localProfile.getSendKeepAlive())) {
- mKeepAliveSession = mSession.duplicate();
- Log.d(TAG, "start keepalive");
- try {
- mKeepAliveSession.startKeepAliveProcess(
- getKeepAliveInterval(), this);
- } catch (SipException e) {
- Log.e(TAG, "AutoRegistrationProcess", e);
- }
+ startKeepAliveProcess(getKeepAliveInterval());
}
}
mMyWakeLock.release(session);
diff --git a/voip/java/com/android/server/sip/SipWakeupTimer.java b/voip/java/com/android/server/sip/SipWakeupTimer.java
index 76780c02b3df..00d47ac63ce6 100644
--- a/voip/java/com/android/server/sip/SipWakeupTimer.java
+++ b/voip/java/com/android/server/sip/SipWakeupTimer.java
@@ -83,7 +83,7 @@ class SipWakeupTimer extends BroadcastReceiver {
mEventQueue = null;
}
- private synchronized boolean stopped() {
+ private boolean stopped() {
if (mEventQueue == null) {
Log.w(TAG, "Timer stopped");
return true;
@@ -233,7 +233,7 @@ class SipWakeupTimer extends BroadcastReceiver {
}
@Override
- public void onReceive(Context context, Intent intent) {
+ public synchronized void onReceive(Context context, Intent intent) {
// This callback is already protected by AlarmManager's wake lock.
String action = intent.getAction();
if (getAction().equals(action)
@@ -261,7 +261,7 @@ class SipWakeupTimer extends BroadcastReceiver {
}
}
- private synchronized void execute(long triggerTime) {
+ private void execute(long triggerTime) {
if (DEBUG_TIMER) Log.d(TAG, "time's up, triggerTime = "
+ showTime(triggerTime) + ": " + mEventQueue.size());
if (stopped() || mEventQueue.isEmpty()) return;