summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/current.txt2
-rw-r--r--cmds/keystore/keystore.cpp2
-rw-r--r--cmds/stagefright/Android.mk6
-rw-r--r--cmds/stagefright/SineSource.cpp2
-rw-r--r--cmds/stagefright/audioloop.cpp8
-rw-r--r--cmds/stagefright/record.cpp12
-rw-r--r--cmds/stagefright/recordvideo.cpp6
-rw-r--r--core/java/android/app/ActivityManagerNative.java6
-rw-r--r--core/java/android/app/ContextImpl.java8
-rw-r--r--core/java/android/app/IActivityManager.java2
-rw-r--r--core/java/android/app/WallpaperManager.java1
-rw-r--r--core/java/android/app/backup/WallpaperBackupHelper.java27
-rw-r--r--core/java/android/content/Context.java9
-rw-r--r--core/java/android/content/ContextWrapper.java6
-rw-r--r--core/java/android/content/pm/PackageParser.java3
-rw-r--r--core/java/android/net/EthernetDataTracker.java31
-rw-r--r--core/java/android/net/NetworkInfo.java12
-rw-r--r--core/java/android/os/UserId.java4
-rw-r--r--core/java/android/text/TextUtils.java6
-rw-r--r--core/java/android/view/Choreographer.java79
-rw-r--r--core/java/android/view/DisplayEventReceiver.java4
-rw-r--r--core/java/android/view/HardwareRenderer.java124
-rw-r--r--core/java/android/view/InputEventReceiver.java57
-rw-r--r--core/java/android/view/View.java344
-rw-r--r--core/java/android/view/ViewGroup.java381
-rw-r--r--core/java/android/view/ViewRootImpl.java51
-rw-r--r--core/java/android/view/VolumePanel.java49
-rw-r--r--core/java/android/view/WindowManagerImpl.java14
-rw-r--r--core/java/android/webkit/ZoomManager.java1
-rw-r--r--core/java/android/widget/GridLayout.java183
-rw-r--r--core/jni/android_app_NativeActivity.cpp36
-rw-r--r--core/jni/android_backup_BackupDataOutput.cpp1
-rw-r--r--core/jni/android_media_AudioRecord.cpp2
-rw-r--r--core/jni/android_media_AudioSystem.cpp2
-rw-r--r--core/jni/android_media_ToneGenerator.cpp2
-rw-r--r--core/jni/android_view_DisplayEventReceiver.cpp38
-rw-r--r--core/jni/android_view_InputChannel.cpp30
-rw-r--r--core/jni/android_view_InputEventReceiver.cpp208
-rw-r--r--core/jni/android_view_Surface.cpp2
-rw-r--r--core/res/res/values-af/strings.xml30
-rw-r--r--core/res/res/values-am/strings.xml8
-rw-r--r--core/res/res/values-ar/strings.xml8
-rw-r--r--core/res/res/values-be/strings.xml8
-rw-r--r--core/res/res/values-bg/strings.xml2
-rw-r--r--core/res/res/values-ca/strings.xml8
-rw-r--r--core/res/res/values-cs/strings.xml2
-rw-r--r--core/res/res/values-da/strings.xml8
-rw-r--r--core/res/res/values-de/strings.xml8
-rw-r--r--core/res/res/values-el/strings.xml2
-rw-r--r--core/res/res/values-en-rGB/strings.xml8
-rw-r--r--core/res/res/values-es-rUS/strings.xml8
-rw-r--r--core/res/res/values-es/strings.xml8
-rw-r--r--core/res/res/values-et/strings.xml8
-rw-r--r--core/res/res/values-fa/strings.xml8
-rw-r--r--core/res/res/values-fi/strings.xml8
-rw-r--r--core/res/res/values-fr/strings.xml8
-rw-r--r--core/res/res/values-hi/strings.xml8
-rw-r--r--core/res/res/values-hr/strings.xml8
-rw-r--r--core/res/res/values-hu/strings.xml8
-rw-r--r--core/res/res/values-in/strings.xml8
-rw-r--r--core/res/res/values-it/strings.xml8
-rw-r--r--core/res/res/values-iw/strings.xml8
-rw-r--r--core/res/res/values-ja/strings.xml2
-rw-r--r--core/res/res/values-ko/strings.xml2
-rw-r--r--core/res/res/values-lt/strings.xml8
-rw-r--r--core/res/res/values-lv/strings.xml8
-rw-r--r--core/res/res/values-ms/strings.xml2
-rw-r--r--core/res/res/values-nb/strings.xml8
-rw-r--r--core/res/res/values-nl/strings.xml8
-rw-r--r--core/res/res/values-pl/strings.xml8
-rw-r--r--core/res/res/values-pt-rPT/strings.xml8
-rw-r--r--core/res/res/values-pt/strings.xml2
-rw-r--r--core/res/res/values-rm/strings.xml4
-rw-r--r--core/res/res/values-ro/strings.xml8
-rw-r--r--core/res/res/values-ru/strings.xml8
-rw-r--r--core/res/res/values-sk/strings.xml2
-rw-r--r--core/res/res/values-sl/strings.xml8
-rw-r--r--core/res/res/values-sr/strings.xml8
-rw-r--r--core/res/res/values-sv/strings.xml8
-rw-r--r--core/res/res/values-sw/strings.xml8
-rw-r--r--core/res/res/values-th/strings.xml8
-rw-r--r--core/res/res/values-tl/strings.xml8
-rw-r--r--core/res/res/values-tr/strings.xml2
-rw-r--r--core/res/res/values-uk/strings.xml8
-rw-r--r--core/res/res/values-vi/strings.xml8
-rw-r--r--core/res/res/values-zh-rCN/strings.xml2
-rw-r--r--core/res/res/values-zh-rTW/strings.xml2
-rw-r--r--core/res/res/values-zu/strings.xml2
-rwxr-xr-xcore/res/res/values/config.xml21
-rw-r--r--core/res/res/values/public.xml3
-rw-r--r--core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java5
-rw-r--r--core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java12
-rw-r--r--data/fonts/Android.mk54
-rw-r--r--data/fonts/fonts.mk48
-rw-r--r--graphics/java/android/renderscript/Allocation.java28
-rw-r--r--graphics/java/android/renderscript/Element.java100
-rw-r--r--graphics/java/android/renderscript/Path.java90
-rw-r--r--graphics/java/android/renderscript/Program.java34
-rw-r--r--graphics/java/android/renderscript/ProgramVertex.java17
-rw-r--r--graphics/java/android/renderscript/RenderScript.java11
-rw-r--r--graphics/jni/android_renderscript_RenderScript.cpp20
-rw-r--r--include/android_runtime/android_app_NativeActivity.h4
-rw-r--r--include/media/AudioRecord.h4
-rw-r--r--include/media/AudioSystem.h2
-rw-r--r--include/media/AudioTrack.h47
-rw-r--r--include/media/EffectsFactoryApi.h8
-rw-r--r--include/media/IAudioRecord.h3
-rw-r--r--include/media/IAudioTrack.h11
-rw-r--r--include/media/MediaPlayerInterface.h2
-rw-r--r--include/media/MemoryLeakTrackUtil.h2
-rw-r--r--include/media/mediaplayer.h3
-rw-r--r--include/media/stagefright/AudioPlayer.h2
-rw-r--r--include/media/stagefright/MediaDebug.h36
-rw-r--r--include/private/media/AudioTrackShared.h29
-rw-r--r--include/ui/InputTransport.h351
-rw-r--r--include/utils/KeyedVector.h2
-rw-r--r--libs/rs/Android.mk3
-rw-r--r--libs/rs/RenderScriptDefines.h26
-rw-r--r--libs/rs/driver/rsdAllocation.cpp11
-rw-r--r--libs/rs/driver/rsdCore.cpp11
-rw-r--r--libs/rs/driver/rsdCore.h1
-rw-r--r--libs/rs/driver/rsdGL.cpp10
-rw-r--r--libs/rs/driver/rsdGL.h2
-rw-r--r--libs/rs/driver/rsdMesh.cpp2
-rw-r--r--libs/rs/driver/rsdMeshObj.cpp36
-rw-r--r--libs/rs/driver/rsdMeshObj.h7
-rw-r--r--libs/rs/driver/rsdPath.cpp185
-rw-r--r--libs/rs/driver/rsdPath.h35
-rw-r--r--libs/rs/driver/rsdProgramRaster.cpp3
-rw-r--r--libs/rs/driver/rsdProgramStore.cpp4
-rw-r--r--libs/rs/driver/rsdRuntimeStubs.cpp25
-rw-r--r--libs/rs/driver/rsdShader.cpp100
-rw-r--r--libs/rs/driver/rsdShaderCache.cpp3
-rw-r--r--libs/rs/rs.spec11
-rw-r--r--libs/rs/rsAllocation.cpp15
-rw-r--r--libs/rs/rsAllocation.h5
-rw-r--r--libs/rs/rsComponent.cpp4
-rw-r--r--libs/rs/rsContext.cpp1
-rw-r--r--libs/rs/rsContext.h1
-rw-r--r--libs/rs/rsElement.cpp42
-rw-r--r--libs/rs/rsElement.h30
-rw-r--r--libs/rs/rsMesh.h27
-rw-r--r--libs/rs/rsPath.cpp78
-rw-r--r--libs/rs/rsPath.h69
-rw-r--r--libs/rs/rsRuntime.h3
-rw-r--r--libs/rs/rsScriptC_LibGL.cpp20
-rw-r--r--libs/rs/rsType.cpp63
-rw-r--r--libs/rs/rsType.h52
-rw-r--r--libs/rs/rs_hal.h8
-rw-r--r--libs/rs/scriptc/rs_allocation.rsh130
-rw-r--r--libs/rs/scriptc/rs_graphics.rsh230
-rw-r--r--libs/rs/scriptc/rs_object.rsh15
-rw-r--r--libs/rs/scriptc/rs_types.rsh98
-rw-r--r--libs/ui/InputTransport.cpp934
-rw-r--r--libs/ui/tests/InputChannel_test.cpp113
-rw-r--r--libs/ui/tests/InputPublisherAndConsumer_test.cpp346
-rw-r--r--media/java/android/media/AudioManager.java204
-rw-r--r--media/java/android/media/AudioService.java152
-rw-r--r--media/java/android/media/IAudioService.aidl12
-rw-r--r--media/java/android/media/MediaInserter.java33
-rw-r--r--media/java/android/media/MediaScanner.java48
-rw-r--r--media/jni/soundpool/SoundPool.cpp2
-rwxr-xr-xmedia/libeffects/preprocessing/PreProcessing.cpp2
-rw-r--r--media/libmedia/AudioRecord.cpp37
-rw-r--r--media/libmedia/AudioTrack.cpp51
-rw-r--r--media/libmedia/IAudioRecord.cpp5
-rw-r--r--media/libmedia/IAudioTrack.cpp7
-rw-r--r--media/libmedia/MediaProfiles.cpp2
-rw-r--r--media/libmedia/ToneGenerator.cpp2
-rw-r--r--media/libmedia/mediaplayer.cpp2
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.cpp25
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.h4
-rw-r--r--media/libmediaplayerservice/StagefrightPlayer.cpp2
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.cpp16
-rw-r--r--media/libstagefright/AACExtractor.cpp2
-rw-r--r--media/libstagefright/AMRExtractor.cpp2
-rw-r--r--media/libstagefright/AMRWriter.cpp2
-rw-r--r--media/libstagefright/AudioPlayer.cpp10
-rw-r--r--media/libstagefright/AwesomePlayer.cpp10
-rwxr-xr-xmedia/libstagefright/CameraSource.cpp11
-rw-r--r--media/libstagefright/CameraSourceTimeLapse.cpp2
-rw-r--r--media/libstagefright/DRMExtractor.cpp2
-rw-r--r--media/libstagefright/FileSource.cpp2
-rw-r--r--media/libstagefright/JPEGSource.cpp4
-rw-r--r--media/libstagefright/MediaBuffer.cpp6
-rw-r--r--media/libstagefright/MediaBufferGroup.cpp2
-rw-r--r--media/libstagefright/MediaSourceSplitter.cpp2
-rw-r--r--media/libstagefright/MetaData.cpp2
-rw-r--r--media/libstagefright/OggExtractor.cpp2
-rw-r--r--media/libstagefright/SampleIterator.cpp2
-rw-r--r--media/libstagefright/StagefrightMetadataRetriever.cpp6
-rw-r--r--media/libstagefright/SurfaceMediaSource.cpp6
-rw-r--r--media/libstagefright/ThrottledSource.cpp2
-rw-r--r--media/libstagefright/TimedEventQueue.cpp2
-rw-r--r--media/libstagefright/VideoSourceDownSampler.cpp2
-rw-r--r--media/libstagefright/WAVExtractor.cpp6
-rw-r--r--media/libstagefright/WVMExtractor.cpp2
-rw-r--r--media/libstagefright/codecs/aacenc/AACEncoder.cpp14
-rw-r--r--media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp4
-rw-r--r--media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp10
-rw-r--r--media/libstagefright/codecs/avc/enc/AVCEncoder.cpp8
-rw-r--r--media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp6
-rw-r--r--media/libstagefright/colorconversion/ColorConverter.cpp2
-rw-r--r--media/libstagefright/id3/Android.mk2
-rw-r--r--media/libstagefright/id3/ID3.cpp2
-rw-r--r--media/libstagefright/id3/testid3.cpp4
-rw-r--r--media/libstagefright/include/AwesomePlayer.h2
-rw-r--r--media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp2
-rw-r--r--media/libstagefright/omx/OMX.cpp4
-rw-r--r--media/libstagefright/omx/OMXComponentBase.cpp4
-rw-r--r--media/libstagefright/omx/OMXMaster.cpp2
-rw-r--r--media/libstagefright/omx/OMXNodeInstance.cpp6
-rw-r--r--media/libstagefright/omx/tests/Android.mk2
-rw-r--r--media/libstagefright/omx/tests/OMXHarness.cpp32
-rw-r--r--media/libstagefright/tests/SurfaceMediaSource_test.cpp10
-rw-r--r--media/libstagefright/timedtext/TimedTextInBandSource.cpp2
-rw-r--r--media/libstagefright/timedtext/TimedTextPlayer.cpp2
-rw-r--r--media/libstagefright/yuv/YUVCanvas.cpp2
-rw-r--r--media/libstagefright/yuv/YUVImage.cpp2
-rw-r--r--media/tests/omxjpegdecoder/Android.mk1
-rw-r--r--media/tests/omxjpegdecoder/SkOmxPixelRef.cpp4
-rw-r--r--media/tests/omxjpegdecoder/StreamSource.cpp2
-rw-r--r--media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp6
-rw-r--r--packages/SettingsProvider/res/values/defaults.xml1
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java3
-rw-r--r--policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java8
-rw-r--r--policy/src/com/android/internal/policy/impl/PhoneWindow.java4
-rwxr-xr-xpolicy/src/com/android/internal/policy/impl/PhoneWindowManager.java6
-rw-r--r--services/audioflinger/Android.mk7
-rw-r--r--services/audioflinger/AudioFlinger.cpp250
-rw-r--r--services/audioflinger/AudioFlinger.h142
-rw-r--r--services/audioflinger/AudioMixer.cpp7
-rw-r--r--services/audioflinger/AudioMixer.h2
-rw-r--r--services/audioflinger/AudioPolicyService.cpp24
-rw-r--r--services/audioflinger/AudioResampler.cpp4
-rw-r--r--services/audioflinger/AudioResampler.h6
-rw-r--r--services/audioflinger/AudioResamplerSinc.cpp23
-rw-r--r--services/audioflinger/ServiceUtilities.cpp55
-rw-r--r--services/audioflinger/ServiceUtilities.h27
-rw-r--r--services/input/InputDispatcher.cpp1365
-rw-r--r--services/input/InputDispatcher.h163
-rw-r--r--services/java/com/android/server/AppWidgetServiceImpl.java22
-rw-r--r--services/java/com/android/server/NetworkTimeUpdateService.java9
-rw-r--r--services/java/com/android/server/SystemBackupAgent.java26
-rw-r--r--services/java/com/android/server/WallpaperManagerService.java740
-rw-r--r--services/java/com/android/server/WiredAccessoryObserver.java8
-rw-r--r--services/java/com/android/server/accessibility/AccessibilityManagerService.java37
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java1053
-rw-r--r--services/java/com/android/server/am/ActivityStack.java14
-rw-r--r--services/java/com/android/server/am/BroadcastQueue.java1017
-rw-r--r--services/java/com/android/server/am/BroadcastRecord.java4
-rw-r--r--services/java/com/android/server/am/CompatModePackages.java2
-rw-r--r--services/java/com/android/server/am/ProviderMap.java2
-rw-r--r--services/java/com/android/server/pm/Settings.java34
-rw-r--r--services/java/com/android/server/usb/UsbDeviceManager.java70
-rw-r--r--services/java/com/android/server/wm/InputManager.java19
-rw-r--r--services/java/com/android/server/wm/ScreenRotationAnimation.java42
-rw-r--r--services/java/com/android/server/wm/WindowManagerService.java23
-rw-r--r--services/jni/com_android_server_InputManager.cpp10
-rw-r--r--telephony/java/android/telephony/PhoneNumberUtils.java11
-rw-r--r--telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java17
-rw-r--r--test-runner/src/android/test/mock/MockContext.java6
-rw-r--r--tests/BiDiTests/res/layout/grid_layout_ltr.xml21
-rw-r--r--tests/BiDiTests/res/layout/grid_layout_rtl.xml21
-rw-r--r--tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeLtr.java5
-rw-r--r--tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeRtl.java5
-rw-r--r--tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java9
-rw-r--r--tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/mandelbrot.rs5
-rw-r--r--tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java3
-rw-r--r--tests/RenderScriptTests/PerfTest/res/raw/singletexfm.glsl8
-rw-r--r--tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java19
-rw-r--r--tests/RenderScriptTests/PerfTest/src/com/android/perftest/fill_test.rs31
-rw-r--r--tests/RenderScriptTests/SceneGraph/Android.mk26
-rw-r--r--tests/RenderScriptTests/SceneGraph/AndroidManifest.xml22
-rw-r--r--tests/RenderScriptTests/SceneGraph/assets/blue.jpgbin0 -> 12773 bytes
-rw-r--r--tests/RenderScriptTests/SceneGraph/assets/carbonfiber.jpgbin0 -> 17021 bytes
-rw-r--r--tests/RenderScriptTests/SceneGraph/assets/green.jpgbin0 -> 12368 bytes
-rw-r--r--tests/RenderScriptTests/SceneGraph/assets/grey.jpgbin0 -> 10744 bytes
-rw-r--r--tests/RenderScriptTests/SceneGraph/assets/orange.jpgbin0 -> 11574 bytes
-rw-r--r--tests/RenderScriptTests/SceneGraph/assets/orientation_test.a3dbin0 -> 346140 bytes
-rw-r--r--tests/RenderScriptTests/SceneGraph/assets/orientation_test.dae1102
-rw-r--r--tests/RenderScriptTests/SceneGraph/assets/paint.jpgbin0 -> 11350 bytes
-rw-r--r--tests/RenderScriptTests/SceneGraph/assets/red.jpgbin0 -> 11975 bytes
-rw-r--r--tests/RenderScriptTests/SceneGraph/res/drawable-nodpi/robot.pngbin0 -> 292580 bytes
-rw-r--r--tests/RenderScriptTests/SceneGraph/res/menu/loader_menu.xml25
-rw-r--r--tests/RenderScriptTests/SceneGraph/res/raw/blur_h.glsl15
-rw-r--r--tests/RenderScriptTests/SceneGraph/res/raw/blur_v.glsl17
-rw-r--r--tests/RenderScriptTests/SceneGraph/res/raw/blur_vertex.glsl7
-rw-r--r--tests/RenderScriptTests/SceneGraph/res/raw/diffuse.glsl19
-rw-r--r--tests/RenderScriptTests/SceneGraph/res/raw/metal.glsl23
-rw-r--r--tests/RenderScriptTests/SceneGraph/res/raw/paintf.glsl26
-rw-r--r--tests/RenderScriptTests/SceneGraph/res/raw/plastic.glsl22
-rw-r--r--tests/RenderScriptTests/SceneGraph/res/raw/plastic_lights.glsl29
-rw-r--r--tests/RenderScriptTests/SceneGraph/res/raw/robot.a3dbin0 -> 144528 bytes
-rw-r--r--tests/RenderScriptTests/SceneGraph/res/raw/select_color.glsl13
-rw-r--r--tests/RenderScriptTests/SceneGraph/res/raw/shader2v.glsl17
-rw-r--r--tests/RenderScriptTests/SceneGraph/res/raw/texture.glsl7
-rw-r--r--tests/RenderScriptTests/SceneGraph/res/values/strings.xml24
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Camera.java118
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaParser.java563
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaScene.java139
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/CompoundTransform.java197
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Float4Param.java146
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/FragmentShader.java167
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/LightBase.java111
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/MatrixTransform.java60
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/PointLight.java43
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderPass.java124
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderState.java111
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Renderable.java214
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableBase.java39
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableGroup.java47
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Scene.java308
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneGraphBase.java61
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java355
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Shader.java76
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java162
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Texture2D.java97
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureBase.java57
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureCube.java104
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureParam.java67
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureRenderTarget.java69
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Transform.java98
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TransformParam.java85
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/VertexShader.java108
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/camera.rs66
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/cull.rs86
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/export.rs61
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/fragment_params.rs30
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/light.rs33
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/object_params.rs36
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh193
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs240
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh323
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs127
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/vertex_params.rs29
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FileSelector.java110
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FullscreenBlur.java192
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestApp.java115
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppLoadingScreen.java113
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppRS.java265
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppView.java152
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TouchHandler.java114
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs86
-rw-r--r--tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rsh52
-rw-r--r--tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java6
-rw-r--r--tests/RenderScriptTests/tests/src/com/android/rs/test/UT_array_init.java95
-rw-r--r--tests/RenderScriptTests/tests/src/com/android/rs/test/UT_element.java132
-rw-r--r--tests/RenderScriptTests/tests/src/com/android/rs/test/UT_mesh.java75
-rw-r--r--tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_raster.java81
-rw-r--r--tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_store.java175
-rw-r--r--tests/RenderScriptTests/tests/src/com/android/rs/test/UT_sampler.java150
-rw-r--r--tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java2
-rw-r--r--tests/RenderScriptTests/tests/src/com/android/rs/test/array_init.rs58
-rw-r--r--tests/RenderScriptTests/tests/src/com/android/rs/test/element.rs158
-rw-r--r--tests/RenderScriptTests/tests/src/com/android/rs/test/mesh.rs64
-rw-r--r--tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs37
-rw-r--r--tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs128
-rw-r--r--tests/RenderScriptTests/tests/src/com/android/rs/test/sampler.rs63
-rwxr-xr-xtools/aidl/Type.cpp78
-rwxr-xr-xtools/aidl/Type.h2
-rw-r--r--tools/aidl/aidl.cpp9
-rw-r--r--tools/aidl/generate_java_rpc.cpp33
-rw-r--r--wifi/java/android/net/wifi/WifiStateMachine.java13
364 files changed, 15729 insertions, 5202 deletions
diff --git a/api/current.txt b/api/current.txt
index 9a1d394bc862..7edfa5316dbc 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -26407,10 +26407,12 @@ package android.widget {
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.Alignment CENTER;
+ field public static final android.widget.GridLayout.Alignment END;
field public static final android.widget.GridLayout.Alignment FILL;
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;
+ field public static final android.widget.GridLayout.Alignment START;
field public static final android.widget.GridLayout.Alignment TOP;
field public static final int UNDEFINED = -2147483648; // 0x80000000
field public static final int VERTICAL = 1; // 0x1
diff --git a/cmds/keystore/keystore.cpp b/cmds/keystore/keystore.cpp
index 05f77e5326d9..2c9cb35b7b25 100644
--- a/cmds/keystore/keystore.cpp
+++ b/cmds/keystore/keystore.cpp
@@ -581,7 +581,7 @@ static ResponseCode get(KeyStore* keyStore, int sock, uid_t uid, Value* keyName,
static ResponseCode insert(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value* val) {
char filename[NAME_MAX];
encode_key(filename, uid, keyName);
- Blob keyBlob(val->value, val->length, 0, NULL);
+ Blob keyBlob(val->value, val->length, NULL, 0);
return keyStore->put(filename, &keyBlob);
}
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index e9642f7cc8c5..11e94e83796b 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -35,7 +35,7 @@ LOCAL_SRC_FILES:= \
record.cpp
LOCAL_SHARED_LIBRARIES := \
- libstagefright liblog libutils libbinder
+ libstagefright liblog libutils libbinder libstagefright_foundation
LOCAL_C_INCLUDES:= \
$(JNI_H_INCLUDE) \
@@ -59,7 +59,7 @@ LOCAL_SRC_FILES:= \
recordvideo.cpp
LOCAL_SHARED_LIBRARIES := \
- libstagefright liblog libutils libbinder
+ libstagefright liblog libutils libbinder libstagefright_foundation
LOCAL_C_INCLUDES:= \
$(JNI_H_INCLUDE) \
@@ -84,7 +84,7 @@ LOCAL_SRC_FILES:= \
audioloop.cpp
LOCAL_SHARED_LIBRARIES := \
- libstagefright liblog libutils libbinder
+ libstagefright liblog libutils libbinder libstagefright_foundation
LOCAL_C_INCLUDES:= \
$(JNI_H_INCLUDE) \
diff --git a/cmds/stagefright/SineSource.cpp b/cmds/stagefright/SineSource.cpp
index 021f636e2eb0..14b43061c1d8 100644
--- a/cmds/stagefright/SineSource.cpp
+++ b/cmds/stagefright/SineSource.cpp
@@ -3,7 +3,7 @@
#include <math.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
diff --git a/cmds/stagefright/audioloop.cpp b/cmds/stagefright/audioloop.cpp
index 858681f6ce45..a6362a47c208 100644
--- a/cmds/stagefright/audioloop.cpp
+++ b/cmds/stagefright/audioloop.cpp
@@ -2,10 +2,10 @@
#include <binder/ProcessState.h>
#include <media/mediarecorder.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/AMRWriter.h>
#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/AudioSource.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/OMXClient.h>
@@ -24,7 +24,7 @@ int main() {
android::ProcessState::self()->startThreadPool();
OMXClient client;
- CHECK_EQ(client.connect(), OK);
+ CHECK_EQ(client.connect(), (status_t)OK);
#if 0
sp<MediaSource> source = new SineSource(kSampleRate, kNumChannels);
@@ -82,7 +82,7 @@ int main() {
delete player;
player = NULL;
#elif 0
- CHECK_EQ(decoder->start(), OK);
+ CHECK_EQ(decoder->start(), (status_t)OK);
MediaBuffer *buffer;
while (decoder->read(&buffer) == OK) {
@@ -95,7 +95,7 @@ int main() {
buffer = NULL;
}
- CHECK_EQ(decoder->stop(), OK);
+ CHECK_EQ(decoder->stop(), (status_t)OK);
#endif
#endif
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 770305860895..45c3f7b7aabe 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -17,11 +17,11 @@
#include "SineSource.h"
#include <binder/ProcessState.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/CameraSource.h>
#include <media/stagefright/FileSource.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MediaExtractor.h>
@@ -183,7 +183,7 @@ int main(int argc, char **argv) {
return 1;
}
OMXClient client;
- CHECK_EQ(client.connect(), OK);
+ CHECK_EQ(client.connect(), (status_t)OK);
status_t err = OK;
@@ -231,14 +231,14 @@ int main(int argc, char **argv) {
sp<MPEG4Writer> writer = new MPEG4Writer("/sdcard/output.mp4");
writer->addSource(encoder);
writer->setMaxFileDuration(kDurationUs);
- CHECK_EQ(OK, writer->start());
+ CHECK_EQ((status_t)OK, writer->start());
while (!writer->reachedEOS()) {
fprintf(stderr, ".");
usleep(100000);
}
err = writer->stop();
#else
- CHECK_EQ(OK, encoder->start());
+ CHECK_EQ((status_t)OK, encoder->start());
MediaBuffer *buffer;
while (encoder->read(&buffer) == OK) {
@@ -272,7 +272,7 @@ int main(int argc, char **argv) {
for (int i = 0; i < 100; ++i) {
MediaBuffer *buffer;
status_t err = source->read(&buffer);
- CHECK_EQ(err, OK);
+ CHECK_EQ(err, (status_t)OK);
printf("got a frame, data=%p, size=%d\n",
buffer->data(), buffer->range_length());
@@ -299,7 +299,7 @@ int main(int argc, char **argv) {
android::ProcessState::self()->startThreadPool();
OMXClient client;
- CHECK_EQ(client.connect(), OK);
+ CHECK_EQ(client.connect(), (status_t)OK);
const int32_t kSampleRate = 22050;
const int32_t kNumChannels = 2;
diff --git a/cmds/stagefright/recordvideo.cpp b/cmds/stagefright/recordvideo.cpp
index c40228631ae2..3bd1fe22f663 100644
--- a/cmds/stagefright/recordvideo.cpp
+++ b/cmds/stagefright/recordvideo.cpp
@@ -17,9 +17,9 @@
#include "SineSource.h"
#include <binder/ProcessState.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/AudioPlayer.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MPEG4Writer.h>
@@ -243,7 +243,7 @@ int main(int argc, char **argv) {
}
OMXClient client;
- CHECK_EQ(client.connect(), OK);
+ CHECK_EQ(client.connect(), (status_t)OK);
status_t err = OK;
sp<MediaSource> source =
@@ -283,7 +283,7 @@ int main(int argc, char **argv) {
sp<MPEG4Writer> writer = new MPEG4Writer(fileName);
writer->addSource(encoder);
int64_t start = systemTime();
- CHECK_EQ(OK, writer->start());
+ CHECK_EQ((status_t)OK, writer->start());
while (!writer->reachedEOS()) {
}
err = writer->stop();
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index dfea7285bdaf..5a364665768d 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -670,8 +670,9 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
String resolvedType = data.readString();
b = data.readStrongBinder();
int fl = data.readInt();
+ int userId = data.readInt();
IServiceConnection conn = IServiceConnection.Stub.asInterface(b);
- int res = bindService(app, token, service, resolvedType, conn, fl);
+ int res = bindService(app, token, service, resolvedType, conn, fl, userId);
reply.writeNoException();
reply.writeInt(res);
return true;
@@ -2288,7 +2289,7 @@ class ActivityManagerProxy implements IActivityManager
}
public int bindService(IApplicationThread caller, IBinder token,
Intent service, String resolvedType, IServiceConnection connection,
- int flags) throws RemoteException {
+ int flags, int userId) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
@@ -2298,6 +2299,7 @@ class ActivityManagerProxy implements IActivityManager
data.writeString(resolvedType);
data.writeStrongBinder(connection.asBinder());
data.writeInt(flags);
+ data.writeInt(userId);
mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0);
reply.readException();
int res = reply.readInt();
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 37900b6fd095..ebf692a99080 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1125,6 +1125,12 @@ class ContextImpl extends Context {
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
+ return bindService(service, conn, flags, UserId.getUserId(Process.myUid()));
+ }
+
+ /** @hide */
+ @Override
+ public boolean bindService(Intent service, ServiceConnection conn, int flags, int userId) {
IServiceConnection sd;
if (mPackageInfo != null) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
@@ -1143,7 +1149,7 @@ class ContextImpl extends Context {
int res = ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(), getActivityToken(),
service, service.resolveTypeIfNeeded(getContentResolver()),
- sd, flags);
+ sd, flags, userId);
if (res < 0) {
throw new SecurityException(
"Not allowed to bind to service " + service);
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index a62f72401ae6..7deb615f6f9f 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -166,7 +166,7 @@ public interface IActivityManager extends IInterface {
int id, Notification notification, boolean keepNotification) throws RemoteException;
public int bindService(IApplicationThread caller, IBinder token,
Intent service, String resolvedType,
- IServiceConnection connection, int flags) throws RemoteException;
+ IServiceConnection connection, int flags, int userId) throws RemoteException;
public boolean unbindService(IServiceConnection connection) throws RemoteException;
public void publishService(IBinder token,
Intent intent, IBinder service) throws RemoteException;
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index abd1c5b809c8..c057d66fb3bf 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -30,6 +30,7 @@ import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
diff --git a/core/java/android/app/backup/WallpaperBackupHelper.java b/core/java/android/app/backup/WallpaperBackupHelper.java
index 170171e3000a..a74a2689c0be 100644
--- a/core/java/android/app/backup/WallpaperBackupHelper.java
+++ b/core/java/android/app/backup/WallpaperBackupHelper.java
@@ -38,15 +38,23 @@ public class WallpaperBackupHelper extends FileBackupHelperBase implements Backu
private static final boolean DEBUG = false;
// This path must match what the WallpaperManagerService uses
- private static final String WALLPAPER_IMAGE = "/data/data/com.android.settings/files/wallpaper";
+ // TODO: Will need to change if backing up non-primary user's wallpaper
+ public static final String WALLPAPER_IMAGE = "/data/system/users/0/wallpaper";
+ public static final String WALLPAPER_INFO = "/data/system/users/0/wallpaper_info.xml";
+ // Use old keys to keep legacy data compatibility and avoid writing two wallpapers
+ public static final String WALLPAPER_IMAGE_KEY =
+ "/data/data/com.android.settings/files/wallpaper";
+ public static final String WALLPAPER_INFO_KEY = "/data/system/wallpaper_info.xml";
// Stage file - should be adjacent to the WALLPAPER_IMAGE location. The wallpapers
// will be saved to this file from the restore stream, then renamed to the proper
// location if it's deemed suitable.
- private static final String STAGE_FILE = "/data/data/com.android.settings/files/wallpaper-tmp";
+ // TODO: Will need to change if backing up non-primary user's wallpaper
+ private static final String STAGE_FILE = "/data/system/users/0/wallpaper-tmp";
Context mContext;
String[] mFiles;
+ String[] mKeys;
double mDesiredMinWidth;
double mDesiredMinHeight;
@@ -57,11 +65,12 @@ public class WallpaperBackupHelper extends FileBackupHelperBase implements Backu
* @param context
* @param files
*/
- public WallpaperBackupHelper(Context context, String... files) {
+ public WallpaperBackupHelper(Context context, String[] files, String[] keys) {
super(context);
mContext = context;
mFiles = files;
+ mKeys = keys;
WallpaperManager wpm;
wpm = (WallpaperManager) context.getSystemService(Context.WALLPAPER_SERVICE);
@@ -89,7 +98,7 @@ public class WallpaperBackupHelper extends FileBackupHelperBase implements Backu
*/
public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState) {
- performBackup_checked(oldState, data, newState, mFiles, mFiles);
+ performBackup_checked(oldState, data, newState, mFiles, mKeys);
}
/**
@@ -99,8 +108,8 @@ public class WallpaperBackupHelper extends FileBackupHelperBase implements Backu
*/
public void restoreEntity(BackupDataInputStream data) {
final String key = data.getKey();
- if (isKeyInList(key, mFiles)) {
- if (key.equals(WALLPAPER_IMAGE)) {
+ if (isKeyInList(key, mKeys)) {
+ if (key.equals(WALLPAPER_IMAGE_KEY)) {
// restore the file to the stage for inspection
File f = new File(STAGE_FILE);
if (writeFile(f, data)) {
@@ -135,9 +144,9 @@ public class WallpaperBackupHelper extends FileBackupHelperBase implements Backu
f.delete();
}
}
- } else {
- // Some other normal file; just decode it to its destination
- File f = new File(key);
+ } else if (key.equals(WALLPAPER_INFO_KEY)) {
+ // XML file containing wallpaper info
+ File f = new File(WALLPAPER_INFO);
writeFile(f, data);
}
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 3d4e35461998..6d4cdaee1060 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1307,6 +1307,15 @@ public abstract class Context {
int flags);
/**
+ * Same as {@link #bindService(Intent, ServiceConnection, int)}, but with an explicit userId
+ * argument for use by system server and other multi-user aware code.
+ * @hide
+ */
+ public boolean bindService(Intent service, ServiceConnection conn, int flags, int userId) {
+ throw new RuntimeException("Not implemented. Must override in a subclass.");
+ }
+
+ /**
* Disconnect from an application service. You will no longer receive
* calls as the service is restarted, and the service is now allowed to
* stop at any time.
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 3928aaf62d10..cd8d87f9d057 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -370,6 +370,12 @@ public class ContextWrapper extends Context {
return mBase.bindService(service, conn, flags);
}
+ /** @hide */
+ @Override
+ public boolean bindService(Intent service, ServiceConnection conn, int flags, int userId) {
+ return mBase.bindService(service, conn, flags, userId);
+ }
+
@Override
public void unbindService(ServiceConnection conn) {
mBase.unbindService(conn);
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 2023f82cb6d1..8029bd51c8d1 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3380,7 +3380,8 @@ public class PackageParser {
public static final ServiceInfo generateServiceInfo(Service s, int flags, int userId) {
if (s == null) return null;
- if (!copyNeeded(flags, s.owner, s.metaData) && userId == 0) {
+ if (!copyNeeded(flags, s.owner, s.metaData)
+ && userId == UserId.getUserId(s.info.applicationInfo.uid)) {
return s.info;
}
// Make shallow copies so we can store the metadata safely
diff --git a/core/java/android/net/EthernetDataTracker.java b/core/java/android/net/EthernetDataTracker.java
index 02e81b6a8697..fb09ba5402e2 100644
--- a/core/java/android/net/EthernetDataTracker.java
+++ b/core/java/android/net/EthernetDataTracker.java
@@ -49,6 +49,7 @@ public class EthernetDataTracker implements NetworkStateTracker {
private LinkCapabilities mLinkCapabilities;
private NetworkInfo mNetworkInfo;
private InterfaceObserver mInterfaceObserver;
+ private String mHwAddr;
/* For sending events to connectivity service handler */
private Handler mCsHandler;
@@ -74,6 +75,7 @@ public class EthernetDataTracker implements NetworkStateTracker {
if (mIface.equals(iface) && mLinkUp != up) {
Log.d(TAG, "Interface " + iface + " link " + (up ? "up" : "down"));
mLinkUp = up;
+ mTracker.mNetworkInfo.setIsAvailable(up);
// use DHCP
if (up) {
@@ -101,10 +103,6 @@ public class EthernetDataTracker implements NetworkStateTracker {
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_ETHERNET, 0, NETWORKTYPE, "");
mLinkProperties = new LinkProperties();
mLinkCapabilities = new LinkCapabilities();
- mLinkUp = false;
-
- mNetworkInfo.setIsAvailable(false);
- setTeardownRequested(false);
}
private void interfaceAdded(String iface) {
@@ -113,7 +111,7 @@ public class EthernetDataTracker implements NetworkStateTracker {
Log.d(TAG, "Adding " + iface);
- synchronized(mIface) {
+ synchronized(this) {
if(!mIface.isEmpty())
return;
mIface = iface;
@@ -122,8 +120,6 @@ public class EthernetDataTracker implements NetworkStateTracker {
mNetworkInfo.setIsAvailable(true);
Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
msg.sendToTarget();
-
- runDhcp();
}
public void disconnect() {
@@ -132,7 +128,7 @@ public class EthernetDataTracker implements NetworkStateTracker {
mLinkProperties.clear();
mNetworkInfo.setIsAvailable(false);
- mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
+ mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr);
Message msg = mCsHandler.obtainMessage(EVENT_CONFIGURATION_CHANGED, mNetworkInfo);
msg.sendToTarget();
@@ -154,7 +150,7 @@ public class EthernetDataTracker implements NetworkStateTracker {
return;
Log.d(TAG, "Removing " + iface);
- disconnect();
+ disconnect();
mIface = "";
}
@@ -169,7 +165,7 @@ public class EthernetDataTracker implements NetworkStateTracker {
mLinkProperties = dhcpInfoInternal.makeLinkProperties();
mLinkProperties.setInterfaceName(mIface);
- mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, null);
+ mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr);
Message msg = mCsHandler.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
msg.sendToTarget();
}
@@ -216,8 +212,15 @@ public class EthernetDataTracker implements NetworkStateTracker {
for (String iface : ifaces) {
if (iface.matches(sIfaceMatch)) {
mIface = iface;
+ service.setInterfaceUp(iface);
InterfaceConfiguration config = service.getInterfaceConfig(iface);
mLinkUp = config.isActive();
+ if (config != null && mHwAddr == null) {
+ mHwAddr = config.getHardwareAddress();
+ if (mHwAddr != null) {
+ mNetworkInfo.setExtraInfo(mHwAddr);
+ }
+ }
reconnect();
break;
}
@@ -247,9 +250,11 @@ public class EthernetDataTracker implements NetworkStateTracker {
* Re-enable connectivity to a network after a {@link #teardown()}.
*/
public boolean reconnect() {
- mTeardownRequested.set(false);
- runDhcp();
- return true;
+ if (mLinkUp) {
+ mTeardownRequested.set(false);
+ runDhcp();
+ }
+ return mLinkUp;
}
/**
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index 7286f0dc6010..2f43cb87f6fc 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -351,6 +351,18 @@ public class NetworkInfo implements Parcelable {
}
/**
+ * Set the extraInfo field.
+ * @param extraInfo an optional {@code String} providing addditional network state
+ * information passed up from the lower networking layers.
+ * @hide
+ */
+ public void setExtraInfo(String extraInfo) {
+ synchronized (this) {
+ this.mExtraInfo = extraInfo;
+ }
+ }
+
+ /**
* Report the reason an attempt to establish connectivity failed,
* if one is available.
* @return the reason for failure, or null if not available
diff --git a/core/java/android/os/UserId.java b/core/java/android/os/UserId.java
index 286b6748ba5c..0da67d63ef94 100644
--- a/core/java/android/os/UserId.java
+++ b/core/java/android/os/UserId.java
@@ -73,6 +73,10 @@ public final class UserId {
}
}
+ public static final int getCallingUserId() {
+ return getUserId(Binder.getCallingUid());
+ }
+
/**
* Returns the uid that is composed from the userId and the appId.
* @hide
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 95a3cdc6ad8d..43dfc8183ec6 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -1325,7 +1325,11 @@ public class TextUtils {
sb.append("&amp;"); //$NON-NLS-1$
break;
case '\'':
- sb.append("&apos;"); //$NON-NLS-1$
+ //http://www.w3.org/TR/xhtml1
+ // The named character reference &apos; (the apostrophe, U+0027) was introduced in
+ // XML 1.0 but does not appear in HTML. Authors should therefore use &#39; instead
+ // of &apos; to work as expected in HTML 4 user agents.
+ sb.append("&#39;"); //$NON-NLS-1$
break;
case '"':
sb.append("&quot;"); //$NON-NLS-1$
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index 3ee275cb6399..3e2d7fc60241 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -31,12 +31,20 @@ import android.util.Log;
* This object is thread-safe. Other threads can add and remove listeners
* or schedule work to occur at a later time on the UI thread.
*
+ * Ensuring thread-safety is a little tricky because the {@link DisplayEventReceiver}
+ * can only be accessed from the UI thread so operations that touch the event receiver
+ * are posted to the UI thread if needed.
+ *
* @hide
*/
public final class Choreographer extends Handler {
private static final String TAG = "Choreographer";
private static final boolean DEBUG = false;
+ // Amount of time in ms to wait before actually disposing of the display event
+ // receiver after all listeners have been removed.
+ private static final long DISPOSE_RECEIVER_DELAY = 200;
+
// The default amount of time in ms between animation frames.
// When vsync is not enabled, we want to have some idea of how long we should
// wait before posting the next animation message. It is important that the
@@ -78,6 +86,8 @@ public final class Choreographer extends Handler {
private static final int MSG_DO_ANIMATION = 0;
private static final int MSG_DO_DRAW = 1;
+ private static final int MSG_DO_SCHEDULE_VSYNC = 2;
+ private static final int MSG_DO_DISPOSE_RECEIVER = 3;
private final Object mLock = new Object();
@@ -88,6 +98,7 @@ public final class Choreographer extends Handler {
private boolean mAnimationScheduled;
private boolean mDrawScheduled;
+ private boolean mFrameDisplayEventReceiverNeeded;
private FrameDisplayEventReceiver mFrameDisplayEventReceiver;
private long mLastAnimationTime;
private long mLastDrawTime;
@@ -158,10 +169,21 @@ public final class Choreographer extends Handler {
if (DEBUG) {
Log.d(TAG, "Scheduling vsync for animation.");
}
- if (mFrameDisplayEventReceiver == null) {
- mFrameDisplayEventReceiver = new FrameDisplayEventReceiver(mLooper);
+
+ // If running on the Looper thread, then schedule the vsync immediately,
+ // otherwise post a message to schedule the vsync from the UI thread
+ // as soon as possible.
+ if (!mFrameDisplayEventReceiverNeeded) {
+ mFrameDisplayEventReceiverNeeded = true;
+ if (mFrameDisplayEventReceiver != null) {
+ removeMessages(MSG_DO_DISPOSE_RECEIVER);
+ }
+ }
+ if (isRunningOnLooperThreadLocked()) {
+ doScheduleVsyncLocked();
+ } else {
+ sendMessageAtFrontOfQueue(obtainMessage(MSG_DO_SCHEDULE_VSYNC));
}
- mFrameDisplayEventReceiver.scheduleVsync();
} else {
final long now = SystemClock.uptimeMillis();
final long nextAnimationTime = Math.max(mLastAnimationTime + sFrameDelay, now);
@@ -224,6 +246,12 @@ public final class Choreographer extends Handler {
case MSG_DO_DRAW:
doDraw();
break;
+ case MSG_DO_SCHEDULE_VSYNC:
+ doScheduleVsync();
+ break;
+ case MSG_DO_DISPOSE_RECEIVER:
+ doDisposeReceiver();
+ break;
}
}
@@ -295,6 +323,30 @@ public final class Choreographer extends Handler {
}
}
+ private void doScheduleVsync() {
+ synchronized (mLock) {
+ doScheduleVsyncLocked();
+ }
+ }
+
+ private void doScheduleVsyncLocked() {
+ if (mFrameDisplayEventReceiverNeeded && mAnimationScheduled) {
+ if (mFrameDisplayEventReceiver == null) {
+ mFrameDisplayEventReceiver = new FrameDisplayEventReceiver(mLooper);
+ }
+ mFrameDisplayEventReceiver.scheduleVsync();
+ }
+ }
+
+ private void doDisposeReceiver() {
+ synchronized (mLock) {
+ if (!mFrameDisplayEventReceiverNeeded && mFrameDisplayEventReceiver != null) {
+ mFrameDisplayEventReceiver.dispose();
+ mFrameDisplayEventReceiver = null;
+ }
+ }
+ }
+
/**
* Adds an animation listener.
*
@@ -386,7 +438,9 @@ public final class Choreographer extends Handler {
if (mAnimationScheduled) {
mAnimationScheduled = false;
- if (!USE_VSYNC) {
+ if (USE_VSYNC) {
+ removeMessages(MSG_DO_SCHEDULE_VSYNC);
+ } else {
removeMessages(MSG_DO_ANIMATION);
}
}
@@ -398,13 +452,24 @@ public final class Choreographer extends Handler {
}
}
- if (mFrameDisplayEventReceiver != null) {
- mFrameDisplayEventReceiver.dispose();
- mFrameDisplayEventReceiver = null;
+ // Post a message to dispose the display event receiver if we haven't needed
+ // it again after a certain amount of time has elapsed. Another reason to
+ // defer disposal is that it is possible for use to attempt to dispose the
+ // receiver while handling a vsync event that it dispatched, which might
+ // cause a few problems...
+ if (mFrameDisplayEventReceiverNeeded) {
+ mFrameDisplayEventReceiverNeeded = false;
+ if (mFrameDisplayEventReceiver != null) {
+ sendEmptyMessageDelayed(MSG_DO_DISPOSE_RECEIVER, DISPOSE_RECEIVER_DELAY);
+ }
}
}
}
+ private boolean isRunningOnLooperThreadLocked() {
+ return Looper.myLooper() == mLooper;
+ }
+
/**
* Listens for animation frame timing events.
*/
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index d6711ee63982..6c2e54018592 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -25,6 +25,10 @@ import android.util.Log;
/**
* Provides a low-level mechanism for an application to receive display events
* such as vertical sync.
+ *
+ * The display event receive is NOT thread safe. Moreover, its methods must only
+ * be called on the Looper thread to which it is attached.
+ *
* @hide
*/
public abstract class DisplayEventReceiver {
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 9e8a228edfa1..1932c7f39608 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -39,6 +39,7 @@ import javax.microedition.khronos.egl.EGLSurface;
import javax.microedition.khronos.opengles.GL;
import java.io.File;
+import java.io.PrintWriter;
import static javax.microedition.khronos.egl.EGL10.*;
@@ -84,13 +85,27 @@ public abstract class HardwareRenderer {
static final String DISABLE_VSYNC_PROPERTY = "hwui.disable_vsync";
/**
+ * System property used to enable or disable hardware rendering profiling.
+ * The default value of this property is assumed to be false.
+ *
+ * When profiling is enabled, the adb shell dumpsys gfxinfo command will
+ * output extra information about the time taken to execute by the last
+ * frames.
+ *
+ * Possible values:
+ * "true", to enable profiling
+ * "false", to disable profiling
+ */
+ static final String PROFILE_PROPERTY = "hwui.profile";
+
+ /**
* System property used to debug EGL configuration choice.
*
* Possible values:
* "choice", print the chosen configuration only
* "all", print all possible configurations
*/
- static final String PRINT_CONFIG_PROPERTY = "hwui.print_config";
+ static final String PRINT_CONFIG_PROPERTY = "hwui.print_config";
/**
* Turn on to draw dirty regions every other frame.
@@ -112,6 +127,16 @@ public abstract class HardwareRenderer {
*/
public static boolean sSystemRendererDisabled = false;
+ /**
+ * Number of frames to profile.
+ */
+ private static final int PROFILE_MAX_FRAMES = 64;
+
+ /**
+ * Number of floats per profiled frame.
+ */
+ private static final int PROFILE_FRAME_DATA_COUNT = 3;
+
private boolean mEnabled;
private boolean mRequested = true;
@@ -226,6 +251,12 @@ public abstract class HardwareRenderer {
abstract HardwareCanvas getCanvas();
/**
+ * Outputs extra debugging information in the specified file descriptor.
+ * @param pw
+ */
+ abstract void dumpGfxInfo(PrintWriter pw);
+
+ /**
* Sets the directory to use as a persistent storage for hardware rendering
* resources.
*
@@ -439,6 +470,7 @@ public abstract class HardwareRenderer {
GL mGl;
HardwareCanvas mCanvas;
+
int mFrameCount;
Paint mDebugPaint;
@@ -456,6 +488,10 @@ public abstract class HardwareRenderer {
final boolean mVsyncDisabled;
+ final boolean mProfileEnabled;
+ final float[] mProfileData;
+ int mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT;
+
final int mGlVersion;
final boolean mTranslucent;
@@ -472,6 +508,34 @@ public abstract class HardwareRenderer {
if (mVsyncDisabled) {
Log.d(LOG_TAG, "Disabling v-sync");
}
+
+ //noinspection PointlessBooleanExpression,ConstantConditions
+ if (!ViewDebug.DEBUG_LATENCY) {
+ final String profileProperty = SystemProperties.get(PROFILE_PROPERTY, "false");
+ mProfileEnabled = "true".equalsIgnoreCase(profileProperty);
+ if (mProfileEnabled) {
+ Log.d(LOG_TAG, "Profiling hardware renderer");
+ }
+ } else {
+ mProfileEnabled = true;
+ }
+
+ if (mProfileEnabled) {
+ mProfileData = new float[PROFILE_MAX_FRAMES * PROFILE_FRAME_DATA_COUNT];
+ } else {
+ mProfileData = null;
+ }
+ }
+
+ @Override
+ void dumpGfxInfo(PrintWriter pw) {
+ if (mProfileEnabled) {
+ pw.printf("\n\tDraw\tProcess\tExecute\n");
+ for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
+ pw.printf("\t%3.2f\t%3.2f\t%3.2f\n", mProfileData[i], mProfileData[i + 1],
+ mProfileData[i + 2]);
+ }
+ }
}
/**
@@ -860,34 +924,49 @@ public abstract class HardwareRenderer {
(view.mPrivateFlags & View.INVALIDATED) == View.INVALIDATED;
view.mPrivateFlags &= ~View.INVALIDATED;
- final long getDisplayListStartTime;
- if (ViewDebug.DEBUG_LATENCY) {
+ long getDisplayListStartTime = 0;
+ if (mProfileEnabled) {
+ mProfileCurrentFrame += PROFILE_FRAME_DATA_COUNT;
+ if (mProfileCurrentFrame >= mProfileData.length) {
+ mProfileCurrentFrame = 0;
+ }
+
getDisplayListStartTime = System.nanoTime();
}
DisplayList displayList = view.getDisplayList();
- if (ViewDebug.DEBUG_LATENCY) {
+ if (mProfileEnabled) {
long now = System.nanoTime();
- Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- getDisplayList() took "
- + ((now - getDisplayListStartTime) * 0.000001f) + "ms");
+ float total = (now - getDisplayListStartTime) * 0.000001f;
+ //noinspection PointlessArithmeticExpression
+ mProfileData[mProfileCurrentFrame] = total;
+
+ if (ViewDebug.DEBUG_LATENCY) {
+ Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- getDisplayList() took " +
+ total + "ms");
+ }
}
if (displayList != null) {
- final long drawDisplayListStartTime;
- if (ViewDebug.DEBUG_LATENCY) {
+ long drawDisplayListStartTime = 0;
+ if (mProfileEnabled) {
drawDisplayListStartTime = System.nanoTime();
}
- boolean invalidateNeeded = canvas.drawDisplayList(
- displayList, view.getWidth(),
- view.getHeight(), mRedrawClip);
+ boolean invalidateNeeded = canvas.drawDisplayList(displayList,
+ view.getWidth(), view.getHeight(), mRedrawClip);
- if (ViewDebug.DEBUG_LATENCY) {
+ if (mProfileEnabled) {
long now = System.nanoTime();
- Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- drawDisplayList() took "
- + ((now - drawDisplayListStartTime) * 0.000001f)
- + "ms, invalidateNeeded=" + invalidateNeeded + ".");
+ float total = (now - drawDisplayListStartTime) * 0.000001f;
+ mProfileData[mProfileCurrentFrame + 1] = total;
+
+ if (ViewDebug.DEBUG_LATENCY) {
+ Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- drawDisplayList() took " +
+ total + "ms, invalidateNeeded=" +
+ invalidateNeeded + ".");
+ }
}
if (invalidateNeeded) {
@@ -922,17 +1001,22 @@ public abstract class HardwareRenderer {
attachInfo.mIgnoreDirtyState = false;
- final long eglSwapBuffersStartTime;
- if (ViewDebug.DEBUG_LATENCY) {
+ long eglSwapBuffersStartTime = 0;
+ if (mProfileEnabled) {
eglSwapBuffersStartTime = System.nanoTime();
}
sEgl.eglSwapBuffers(sEglDisplay, mEglSurface);
- if (ViewDebug.DEBUG_LATENCY) {
+ if (mProfileEnabled) {
long now = System.nanoTime();
- Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- eglSwapBuffers() took "
- + ((now - eglSwapBuffersStartTime) * 0.000001f) + "ms");
+ float total = (now - eglSwapBuffersStartTime) * 0.000001f;
+ mProfileData[mProfileCurrentFrame + 2] = total;
+
+ if (ViewDebug.DEBUG_LATENCY) {
+ Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- eglSwapBuffers() took " +
+ total + "ms");
+ }
}
checkEglErrors();
diff --git a/core/java/android/view/InputEventReceiver.java b/core/java/android/view/InputEventReceiver.java
index 764d8dcaba2a..6a457ece9b9d 100644
--- a/core/java/android/view/InputEventReceiver.java
+++ b/core/java/android/view/InputEventReceiver.java
@@ -21,6 +21,7 @@ import dalvik.system.CloseGuard;
import android.os.Looper;
import android.os.MessageQueue;
import android.util.Log;
+import android.util.SparseIntArray;
/**
* Provides a low-level mechanism for an application to receive input events.
@@ -38,13 +39,14 @@ public abstract class InputEventReceiver {
private InputChannel mInputChannel;
private MessageQueue mMessageQueue;
- // The sequence number of the event that is in progress.
- private int mEventSequenceNumberInProgress = -1;
+ // Map from InputEvent sequence numbers to dispatcher sequence numbers.
+ private final SparseIntArray mSeqMap = new SparseIntArray();
private static native int nativeInit(InputEventReceiver receiver,
InputChannel inputChannel, MessageQueue messageQueue);
private static native void nativeDispose(int receiverPtr);
- private static native void nativeFinishInputEvent(int receiverPtr, boolean handled);
+ private static native void nativeFinishInputEvent(int receiverPtr, int seq, boolean handled);
+ private static native void nativeConsumeBatchedInputEvents(int receiverPtr);
/**
* Creates an input event receiver bound to the specified input channel.
@@ -104,12 +106,25 @@ public abstract class InputEventReceiver {
}
/**
+ * Called when a batched input event is pending.
+ *
+ * The batched input event will continue to accumulate additional movement
+ * samples until the recipient calls {@link #consumeBatchedInputEvents} or
+ * an event is received that ends the batch and causes it to be consumed
+ * immediately (such as a pointer up event).
+ */
+ public void onBatchedInputEventPending() {
+ consumeBatchedInputEvents();
+ }
+
+ /**
* Finishes an input event and indicates whether it was handled.
+ * Must be called on the same Looper thread to which the receiver is attached.
*
* @param event The input event that was finished.
* @param handled True if the event was handled.
*/
- public void finishInputEvent(InputEvent event, boolean handled) {
+ public final void finishInputEvent(InputEvent event, boolean handled) {
if (event == null) {
throw new IllegalArgumentException("event must not be null");
}
@@ -117,23 +132,47 @@ public abstract class InputEventReceiver {
Log.w(TAG, "Attempted to finish an input event but the input event "
+ "receiver has already been disposed.");
} else {
- if (event.getSequenceNumber() != mEventSequenceNumberInProgress) {
+ int index = mSeqMap.indexOfKey(event.getSequenceNumber());
+ if (index < 0) {
Log.w(TAG, "Attempted to finish an input event that is not in progress.");
} else {
- mEventSequenceNumberInProgress = -1;
- nativeFinishInputEvent(mReceiverPtr, handled);
+ int seq = mSeqMap.valueAt(index);
+ mSeqMap.removeAt(index);
+ nativeFinishInputEvent(mReceiverPtr, seq, handled);
}
}
event.recycleIfNeededAfterDispatch();
}
+ /**
+ * Consumes all pending batched input events.
+ * Must be called on the same Looper thread to which the receiver is attached.
+ *
+ * This method forces all batched input events to be delivered immediately.
+ * Should be called just before animating or drawing a new frame in the UI.
+ */
+ public final void consumeBatchedInputEvents() {
+ if (mReceiverPtr == 0) {
+ Log.w(TAG, "Attempted to consume batched input events but the input event "
+ + "receiver has already been disposed.");
+ } else {
+ nativeConsumeBatchedInputEvents(mReceiverPtr);
+ }
+ }
+
// Called from native code.
@SuppressWarnings("unused")
- private void dispatchInputEvent(InputEvent event) {
- mEventSequenceNumberInProgress = event.getSequenceNumber();
+ private void dispatchInputEvent(int seq, InputEvent event) {
+ mSeqMap.put(event.getSequenceNumber(), seq);
onInputEvent(event);
}
+ // Called from native code.
+ @SuppressWarnings("unused")
+ private void dispatchBatchedInputEventPending() {
+ onBatchedInputEventPending();
+ }
+
public static interface Factory {
public InputEventReceiver createInputEventReceiver(
InputChannel inputChannel, Looper looper);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 7658d041cb1f..056be7ffaf09 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -65,6 +65,7 @@ import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeProvider;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
+import android.view.animation.Transformation;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
@@ -8252,6 +8253,9 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
throw new NullPointerException("Layout parameters cannot be null");
}
mLayoutParams = params;
+ if (mParent instanceof ViewGroup) {
+ ((ViewGroup) mParent).onSetLayoutParams(this, params);
+ }
requestLayout();
}
@@ -10947,6 +10951,346 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
}
/**
+ * Utility function, called by draw(canvas, parent, drawingTime) to handle the less common
+ * case of an active Animation being run on the view.
+ */
+ private boolean drawAnimation(ViewGroup parent, long drawingTime,
+ Animation a, boolean scalingRequired) {
+ Transformation invalidationTransform;
+ final int flags = parent.mGroupFlags;
+ final boolean initialized = a.isInitialized();
+ if (!initialized) {
+ a.initialize(mRight - mLeft, mBottom - mTop, getWidth(), getHeight());
+ a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop);
+ onAnimationStart();
+ }
+
+ boolean more = a.getTransformation(drawingTime, parent.mChildTransformation, 1f);
+ if (scalingRequired && mAttachInfo.mApplicationScale != 1f) {
+ if (parent.mInvalidationTransformation == null) {
+ parent.mInvalidationTransformation = new Transformation();
+ }
+ invalidationTransform = parent.mInvalidationTransformation;
+ a.getTransformation(drawingTime, invalidationTransform, 1f);
+ } else {
+ invalidationTransform = parent.mChildTransformation;
+ }
+ if (more) {
+ if (!a.willChangeBounds()) {
+ if ((flags & (parent.FLAG_OPTIMIZE_INVALIDATE | parent.FLAG_ANIMATION_DONE)) ==
+ parent.FLAG_OPTIMIZE_INVALIDATE) {
+ parent.mGroupFlags |= parent.FLAG_INVALIDATE_REQUIRED;
+ } else if ((flags & parent.FLAG_INVALIDATE_REQUIRED) == 0) {
+ // The child need to draw an animation, potentially offscreen, so
+ // make sure we do not cancel invalidate requests
+ parent.mPrivateFlags |= DRAW_ANIMATION;
+ parent.invalidate(mLeft, mTop, mRight, mBottom);
+ }
+ } else {
+ if (parent.mInvalidateRegion == null) {
+ parent.mInvalidateRegion = new RectF();
+ }
+ final RectF region = parent.mInvalidateRegion;
+ a.getInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop, region,
+ invalidationTransform);
+
+ // The child need to draw an animation, potentially offscreen, so
+ // make sure we do not cancel invalidate requests
+ parent.mPrivateFlags |= DRAW_ANIMATION;
+
+ final int left = mLeft + (int) region.left;
+ final int top = mTop + (int) region.top;
+ parent.invalidate(left, top, left + (int) (region.width() + .5f),
+ top + (int) (region.height() + .5f));
+ }
+ }
+ return more;
+ }
+
+ /**
+ * This method is called by ViewGroup.drawChild() to have each child view draw itself.
+ * This draw() method is an implementation detail and is not intended to be overridden or
+ * to be called from anywhere else other than ViewGroup.drawChild().
+ */
+ boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
+ boolean more = false;
+ final boolean childHasIdentityMatrix = hasIdentityMatrix();
+ final int flags = parent.mGroupFlags;
+
+ if ((flags & parent.FLAG_CLEAR_TRANSFORMATION) == parent.FLAG_CLEAR_TRANSFORMATION) {
+ parent.mChildTransformation.clear();
+ parent.mGroupFlags &= ~parent.FLAG_CLEAR_TRANSFORMATION;
+ }
+
+ Transformation transformToApply = null;
+ boolean concatMatrix = false;
+
+ boolean scalingRequired = false;
+ boolean caching;
+ int layerType = parent.mDrawLayers ? getLayerType() : LAYER_TYPE_NONE;
+
+ final boolean hardwareAccelerated = canvas.isHardwareAccelerated();
+ if ((flags & parent.FLAG_CHILDREN_DRAWN_WITH_CACHE) == parent.FLAG_CHILDREN_DRAWN_WITH_CACHE ||
+ (flags & parent.FLAG_ALWAYS_DRAWN_WITH_CACHE) == parent.FLAG_ALWAYS_DRAWN_WITH_CACHE) {
+ caching = true;
+ if (mAttachInfo != null) scalingRequired = mAttachInfo.mScalingRequired;
+ } else {
+ caching = (layerType != LAYER_TYPE_NONE) || hardwareAccelerated;
+ }
+
+ final Animation a = getAnimation();
+ if (a != null) {
+ more = drawAnimation(parent, drawingTime, a, scalingRequired);
+ concatMatrix = a.willChangeTransformationMatrix();
+ transformToApply = parent.mChildTransformation;
+ } else if ((flags & parent.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) ==
+ parent.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) {
+ final boolean hasTransform =
+ parent.getChildStaticTransformation(this, parent.mChildTransformation);
+ if (hasTransform) {
+ final int transformType = parent.mChildTransformation.getTransformationType();
+ transformToApply = transformType != Transformation.TYPE_IDENTITY ?
+ parent.mChildTransformation : null;
+ concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0;
+ }
+ }
+
+ concatMatrix |= !childHasIdentityMatrix;
+
+ // Sets the flag as early as possible to allow draw() implementations
+ // to call invalidate() successfully when doing animations
+ mPrivateFlags |= DRAWN;
+
+ if (!concatMatrix && canvas.quickReject(mLeft, mTop, mRight, mBottom, Canvas.EdgeType.BW) &&
+ (mPrivateFlags & DRAW_ANIMATION) == 0) {
+ return more;
+ }
+
+ if (hardwareAccelerated) {
+ // Clear INVALIDATED flag to allow invalidation to occur during rendering, but
+ // retain the flag's value temporarily in the mRecreateDisplayList flag
+ mRecreateDisplayList = (mPrivateFlags & INVALIDATED) == INVALIDATED;
+ mPrivateFlags &= ~INVALIDATED;
+ }
+
+ computeScroll();
+
+ final int sx = mScrollX;
+ final int sy = mScrollY;
+
+ DisplayList displayList = null;
+ Bitmap cache = null;
+ boolean hasDisplayList = false;
+ if (caching) {
+ if (!hardwareAccelerated) {
+ if (layerType != LAYER_TYPE_NONE) {
+ layerType = LAYER_TYPE_SOFTWARE;
+ buildDrawingCache(true);
+ }
+ cache = getDrawingCache(true);
+ } else {
+ switch (layerType) {
+ case LAYER_TYPE_SOFTWARE:
+ buildDrawingCache(true);
+ cache = getDrawingCache(true);
+ break;
+ case LAYER_TYPE_NONE:
+ // Delay getting the display list until animation-driven alpha values are
+ // set up and possibly passed on to the view
+ hasDisplayList = canHaveDisplayList();
+ break;
+ }
+ }
+ }
+
+ final boolean hasNoCache = cache == null || hasDisplayList;
+ final boolean offsetForScroll = cache == null && !hasDisplayList &&
+ layerType != LAYER_TYPE_HARDWARE;
+
+ final int restoreTo = canvas.save();
+ if (offsetForScroll) {
+ canvas.translate(mLeft - sx, mTop - sy);
+ } else {
+ canvas.translate(mLeft, mTop);
+ if (scalingRequired) {
+ // mAttachInfo cannot be null, otherwise scalingRequired == false
+ final float scale = 1.0f / mAttachInfo.mApplicationScale;
+ canvas.scale(scale, scale);
+ }
+ }
+
+ float alpha = getAlpha();
+ if (transformToApply != null || alpha < 1.0f || !hasIdentityMatrix()) {
+ if (transformToApply != null || !childHasIdentityMatrix) {
+ int transX = 0;
+ int transY = 0;
+
+ if (offsetForScroll) {
+ transX = -sx;
+ transY = -sy;
+ }
+
+ if (transformToApply != null) {
+ if (concatMatrix) {
+ // Undo the scroll translation, apply the transformation matrix,
+ // then redo the scroll translate to get the correct result.
+ canvas.translate(-transX, -transY);
+ canvas.concat(transformToApply.getMatrix());
+ canvas.translate(transX, transY);
+ parent.mGroupFlags |= parent.FLAG_CLEAR_TRANSFORMATION;
+ }
+
+ float transformAlpha = transformToApply.getAlpha();
+ if (transformAlpha < 1.0f) {
+ alpha *= transformToApply.getAlpha();
+ parent.mGroupFlags |= parent.FLAG_CLEAR_TRANSFORMATION;
+ }
+ }
+
+ if (!childHasIdentityMatrix) {
+ canvas.translate(-transX, -transY);
+ canvas.concat(getMatrix());
+ canvas.translate(transX, transY);
+ }
+ }
+
+ if (alpha < 1.0f) {
+ parent.mGroupFlags |= parent.FLAG_CLEAR_TRANSFORMATION;
+ if (hasNoCache) {
+ final int multipliedAlpha = (int) (255 * alpha);
+ if (!onSetAlpha(multipliedAlpha)) {
+ int layerFlags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
+ if ((flags & parent.FLAG_CLIP_CHILDREN) == parent.FLAG_CLIP_CHILDREN ||
+ layerType != LAYER_TYPE_NONE) {
+ layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG;
+ }
+ if (layerType == LAYER_TYPE_NONE) {
+ final int scrollX = hasDisplayList ? 0 : sx;
+ final int scrollY = hasDisplayList ? 0 : sy;
+ canvas.saveLayerAlpha(scrollX, scrollY, scrollX + mRight - mLeft,
+ scrollY + mBottom - mTop, multipliedAlpha, layerFlags);
+ }
+ } else {
+ // Alpha is handled by the child directly, clobber the layer's alpha
+ mPrivateFlags |= ALPHA_SET;
+ }
+ }
+ }
+ } else if ((mPrivateFlags & ALPHA_SET) == ALPHA_SET) {
+ onSetAlpha(255);
+ mPrivateFlags &= ~ALPHA_SET;
+ }
+
+ if ((flags & parent.FLAG_CLIP_CHILDREN) == parent.FLAG_CLIP_CHILDREN) {
+ if (offsetForScroll) {
+ canvas.clipRect(sx, sy, sx + (mRight - mLeft), sy + (mBottom - mTop));
+ } else {
+ if (!scalingRequired || cache == null) {
+ canvas.clipRect(0, 0, mRight - mLeft, mBottom - mTop);
+ } else {
+ canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight());
+ }
+ }
+ }
+
+ if (hasDisplayList) {
+ displayList = getDisplayList();
+ if (!displayList.isValid()) {
+ // Uncommon, but possible. If a view is removed from the hierarchy during the call
+ // to getDisplayList(), the display list will be marked invalid and we should not
+ // try to use it again.
+ displayList = null;
+ hasDisplayList = false;
+ }
+ }
+
+ if (hasNoCache) {
+ boolean layerRendered = false;
+ if (layerType == LAYER_TYPE_HARDWARE) {
+ final HardwareLayer layer = getHardwareLayer();
+ if (layer != null && layer.isValid()) {
+ mLayerPaint.setAlpha((int) (alpha * 255));
+ ((HardwareCanvas) canvas).drawHardwareLayer(layer, 0, 0, mLayerPaint);
+ layerRendered = true;
+ } else {
+ final int scrollX = hasDisplayList ? 0 : sx;
+ final int scrollY = hasDisplayList ? 0 : sy;
+ canvas.saveLayer(scrollX, scrollY,
+ scrollX + mRight - mLeft, scrollY + mBottom - mTop, mLayerPaint,
+ Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
+ }
+ }
+
+ if (!layerRendered) {
+ if (!hasDisplayList) {
+ // Fast path for layouts with no backgrounds
+ if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
+ if (ViewDebug.TRACE_HIERARCHY) {
+ ViewDebug.trace(parent, ViewDebug.HierarchyTraceType.DRAW);
+ }
+ mPrivateFlags &= ~DIRTY_MASK;
+ dispatchDraw(canvas);
+ } else {
+ draw(canvas);
+ }
+ } else {
+ mPrivateFlags &= ~DIRTY_MASK;
+ ((HardwareCanvas) canvas).drawDisplayList(displayList,
+ mRight - mLeft, mBottom - mTop, null);
+ }
+ }
+ } else if (cache != null) {
+ mPrivateFlags &= ~DIRTY_MASK;
+ Paint cachePaint;
+
+ if (layerType == LAYER_TYPE_NONE) {
+ cachePaint = parent.mCachePaint;
+ if (cachePaint == null) {
+ cachePaint = new Paint();
+ cachePaint.setDither(false);
+ parent.mCachePaint = cachePaint;
+ }
+ if (alpha < 1.0f) {
+ cachePaint.setAlpha((int) (alpha * 255));
+ parent.mGroupFlags |= parent.FLAG_ALPHA_LOWER_THAN_ONE;
+ } else if ((flags & parent.FLAG_ALPHA_LOWER_THAN_ONE) ==
+ parent.FLAG_ALPHA_LOWER_THAN_ONE) {
+ cachePaint.setAlpha(255);
+ parent.mGroupFlags &= ~parent.FLAG_ALPHA_LOWER_THAN_ONE;
+ }
+ } else {
+ cachePaint = mLayerPaint;
+ cachePaint.setAlpha((int) (alpha * 255));
+ }
+ canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint);
+ }
+
+ canvas.restoreToCount(restoreTo);
+
+ if (a != null && !more) {
+ if (!hardwareAccelerated && !a.getFillAfter()) {
+ onSetAlpha(255);
+ }
+ parent.finishAnimatingView(this, a);
+ }
+
+ if (more && hardwareAccelerated) {
+ // invalidation is the trigger to recreate display lists, so if we're using
+ // display lists to render, force an invalidate to allow the animation to
+ // continue drawing another frame
+ parent.invalidate(true);
+ if (a.hasAlpha() && (mPrivateFlags & ALPHA_SET) == ALPHA_SET) {
+ // alpha animations should cause the child to recreate its display list
+ invalidate(true);
+ }
+ }
+
+ mRecreateDisplayList = false;
+
+ return more;
+ }
+
+ /**
* Manually render this view (and all of its children) to the given Canvas.
* The view must have already done a full layout before this function is
* called. When implementing a view, implement
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index d3af61841295..a2e85a334575 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -103,18 +103,18 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
* A Transformation used when drawing children, to
* apply on the child being drawn.
*/
- private final Transformation mChildTransformation = new Transformation();
+ final Transformation mChildTransformation = new Transformation();
/**
* Used to track the current invalidation region.
*/
- private RectF mInvalidateRegion;
+ RectF mInvalidateRegion;
/**
* A Transformation used to calculate a correct
* invalidation area when the application is autoscaled.
*/
- private Transformation mInvalidationTransformation;
+ Transformation mInvalidationTransformation;
// View currently under an ongoing drag
private View mCurrentDragView;
@@ -170,7 +170,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
// When set, ViewGroup invalidates only the child's rectangle
// Set by default
- private static final int FLAG_CLIP_CHILDREN = 0x1;
+ static final int FLAG_CLIP_CHILDREN = 0x1;
// When set, ViewGroup excludes the padding area from the invalidate rectangle
// Set by default
@@ -178,7 +178,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
// When set, dispatchDraw() will invoke invalidate(); this is set by drawChild() when
// a child needs to be invalidated and FLAG_OPTIMIZE_INVALIDATE is set
- private static final int FLAG_INVALIDATE_REQUIRED = 0x4;
+ static final int FLAG_INVALIDATE_REQUIRED = 0x4;
// When set, dispatchDraw() will run the layout animation and unset the flag
private static final int FLAG_RUN_ANIMATION = 0x8;
@@ -186,7 +186,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
// When set, there is either no layout animation on the ViewGroup or the layout
// animation is over
// Set by default
- private static final int FLAG_ANIMATION_DONE = 0x10;
+ static final int FLAG_ANIMATION_DONE = 0x10;
// If set, this ViewGroup has padding; if unset there is no padding and we don't need
// to clip it, even if FLAG_CLIP_TO_PADDING is set
@@ -200,10 +200,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
// layout animation; this avoid clobbering the hierarchy
// Automatically set when the layout animation starts, depending on the animation's
// characteristics
- private static final int FLAG_OPTIMIZE_INVALIDATE = 0x80;
+ static final int FLAG_OPTIMIZE_INVALIDATE = 0x80;
// When set, the next call to drawChild() will clear mChildTransformation's matrix
- private static final int FLAG_CLEAR_TRANSFORMATION = 0x100;
+ static final int FLAG_CLEAR_TRANSFORMATION = 0x100;
// When set, this ViewGroup invokes mAnimationListener.onAnimationEnd() and removes
// the children's Bitmap caches if necessary
@@ -233,7 +233,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
// When the previous drawChild() invocation used an alpha value that was lower than
// 1.0 and set it in mCachePaint
- private static final int FLAG_ALPHA_LOWER_THAN_ONE = 0x1000;
+ static final int FLAG_ALPHA_LOWER_THAN_ONE = 0x1000;
/**
* When set, this ViewGroup's drawable states also include those
@@ -244,13 +244,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
/**
* When set, this ViewGroup tries to always draw its children using their drawing cache.
*/
- private static final int FLAG_ALWAYS_DRAWN_WITH_CACHE = 0x4000;
+ static final int FLAG_ALWAYS_DRAWN_WITH_CACHE = 0x4000;
/**
* When set, and if FLAG_ALWAYS_DRAWN_WITH_CACHE is not set, this ViewGroup will try to
* draw its children with their drawing cache.
*/
- private static final int FLAG_CHILDREN_DRAWN_WITH_CACHE = 0x8000;
+ static final int FLAG_CHILDREN_DRAWN_WITH_CACHE = 0x8000;
/**
* When set, this group will go through its list of children to notify them of
@@ -352,7 +352,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
private static final int ARRAY_CAPACITY_INCREMENT = 12;
// Used to draw cached views
- private Paint mCachePaint;
+ Paint mCachePaint;
// Used to animate add/remove changes in layout
private LayoutTransition mTransition;
@@ -368,7 +368,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
// Indicates whether this container will use its children layers to draw
@ViewDebug.ExportedProperty(category = "drawing")
- private boolean mDrawLayers = true;
+ boolean mDrawLayers = true;
public ViewGroup(Context context) {
super(context);
@@ -2620,336 +2620,11 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
*
* @param canvas The canvas on which to draw the child
* @param child Who to draw
- * @param drawingTime The time at which draw is occuring
+ * @param drawingTime The time at which draw is occurring
* @return True if an invalidate() was issued
*/
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
- boolean more = false;
-
- final int cl = child.mLeft;
- final int ct = child.mTop;
- final int cr = child.mRight;
- final int cb = child.mBottom;
-
- final boolean childHasIdentityMatrix = child.hasIdentityMatrix();
-
- final int flags = mGroupFlags;
-
- if ((flags & FLAG_CLEAR_TRANSFORMATION) == FLAG_CLEAR_TRANSFORMATION) {
- mChildTransformation.clear();
- mGroupFlags &= ~FLAG_CLEAR_TRANSFORMATION;
- }
-
- Transformation transformToApply = null;
- Transformation invalidationTransform;
- final Animation a = child.getAnimation();
- boolean concatMatrix = false;
-
- boolean scalingRequired = false;
- boolean caching;
- int layerType = mDrawLayers ? child.getLayerType() : LAYER_TYPE_NONE;
-
- final boolean hardwareAccelerated = canvas.isHardwareAccelerated();
- if ((flags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE ||
- (flags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE) {
- caching = true;
- if (mAttachInfo != null) scalingRequired = mAttachInfo.mScalingRequired;
- } else {
- caching = (layerType != LAYER_TYPE_NONE) || hardwareAccelerated;
- }
-
- if (a != null) {
- final boolean initialized = a.isInitialized();
- if (!initialized) {
- a.initialize(cr - cl, cb - ct, getWidth(), getHeight());
- a.initializeInvalidateRegion(0, 0, cr - cl, cb - ct);
- child.onAnimationStart();
- }
-
- more = a.getTransformation(drawingTime, mChildTransformation, 1f);
- if (scalingRequired && mAttachInfo.mApplicationScale != 1f) {
- if (mInvalidationTransformation == null) {
- mInvalidationTransformation = new Transformation();
- }
- invalidationTransform = mInvalidationTransformation;
- a.getTransformation(drawingTime, invalidationTransform, 1f);
- } else {
- invalidationTransform = mChildTransformation;
- }
- transformToApply = mChildTransformation;
-
- concatMatrix = a.willChangeTransformationMatrix();
-
- if (more) {
- if (!a.willChangeBounds()) {
- if ((flags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) ==
- FLAG_OPTIMIZE_INVALIDATE) {
- mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
- } else if ((flags & FLAG_INVALIDATE_REQUIRED) == 0) {
- // The child need to draw an animation, potentially offscreen, so
- // make sure we do not cancel invalidate requests
- mPrivateFlags |= DRAW_ANIMATION;
- invalidate(cl, ct, cr, cb);
- }
- } else {
- if (mInvalidateRegion == null) {
- mInvalidateRegion = new RectF();
- }
- final RectF region = mInvalidateRegion;
- a.getInvalidateRegion(0, 0, cr - cl, cb - ct, region, invalidationTransform);
-
- // The child need to draw an animation, potentially offscreen, so
- // make sure we do not cancel invalidate requests
- mPrivateFlags |= DRAW_ANIMATION;
-
- final int left = cl + (int) region.left;
- final int top = ct + (int) region.top;
- invalidate(left, top, left + (int) (region.width() + .5f),
- top + (int) (region.height() + .5f));
- }
- }
- } else if ((flags & FLAG_SUPPORT_STATIC_TRANSFORMATIONS) ==
- FLAG_SUPPORT_STATIC_TRANSFORMATIONS) {
- final boolean hasTransform = getChildStaticTransformation(child, mChildTransformation);
- if (hasTransform) {
- final int transformType = mChildTransformation.getTransformationType();
- transformToApply = transformType != Transformation.TYPE_IDENTITY ?
- mChildTransformation : null;
- concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0;
- }
- }
-
- concatMatrix |= !childHasIdentityMatrix;
-
- // Sets the flag as early as possible to allow draw() implementations
- // to call invalidate() successfully when doing animations
- child.mPrivateFlags |= DRAWN;
-
- if (!concatMatrix && canvas.quickReject(cl, ct, cr, cb, Canvas.EdgeType.BW) &&
- (child.mPrivateFlags & DRAW_ANIMATION) == 0) {
- return more;
- }
-
- if (hardwareAccelerated) {
- // Clear INVALIDATED flag to allow invalidation to occur during rendering, but
- // retain the flag's value temporarily in the mRecreateDisplayList flag
- child.mRecreateDisplayList = (child.mPrivateFlags & INVALIDATED) == INVALIDATED;
- child.mPrivateFlags &= ~INVALIDATED;
- }
-
- child.computeScroll();
-
- final int sx = child.mScrollX;
- final int sy = child.mScrollY;
-
- DisplayList displayList = null;
- Bitmap cache = null;
- boolean hasDisplayList = false;
- if (caching) {
- if (!hardwareAccelerated) {
- if (layerType != LAYER_TYPE_NONE) {
- layerType = LAYER_TYPE_SOFTWARE;
- child.buildDrawingCache(true);
- }
- cache = child.getDrawingCache(true);
- } else {
- switch (layerType) {
- case LAYER_TYPE_SOFTWARE:
- child.buildDrawingCache(true);
- cache = child.getDrawingCache(true);
- break;
- case LAYER_TYPE_NONE:
- // Delay getting the display list until animation-driven alpha values are
- // set up and possibly passed on to the view
- hasDisplayList = child.canHaveDisplayList();
- break;
- }
- }
- }
-
- final boolean hasNoCache = cache == null || hasDisplayList;
- final boolean offsetForScroll = cache == null && !hasDisplayList &&
- layerType != LAYER_TYPE_HARDWARE;
-
- final int restoreTo = canvas.save();
- if (offsetForScroll) {
- canvas.translate(cl - sx, ct - sy);
- } else {
- canvas.translate(cl, ct);
- if (scalingRequired) {
- // mAttachInfo cannot be null, otherwise scalingRequired == false
- final float scale = 1.0f / mAttachInfo.mApplicationScale;
- canvas.scale(scale, scale);
- }
- }
-
- float alpha = child.getAlpha();
- if (transformToApply != null || alpha < 1.0f || !child.hasIdentityMatrix()) {
- if (transformToApply != null || !childHasIdentityMatrix) {
- int transX = 0;
- int transY = 0;
-
- if (offsetForScroll) {
- transX = -sx;
- transY = -sy;
- }
-
- if (transformToApply != null) {
- if (concatMatrix) {
- // Undo the scroll translation, apply the transformation matrix,
- // then redo the scroll translate to get the correct result.
- canvas.translate(-transX, -transY);
- canvas.concat(transformToApply.getMatrix());
- canvas.translate(transX, transY);
- mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
- }
-
- float transformAlpha = transformToApply.getAlpha();
- if (transformAlpha < 1.0f) {
- alpha *= transformToApply.getAlpha();
- mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
- }
- }
-
- if (!childHasIdentityMatrix) {
- canvas.translate(-transX, -transY);
- canvas.concat(child.getMatrix());
- canvas.translate(transX, transY);
- }
- }
-
- if (alpha < 1.0f) {
- mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
- if (hasNoCache) {
- final int multipliedAlpha = (int) (255 * alpha);
- if (!child.onSetAlpha(multipliedAlpha)) {
- int layerFlags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
- if ((flags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN ||
- layerType != LAYER_TYPE_NONE) {
- layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG;
- }
- if (layerType == LAYER_TYPE_NONE) {
- final int scrollX = hasDisplayList ? 0 : sx;
- final int scrollY = hasDisplayList ? 0 : sy;
- canvas.saveLayerAlpha(scrollX, scrollY, scrollX + cr - cl,
- scrollY + cb - ct, multipliedAlpha, layerFlags);
- }
- } else {
- // Alpha is handled by the child directly, clobber the layer's alpha
- child.mPrivateFlags |= ALPHA_SET;
- }
- }
- }
- } else if ((child.mPrivateFlags & ALPHA_SET) == ALPHA_SET) {
- child.onSetAlpha(255);
- child.mPrivateFlags &= ~ALPHA_SET;
- }
-
- if ((flags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
- if (offsetForScroll) {
- canvas.clipRect(sx, sy, sx + (cr - cl), sy + (cb - ct));
- } else {
- if (!scalingRequired || cache == null) {
- canvas.clipRect(0, 0, cr - cl, cb - ct);
- } else {
- canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight());
- }
- }
- }
-
- if (hasDisplayList) {
- displayList = child.getDisplayList();
- if (!displayList.isValid()) {
- // Uncommon, but possible. If a view is removed from the hierarchy during the call
- // to getDisplayList(), the display list will be marked invalid and we should not
- // try to use it again.
- displayList = null;
- hasDisplayList = false;
- }
- }
-
- if (hasNoCache) {
- boolean layerRendered = false;
- if (layerType == LAYER_TYPE_HARDWARE) {
- final HardwareLayer layer = child.getHardwareLayer();
- if (layer != null && layer.isValid()) {
- child.mLayerPaint.setAlpha((int) (alpha * 255));
- ((HardwareCanvas) canvas).drawHardwareLayer(layer, 0, 0, child.mLayerPaint);
- layerRendered = true;
- } else {
- final int scrollX = hasDisplayList ? 0 : sx;
- final int scrollY = hasDisplayList ? 0 : sy;
- canvas.saveLayer(scrollX, scrollY,
- scrollX + cr - cl, scrollY + cb - ct, child.mLayerPaint,
- Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
- }
- }
-
- if (!layerRendered) {
- if (!hasDisplayList) {
- // Fast path for layouts with no backgrounds
- if ((child.mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
- if (ViewDebug.TRACE_HIERARCHY) {
- ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW);
- }
- child.mPrivateFlags &= ~DIRTY_MASK;
- child.dispatchDraw(canvas);
- } else {
- child.draw(canvas);
- }
- } else {
- child.mPrivateFlags &= ~DIRTY_MASK;
- ((HardwareCanvas) canvas).drawDisplayList(displayList, cr - cl, cb - ct, null);
- }
- }
- } else if (cache != null) {
- child.mPrivateFlags &= ~DIRTY_MASK;
- Paint cachePaint;
-
- if (layerType == LAYER_TYPE_NONE) {
- cachePaint = mCachePaint;
- if (cachePaint == null) {
- cachePaint = new Paint();
- cachePaint.setDither(false);
- mCachePaint = cachePaint;
- }
- if (alpha < 1.0f) {
- cachePaint.setAlpha((int) (alpha * 255));
- mGroupFlags |= FLAG_ALPHA_LOWER_THAN_ONE;
- } else if ((flags & FLAG_ALPHA_LOWER_THAN_ONE) == FLAG_ALPHA_LOWER_THAN_ONE) {
- cachePaint.setAlpha(255);
- mGroupFlags &= ~FLAG_ALPHA_LOWER_THAN_ONE;
- }
- } else {
- cachePaint = child.mLayerPaint;
- cachePaint.setAlpha((int) (alpha * 255));
- }
- canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint);
- }
-
- canvas.restoreToCount(restoreTo);
-
- if (a != null && !more) {
- if (!hardwareAccelerated && !a.getFillAfter()) {
- child.onSetAlpha(255);
- }
- finishAnimatingView(child, a);
- }
-
- if (more && hardwareAccelerated) {
- // invalidation is the trigger to recreate display lists, so if we're using
- // display lists to render, force an invalidate to allow the animation to
- // continue drawing another frame
- invalidate(true);
- if (a.hasAlpha() && (child.mPrivateFlags & ALPHA_SET) == ALPHA_SET) {
- // alpha animations should cause the child to recreate its display list
- child.invalidate(true);
- }
- }
-
- child.mRecreateDisplayList = false;
-
- return more;
+ return child.draw(canvas, this, drawingTime);
}
/**
@@ -4854,7 +4529,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
* @param view The view whose animation has finished
* @param animation The animation, cannot be null
*/
- private void finishAnimatingView(final View view, Animation animation) {
+ void finishAnimatingView(final View view, Animation animation) {
final ArrayList<View> disappearingChildren = mDisappearingChildren;
if (disappearingChildren != null) {
if (disappearingChildren.contains(view)) {
@@ -5203,6 +4878,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
return true;
}
+ /** @hide */
+ protected void onSetLayoutParams(View child, LayoutParams layoutParams) {
+ }
+
/**
* LayoutParams are used by views to tell their parents how they want to be
* laid out. See
@@ -5411,29 +5090,33 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
*/
public static class MarginLayoutParams extends ViewGroup.LayoutParams {
/**
- * The left margin in pixels of the child. Whenever this value is changed, a call to
- * {@link android.view.View#requestLayout()} needs to be done.
+ * The left margin in pixels of the child.
+ * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
+ * to this field.
*/
@ViewDebug.ExportedProperty(category = "layout")
public int leftMargin;
/**
- * The top margin in pixels of the child. Whenever this value is changed, a call to
- * {@link android.view.View#requestLayout()} needs to be done.
+ * The top margin in pixels of the child.
+ * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
+ * to this field.
*/
@ViewDebug.ExportedProperty(category = "layout")
public int topMargin;
/**
- * The right margin in pixels of the child. Whenever this value is changed, a call to
- * {@link android.view.View#requestLayout()} needs to be done.
+ * The right margin in pixels of the child.
+ * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
+ * to this field.
*/
@ViewDebug.ExportedProperty(category = "layout")
public int rightMargin;
/**
- * The bottom margin in pixels of the child. Whenever this value is changed, a call to
- * {@link android.view.View#requestLayout()} needs to be done.
+ * The bottom margin in pixels of the child.
+ * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
+ * to this field.
*/
@ViewDebug.ExportedProperty(category = "layout")
public int bottomMargin;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index cbf4b5a21d7e..1930a5edd968 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -851,6 +851,11 @@ public final class ViewRootImpl extends Handler implements ViewParent,
@Override
public void onDraw() {
+ if (mInputEventReceiver != null) {
+ mInputEventReceiver.consumeBatchedInputEvents();
+ }
+ doProcessInputEvents();
+
if (mTraversalScheduled) {
mTraversalScheduled = false;
doTraversal();
@@ -891,8 +896,6 @@ public final class ViewRootImpl extends Handler implements ViewParent,
}
private void doTraversal() {
- doProcessInputEvents();
-
if (mProfile) {
Debug.startMethodTracing("ViewAncestor");
}
@@ -2631,7 +2634,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
break;
case DISPATCH_KEY: {
KeyEvent event = (KeyEvent)msg.obj;
- enqueueInputEvent(event, null, 0);
+ enqueueInputEvent(event, null, 0, true);
} break;
case DISPATCH_KEY_FROM_IME: {
if (LOCAL_LOGV) Log.v(
@@ -2644,7 +2647,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
//noinspection UnusedAssignment
event = KeyEvent.changeFlags(event, event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
}
- enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME);
+ enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
} break;
case FINISH_INPUT_CONNECTION: {
InputMethodManager imm = InputMethodManager.peekInstance();
@@ -2947,7 +2950,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
case MotionEvent.ACTION_DOWN:
x.reset(2);
y.reset(2);
- dispatchKey(new KeyEvent(curTime, curTime,
+ enqueueInputEvent(new KeyEvent(curTime, curTime,
KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
InputDevice.SOURCE_KEYBOARD));
@@ -2955,7 +2958,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
case MotionEvent.ACTION_UP:
x.reset(2);
y.reset(2);
- dispatchKey(new KeyEvent(curTime, curTime,
+ enqueueInputEvent(new KeyEvent(curTime, curTime,
KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, metaState,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
InputDevice.SOURCE_KEYBOARD));
@@ -3009,7 +3012,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
+ keycode);
movement--;
int repeatCount = accelMovement - movement;
- dispatchKey(new KeyEvent(curTime, curTime,
+ enqueueInputEvent(new KeyEvent(curTime, curTime,
KeyEvent.ACTION_MULTIPLE, keycode, repeatCount, metaState,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
InputDevice.SOURCE_KEYBOARD));
@@ -3019,11 +3022,11 @@ public final class ViewRootImpl extends Handler implements ViewParent,
+ keycode);
movement--;
curTime = SystemClock.uptimeMillis();
- dispatchKey(new KeyEvent(curTime, curTime,
+ enqueueInputEvent(new KeyEvent(curTime, curTime,
KeyEvent.ACTION_DOWN, keycode, 0, metaState,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
InputDevice.SOURCE_KEYBOARD));
- dispatchKey(new KeyEvent(curTime, curTime,
+ enqueueInputEvent(new KeyEvent(curTime, curTime,
KeyEvent.ACTION_UP, keycode, 0, metaState,
KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FALLBACK,
InputDevice.SOURCE_KEYBOARD));
@@ -3090,7 +3093,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
if (xDirection != mLastJoystickXDirection) {
if (mLastJoystickXKeyCode != 0) {
- dispatchKey(new KeyEvent(time, time,
+ enqueueInputEvent(new KeyEvent(time, time,
KeyEvent.ACTION_UP, mLastJoystickXKeyCode, 0, metaState,
deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
mLastJoystickXKeyCode = 0;
@@ -3101,7 +3104,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
if (xDirection != 0 && synthesizeNewKeys) {
mLastJoystickXKeyCode = xDirection > 0
? KeyEvent.KEYCODE_DPAD_RIGHT : KeyEvent.KEYCODE_DPAD_LEFT;
- dispatchKey(new KeyEvent(time, time,
+ enqueueInputEvent(new KeyEvent(time, time,
KeyEvent.ACTION_DOWN, mLastJoystickXKeyCode, 0, metaState,
deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
}
@@ -3109,7 +3112,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
if (yDirection != mLastJoystickYDirection) {
if (mLastJoystickYKeyCode != 0) {
- dispatchKey(new KeyEvent(time, time,
+ enqueueInputEvent(new KeyEvent(time, time,
KeyEvent.ACTION_UP, mLastJoystickYKeyCode, 0, metaState,
deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
mLastJoystickYKeyCode = 0;
@@ -3120,7 +3123,7 @@ public final class ViewRootImpl extends Handler implements ViewParent,
if (yDirection != 0 && synthesizeNewKeys) {
mLastJoystickYKeyCode = yDirection > 0
? KeyEvent.KEYCODE_DPAD_DOWN : KeyEvent.KEYCODE_DPAD_UP;
- dispatchKey(new KeyEvent(time, time,
+ enqueueInputEvent(new KeyEvent(time, time,
KeyEvent.ACTION_DOWN, mLastJoystickYKeyCode, 0, metaState,
deviceId, 0, KeyEvent.FLAG_FALLBACK, source));
}
@@ -3805,8 +3808,12 @@ public final class ViewRootImpl extends Handler implements ViewParent,
}
}
+ void enqueueInputEvent(InputEvent event) {
+ enqueueInputEvent(event, null, 0, false);
+ }
+
void enqueueInputEvent(InputEvent event,
- InputEventReceiver receiver, int flags) {
+ InputEventReceiver receiver, int flags, boolean processImmediately) {
QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
if (ViewDebug.DEBUG_LATENCY) {
@@ -3830,7 +3837,11 @@ public final class ViewRootImpl extends Handler implements ViewParent,
last.mNext = q;
}
- scheduleProcessInputEvents();
+ if (processImmediately) {
+ doProcessInputEvents();
+ } else {
+ scheduleProcessInputEvents();
+ }
}
private void scheduleProcessInputEvents() {
@@ -3919,13 +3930,19 @@ public final class ViewRootImpl extends Handler implements ViewParent,
@Override
public void onInputEvent(InputEvent event) {
- enqueueInputEvent(event, this, 0);
+ enqueueInputEvent(event, this, 0, true);
+ }
+
+ @Override
+ public void onBatchedInputEventPending() {
+ mChoreographer.scheduleDraw();
}
}
WindowInputEventReceiver mInputEventReceiver;
public void dispatchKey(KeyEvent event) {
- enqueueInputEvent(event, null, 0);
+ Message msg = obtainMessage(DISPATCH_KEY, event);
+ sendMessage(msg);
}
public void dispatchAppVisibility(boolean visible) {
diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java
index 0d60d3f03f0a..9152cc344949 100644
--- a/core/java/android/view/VolumePanel.java
+++ b/core/java/android/view/VolumePanel.java
@@ -91,9 +91,10 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie
private static final int MSG_VIBRATE = 4;
private static final int MSG_TIMEOUT = 5;
private static final int MSG_RINGER_MODE_CHANGED = 6;
+ private static final int MSG_MUTE_CHANGED = 7;
// Pseudo stream type for master volume
- private static final int STREAM_MASTER = -1;
+ private static final int STREAM_MASTER = -100;
protected Context mContext;
private AudioManager mAudioManager;
@@ -295,45 +296,39 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie
private boolean isMuted(int streamType) {
if (streamType == STREAM_MASTER) {
- // master volume mute not yet supported
- return false;
+ return mAudioService.isMasterMute();
} else {
return mAudioService.isStreamMute(streamType);
}
}
private int getStreamMaxVolume(int streamType) {
- // master volume is 0.0f - 1.0f, but we will use 0 - 100 internally
if (streamType == STREAM_MASTER) {
- return 100;
+ return mAudioService.getMasterMaxVolume();
} else {
return mAudioService.getStreamMaxVolume(streamType);
}
}
private int getStreamVolume(int streamType) {
- // master volume is 0.0f - 1.0f, but we will use 0 - 100 internally
if (streamType == STREAM_MASTER) {
- return Math.round(mAudioService.getMasterVolume() * 100);
+ return mAudioService.getMasterVolume();
} else {
return mAudioService.getStreamVolume(streamType);
}
}
private void setStreamVolume(int streamType, int index, int flags) {
- // master volume is 0.0f - 1.0f, but we will use 0 - 100 internally
if (streamType == STREAM_MASTER) {
- mAudioService.setMasterVolume((float)index / 100.0f);
+ mAudioService.setMasterVolume(index, flags);
} else {
mAudioService.setStreamVolume(streamType, index, flags);
}
}
private int getLastAudibleStreamVolume(int streamType) {
- // master volume is 0.0f - 1.0f, but we will use 0 - 100 internally
if (streamType == STREAM_MASTER) {
- // master volume mute not yet supported
- return getStreamVolume(STREAM_MASTER);
+ return mAudioService.getLastAudibleMasterVolume();
} else {
return mAudioService.getLastAudibleStreamVolume(streamType);
}
@@ -456,6 +451,19 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie
postVolumeChanged(STREAM_MASTER, flags);
}
+ public void postMuteChanged(int streamType, int flags) {
+ if (hasMessages(MSG_VOLUME_CHANGED)) return;
+ if (mStreamControls == null) {
+ createSliders();
+ }
+ removeMessages(MSG_FREE_RESOURCES);
+ obtainMessage(MSG_MUTE_CHANGED, streamType, flags).sendToTarget();
+ }
+
+ public void postMasterMuteChanged(int flags) {
+ postMuteChanged(STREAM_MASTER, flags);
+ }
+
/**
* Override this if you have other work to do when the volume changes (for
* example, vibrating, playing a sound, etc.). Make sure to call through to
@@ -489,6 +497,18 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie
resetTimeout();
}
+ protected void onMuteChanged(int streamType, int flags) {
+
+ if (LOGD) Log.d(TAG, "onMuteChanged(streamType: " + streamType + ", flags: " + flags + ")");
+
+ StreamControl sc = mStreamControls.get(streamType);
+ if (sc != null) {
+ sc.icon.setImageResource(isMuted(sc.streamType) ? sc.iconMuteRes : sc.iconRes);
+ }
+
+ onVolumeChanged(streamType, flags);
+ }
+
protected void onShowVolumeChanged(int streamType, int flags) {
int index = isMuted(streamType) ?
getLastAudibleStreamVolume(streamType)
@@ -687,6 +707,11 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie
break;
}
+ case MSG_MUTE_CHANGED: {
+ onMuteChanged(msg.arg1, msg.arg2);
+ break;
+ }
+
case MSG_FREE_RESOURCES: {
onFreeResources();
break;
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 6bdc4e865660..6dbdedbb7cb4 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -480,9 +480,19 @@ public class WindowManagerImpl implements WindowManager {
try {
synchronized (this) {
if (mViews != null) {
- pw.println("View hierarchy:");
-
final int count = mViews.length;
+
+ pw.println("Profile data in ms:");
+
+ for (int i = 0; i < count; i++) {
+ ViewRootImpl root = mRoots[i];
+ HardwareRenderer renderer = root.getView().mAttachInfo.mHardwareRenderer;
+ if (renderer != null) {
+ renderer.dumpGfxInfo(pw);
+ }
+ }
+
+ pw.println("\nView hierarchy:");
int viewsCount = 0;
int displayListsSize = 0;
diff --git a/core/java/android/webkit/ZoomManager.java b/core/java/android/webkit/ZoomManager.java
index ae2d6173cb84..369e8838e4e2 100644
--- a/core/java/android/webkit/ZoomManager.java
+++ b/core/java/android/webkit/ZoomManager.java
@@ -258,6 +258,7 @@ class ZoomManager {
// Remember the current zoom density before it gets changed.
final float originalDefault = mDefaultScale;
// set the new default density
+ mDisplayDensity = density;
setDefaultZoomScale(density);
float scaleChange = (originalDefault > 0.0) ? density / originalDefault: 1.0f;
// adjust the scale if it falls outside the new zoom bounds
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 984ec79bee3e..ea40dc24f1b7 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -212,6 +212,7 @@ public class GridLayout extends ViewGroup {
static final int PRF = 1;
static final int MAX_SIZE = 100000;
static final int DEFAULT_CONTAINER_MARGIN = 0;
+ static final int UNINITIALIZED_HASH = 0;
// Defaults
@@ -240,6 +241,7 @@ public class GridLayout extends ViewGroup {
boolean useDefaultMargins = DEFAULT_USE_DEFAULT_MARGINS;
int alignmentMode = DEFAULT_ALIGNMENT_MODE;
int defaultGap;
+ int lastLayoutParamsHashCode = UNINITIALIZED_HASH;
// Constructors
@@ -566,6 +568,10 @@ public class GridLayout extends ViewGroup {
return FILL;
case AXIS_SPECIFIED:
return CENTER;
+ case (AXIS_SPECIFIED | AXIS_PULL_BEFORE | RELATIVE_LAYOUT_DIRECTION):
+ return START;
+ case (AXIS_SPECIFIED | AXIS_PULL_AFTER | RELATIVE_LAYOUT_DIRECTION):
+ return END;
default:
return UNDEFINED_ALIGNMENT;
}
@@ -590,7 +596,8 @@ public class GridLayout extends ViewGroup {
Spec spec = horizontal ? p.columnSpec : p.rowSpec;
Axis axis = horizontal ? horizontalAxis : verticalAxis;
Interval span = spec.span;
- boolean isAtEdge = leading ? (span.min == 0) : (span.max == axis.getCount());
+ boolean leading1 = (horizontal && isLayoutRtl()) ? !leading : leading;
+ boolean isAtEdge = leading1 ? (span.min == 0) : (span.max == axis.getCount());
return getDefaultMargin(c, isAtEdge, horizontal, leading);
}
@@ -663,7 +670,7 @@ public class GridLayout extends ViewGroup {
int[] maxSizes = new int[count];
for (int i = 0, N = getChildCount(); i < N; i++) {
- LayoutParams lp = getLayoutParams1(getChildAt(i));
+ LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
final Spec majorSpec = horizontal ? lp.rowSpec : lp.columnSpec;
final Interval majorRange = majorSpec.span;
@@ -708,6 +715,7 @@ public class GridLayout extends ViewGroup {
minor = minor + minorSpan;
}
+ lastLayoutParamsHashCode = computeLayoutParamsHashCode();
invalidateStructure();
}
@@ -728,8 +736,11 @@ public class GridLayout extends ViewGroup {
}
}
- private LayoutParams getLayoutParams1(View c) {
- return (LayoutParams) c.getLayoutParams();
+ /** @hide */
+ @Override
+ protected void onSetLayoutParams(View child, ViewGroup.LayoutParams layoutParams) {
+ super.onSetLayoutParams(child, layoutParams);
+ invalidateStructure();
}
final LayoutParams getLayoutParams(View c) {
@@ -737,7 +748,7 @@ public class GridLayout extends ViewGroup {
validateLayoutParams();
layoutParamsValid = true;
}
- return getLayoutParams1(c);
+ return (LayoutParams) c.getLayoutParams();
}
@Override
@@ -760,10 +771,15 @@ public class GridLayout extends ViewGroup {
private void drawLine(Canvas graphics, int x1, int y1, int x2, int y2, Paint paint) {
int dx = getPaddingLeft();
int dy = getPaddingTop();
- graphics.drawLine(dx + x1, dy + y1, dx + x2, dy + y2, paint);
+ if (isLayoutRtl()) {
+ int width = getWidth();
+ graphics.drawLine(width - dx - x1, dy + y1, width - dx - x2, dy + y2, paint);
+ } else {
+ graphics.drawLine(dx + x1, dy + y1, dx + x2, dy + y2, paint);
+ }
}
- private static void drawRect(Canvas canvas, int x1, int y1, int x2, int y2, Paint paint) {
+ private void drawRect(Canvas canvas, int x1, int y1, int x2, int y2, Paint paint) {
canvas.drawRect(x1, y1, x2 - 1, y2 - 1, paint);
}
@@ -849,12 +865,29 @@ public class GridLayout extends ViewGroup {
}
}
- // Measurement
+ private int computeLayoutParamsHashCode() {
+ int result = 1;
+ for (int i = 0, N = getChildCount(); i < N; i++) {
+ View c = getChildAt(i);
+ if (c.getVisibility() == View.GONE) continue;
+ LayoutParams lp = (LayoutParams) c.getLayoutParams();
+ result = 31 * result + lp.hashCode();
+ }
+ return result;
+ }
- final boolean isGone(View c) {
- return c.getVisibility() == View.GONE;
+ private void checkForLayoutParamsModification() {
+ int layoutParamsHashCode = computeLayoutParamsHashCode();
+ if (lastLayoutParamsHashCode != UNINITIALIZED_HASH &&
+ lastLayoutParamsHashCode != layoutParamsHashCode) {
+ invalidateStructure();
+ Log.w(TAG, "The fields of some layout parameters were modified in between layout " +
+ "operations. Check the javadoc for GridLayout.LayoutParams#rowSpec.");
+ }
}
+ // Measurement
+
private void measureChildWithMargins2(View child, int parentWidthSpec, int parentHeightSpec,
int childWidth, int childHeight) {
int childWidthSpec = getChildMeasureSpec(parentWidthSpec,
@@ -867,7 +900,7 @@ public class GridLayout extends ViewGroup {
private void measureChildrenWithMargins(int widthSpec, int heightSpec, boolean firstPass) {
for (int i = 0, N = getChildCount(); i < N; i++) {
View c = getChildAt(i);
- if (isGone(c)) continue;
+ if (c.getVisibility() == View.GONE) continue;
LayoutParams lp = getLayoutParams(c);
if (firstPass) {
measureChildWithMargins2(c, widthSpec, heightSpec, lp.width, lp.height);
@@ -892,6 +925,8 @@ public class GridLayout extends ViewGroup {
@Override
protected void onMeasure(int widthSpec, int heightSpec) {
+ checkForLayoutParamsModification();
+
/** If we have been called by {@link View#measure(int, int)}, one of width or height
* is likely to have changed. We must invalidate if so. */
invalidateValues();
@@ -931,7 +966,7 @@ public class GridLayout extends ViewGroup {
}
final int getMeasurementIncludingMargin(View c, boolean horizontal) {
- if (isGone(c)) {
+ if (c.getVisibility() == View.GONE) {
return 0;
}
return getMeasurement(c, horizontal) + getTotalMargin(c, horizontal);
@@ -945,7 +980,7 @@ public class GridLayout extends ViewGroup {
final Alignment getAlignment(Alignment alignment, boolean horizontal) {
return (alignment != UNDEFINED_ALIGNMENT) ? alignment :
- (horizontal ? LEFT : BASELINE);
+ (horizontal ? START : BASELINE);
}
// Layout container
@@ -964,6 +999,8 @@ public class GridLayout extends ViewGroup {
*/
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ checkForLayoutParamsModification();
+
int targetWidth = right - left;
int targetHeight = bottom - top;
@@ -980,7 +1017,7 @@ public class GridLayout extends ViewGroup {
for (int i = 0, N = getChildCount(); i < N; i++) {
View c = getChildAt(i);
- if (isGone(c)) continue;
+ if (c.getVisibility() == View.GONE) continue;
LayoutParams lp = getLayoutParams(c);
Spec columnSpec = lp.columnSpec;
Spec rowSpec = lp.rowSpec;
@@ -1003,41 +1040,41 @@ public class GridLayout extends ViewGroup {
Alignment hAlign = getAlignment(columnSpec.alignment, true);
Alignment vAlign = getAlignment(rowSpec.alignment, false);
- int dx, dy;
-
Bounds colBounds = horizontalAxis.getGroupBounds().getValue(i);
Bounds rowBounds = verticalAxis.getGroupBounds().getValue(i);
// Gravity offsets: the location of the alignment group relative to its cell group.
//noinspection NullableProblems
- int c2ax = protect(hAlign.getAlignmentValue(null, cellWidth - colBounds.size(true)));
+ int gravityOffsetX = protect(hAlign.getAlignmentValue(null,
+ cellWidth - colBounds.size(true)));
//noinspection NullableProblems
- int c2ay = protect(vAlign.getAlignmentValue(null, cellHeight - rowBounds.size(true)));
+ int gravityOffsetY = protect(vAlign.getAlignmentValue(null,
+ cellHeight - rowBounds.size(true)));
- int leftMargin = getMargin(c, true, true);
+ boolean rtl = isLayoutRtl();
+ int startMargin = getMargin(c, true, !rtl);
int topMargin = getMargin(c, false, true);
- int rightMargin = getMargin(c, true, false);
+ int endMargin = getMargin(c, true, rtl);
int bottomMargin = getMargin(c, false, false);
// Same calculation as getMeasurementIncludingMargin()
- int mWidth = leftMargin + pWidth + rightMargin;
+ int mWidth = startMargin + pWidth + endMargin;
int mHeight = topMargin + pHeight + bottomMargin;
// Alignment offsets: the location of the view relative to its alignment group.
- int a2vx = colBounds.getOffset(c, hAlign, mWidth);
- int a2vy = rowBounds.getOffset(c, vAlign, mHeight);
+ int alignmentOffsetX = colBounds.getOffset(c, hAlign, mWidth);
+ int alignmentOffsetY = rowBounds.getOffset(c, vAlign, mHeight);
- dx = c2ax + a2vx + leftMargin;
- dy = c2ay + a2vy + topMargin;
+ int dx = gravityOffsetX + alignmentOffsetX + startMargin;
+ int dy = gravityOffsetY + alignmentOffsetY + topMargin;
- cellWidth -= leftMargin + rightMargin;
+ cellWidth -= startMargin + endMargin;
cellHeight -= topMargin + bottomMargin;
- int type = PRF;
- int width = hAlign.getSizeInCell(c, pWidth, cellWidth, type);
- int height = vAlign.getSizeInCell(c, pHeight, cellHeight, type);
+ int width = hAlign.getSizeInCell(c, pWidth, cellWidth, PRF);
+ int height = vAlign.getSizeInCell(c, pHeight, cellHeight, PRF);
- int cx = paddingLeft + x1 + dx;
+ int cx = rtl ? targetWidth - paddingRight - x1 - dx - width : paddingLeft + x1 + dx;
int cy = paddingTop + y1 + dy;
if (width != c.getMeasuredWidth() || height != c.getMeasuredHeight()) {
c.measure(makeMeasureSpec(width, EXACTLY), makeMeasureSpec(height, EXACTLY));
@@ -1517,7 +1554,7 @@ public class GridLayout extends ViewGroup {
int[] margins = leading ? leadingMargins : trailingMargins;
for (int i = 0, N = getChildCount(); i < N; i++) {
View c = getChildAt(i);
- if (isGone(c)) continue;
+ if (c.getVisibility() == View.GONE) continue;
LayoutParams lp = getLayoutParams(c);
Spec spec = horizontal ? lp.columnSpec : lp.rowSpec;
Interval span = spec.span;
@@ -1757,12 +1794,28 @@ public class GridLayout extends ViewGroup {
/**
* The spec that defines the vertical characteristics of the cell group
* described by these layout parameters.
+ * If an assignment is made to this field after a measurement or layout operation
+ * has already taken place, a call to
+ * {@link ViewGroup#setLayoutParams(ViewGroup.LayoutParams)}
+ * must be made to notify GridLayout of the change. GridLayout is normally able
+ * to detect when code fails to observe this rule, issue a warning and take steps to
+ * compensate for the omission. This facility is implemented on a best effort basis
+ * and should not be relied upon in production code - so it is best to include the above
+ * calls to remove the warnings as soon as it is practical.
*/
public Spec rowSpec = Spec.UNDEFINED;
/**
* The spec that defines the horizontal characteristics of the cell group
* described by these layout parameters.
+ * If an assignment is made to this field after a measurement or layout operation
+ * has already taken place, a call to
+ * {@link ViewGroup#setLayoutParams(ViewGroup.LayoutParams)}
+ * must be made to notify GridLayout of the change. GridLayout is normally able
+ * to detect when code fails to observe this rule, issue a warning and take steps to
+ * compensate for the omission. This facility is implemented on a best effort basis
+ * and should not be relied upon in production code - so it is best to include the above
+ * calls to remove the warnings as soon as it is practical.
*/
public Spec columnSpec = Spec.UNDEFINED;
@@ -1907,6 +1960,26 @@ public class GridLayout extends ViewGroup {
final void setColumnSpecSpan(Interval span) {
columnSpec = columnSpec.copyWriteSpan(span);
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ LayoutParams that = (LayoutParams) o;
+
+ if (!columnSpec.equals(that.columnSpec)) return false;
+ if (!rowSpec.equals(that.rowSpec)) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = rowSpec.hashCode();
+ result = 31 * result + columnSpec.hashCode();
+ return result;
+ }
}
/*
@@ -2049,7 +2122,7 @@ public class GridLayout extends ViewGroup {
/*
For each group (with a given alignment) we need to store the amount of space required
before the alignment point and the amount of space required after it. One side of this
- calculation is always 0 for LEADING and TRAILING alignments but we don't make use of this.
+ calculation is always 0 for START and END alignments but we don't make use of this.
For CENTER and BASELINE alignments both sides are needed and in the BASELINE case no
simple optimisations are possible.
@@ -2405,18 +2478,29 @@ public class GridLayout extends ViewGroup {
}
static final Alignment UNDEFINED_ALIGNMENT = new Alignment() {
+ @Override
public int getAlignmentValue(View view, int viewSize) {
return UNDEFINED;
}
};
+ /**
+ * Indicates that a view should be aligned with the <em>start</em>
+ * edges of the other views in its cell group.
+ */
private static final Alignment LEADING = new Alignment() {
+ @Override
public int getAlignmentValue(View view, int viewSize) {
return 0;
}
};
+ /**
+ * Indicates that a view should be aligned with the <em>end</em>
+ * edges of the other views in its cell group.
+ */
private static final Alignment TRAILING = new Alignment() {
+ @Override
public int getAlignmentValue(View view, int viewSize) {
return viewSize;
}
@@ -2435,16 +2519,41 @@ public class GridLayout extends ViewGroup {
public static final Alignment BOTTOM = TRAILING;
/**
- * Indicates that a view should be aligned with the <em>right</em>
+ * Indicates that a view should be aligned with the <em>start</em>
+ * edges of the other views in its cell group.
+ */
+ public static final Alignment START = LEADING;
+
+ /**
+ * Indicates that a view should be aligned with the <em>end</em>
* edges of the other views in its cell group.
*/
- public static final Alignment RIGHT = TRAILING;
+ public static final Alignment END = TRAILING;
+
+ private static Alignment getAbsoluteAlignment(final Alignment a1, final Alignment a2) {
+ return new Alignment() {
+ @Override
+ public int getAlignmentValue(View view, int viewSize) {
+ if (view == null) {
+ return UNDEFINED;
+ }
+ Alignment alignment = view.isLayoutRtl() ? a2 : a1;
+ return alignment.getAlignmentValue(view, viewSize);
+ }
+ };
+ }
/**
* Indicates that a view should be aligned with the <em>left</em>
* edges of the other views in its cell group.
*/
- public static final Alignment LEFT = LEADING;
+ public static final Alignment LEFT = getAbsoluteAlignment(START, END);
+
+ /**
+ * Indicates that a view should be aligned with the <em>right</em>
+ * edges of the other views in its cell group.
+ */
+ public static final Alignment RIGHT = getAbsoluteAlignment(END, START);
/**
* Indicates that a view should be <em>centered</em> with the other views in its cell group.
@@ -2452,6 +2561,7 @@ public class GridLayout extends ViewGroup {
* LayoutParams#columnSpec columnSpecs}.
*/
public static final Alignment CENTER = new Alignment() {
+ @Override
public int getAlignmentValue(View view, int viewSize) {
return viewSize >> 1;
}
@@ -2465,6 +2575,7 @@ public class GridLayout extends ViewGroup {
* @see View#getBaseline()
*/
public static final Alignment BASELINE = new Alignment() {
+ @Override
public int getAlignmentValue(View view, int viewSize) {
if (view == null) {
return UNDEFINED;
@@ -2515,6 +2626,7 @@ public class GridLayout extends ViewGroup {
* {@link LayoutParams#columnSpec columnSpecs}.
*/
public static final Alignment FILL = new Alignment() {
+ @Override
public int getAlignmentValue(View view, int viewSize) {
return UNDEFINED;
}
@@ -2530,6 +2642,5 @@ public class GridLayout extends ViewGroup {
}
private static final int INFLEXIBLE = 0;
-
private static final int CAN_STRETCH = 2;
}
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index ac4fe5b1c6be..536681b0452f 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -130,21 +130,21 @@ AInputQueue::~AInputQueue() {
void AInputQueue::attachLooper(ALooper* looper, int ident,
ALooper_callbackFunc callback, void* data) {
mLooper = static_cast<android::Looper*>(looper);
- mLooper->addFd(mConsumer.getChannel()->getReceivePipeFd(),
+ mLooper->addFd(mConsumer.getChannel()->getFd(),
ident, ALOOPER_EVENT_INPUT, callback, data);
mLooper->addFd(mDispatchKeyRead,
ident, ALOOPER_EVENT_INPUT, callback, data);
}
void AInputQueue::detachLooper() {
- mLooper->removeFd(mConsumer.getChannel()->getReceivePipeFd());
+ mLooper->removeFd(mConsumer.getChannel()->getFd());
mLooper->removeFd(mDispatchKeyRead);
}
int32_t AInputQueue::hasEvents() {
struct pollfd pfd[2];
- pfd[0].fd = mConsumer.getChannel()->getReceivePipeFd();
+ pfd[0].fd = mConsumer.getChannel()->getFd();
pfd[0].events = POLLIN;
pfd[0].revents = 0;
pfd[1].fd = mDispatchKeyRead;
@@ -172,7 +172,7 @@ int32_t AInputQueue::getEvent(AInputEvent** outEvent) {
in_flight_event inflight;
inflight.event = kevent;
inflight.seq = -1;
- inflight.doFinish = false;
+ inflight.finishSeq = 0;
mInFlightEvents.push(inflight);
}
if (mFinishPreDispatches.size() > 0) {
@@ -200,27 +200,22 @@ int32_t AInputQueue::getEvent(AInputEvent** outEvent) {
return 0;
}
}
-
- int32_t res = mConsumer.receiveDispatchSignal();
- if (res != android::OK) {
- ALOGE("channel '%s' ~ Failed to receive dispatch signal. status=%d",
- mConsumer.getChannel()->getName().string(), res);
- return -1;
- }
+ uint32_t consumerSeq;
InputEvent* myEvent = NULL;
- res = mConsumer.consume(this, &myEvent);
+ status_t res = mConsumer.consume(this, true /*consumeBatches*/, &consumerSeq, &myEvent);
if (res != android::OK) {
- ALOGW("channel '%s' ~ Failed to consume input event. status=%d",
- mConsumer.getChannel()->getName().string(), res);
- mConsumer.sendFinishedSignal(false);
+ if (res != android::WOULD_BLOCK) {
+ ALOGW("channel '%s' ~ Failed to consume input event. status=%d",
+ mConsumer.getChannel()->getName().string(), res);
+ }
return -1;
}
in_flight_event inflight;
inflight.event = myEvent;
inflight.seq = -1;
- inflight.doFinish = true;
+ inflight.finishSeq = consumerSeq;
mInFlightEvents.push(inflight);
*outEvent = myEvent;
@@ -262,8 +257,8 @@ void AInputQueue::finishEvent(AInputEvent* event, bool handled, bool didDefaultH
for (size_t i=0; i<N; i++) {
const in_flight_event& inflight(mInFlightEvents[i]);
if (inflight.event == event) {
- if (inflight.doFinish) {
- int32_t res = mConsumer.sendFinishedSignal(handled);
+ if (inflight.finishSeq) {
+ status_t res = mConsumer.sendFinishedSignal(inflight.finishSeq, handled);
if (res != android::OK) {
ALOGW("Failed to send finished signal on channel '%s'. status=%d",
mConsumer.getChannel()->getName().string(), res);
@@ -481,11 +476,6 @@ struct NativeCode : public ANativeActivity {
android_view_InputChannel_getInputChannel(env, _channel);
if (ic != NULL) {
nativeInputQueue = new AInputQueue(ic, mainWorkWrite);
- if (nativeInputQueue->getConsumer().initialize() != android::OK) {
- delete nativeInputQueue;
- nativeInputQueue = NULL;
- return UNKNOWN_ERROR;
- }
} else {
return UNKNOWN_ERROR;
}
diff --git a/core/jni/android_backup_BackupDataOutput.cpp b/core/jni/android_backup_BackupDataOutput.cpp
index f4b5dcaba8a2..abe0104cfcf5 100644
--- a/core/jni/android_backup_BackupDataOutput.cpp
+++ b/core/jni/android_backup_BackupDataOutput.cpp
@@ -52,7 +52,6 @@ writeEntityHeader_native(JNIEnv* env, jobject clazz, int w, jstring key, int dat
if (keyUTF == NULL) {
return -1;
}
-
err = writer->WriteEntityHeader(String8(keyUTF), dataSize);
env->ReleaseStringUTFChars(key, keyUTF);
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 547607ec2947..68a8de8f7c70 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -220,7 +220,7 @@ android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
ALOGE("Error creating AudioRecord: Error retrieving session id pointer");
goto native_init_failure;
}
- // read the audio session ID back from AudioTrack in case a new session was created during set()
+ // read the audio session ID back from AudioRecord in case a new session was created during set()
nSession[0] = lpRecorder->getSessionId();
env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
nSession = NULL;
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 31c5ed482a3d..ee5eb7e87506 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -1,4 +1,4 @@
-/* //device/libs/android_runtime/android_media_AudioSystem.cpp
+/*
**
** Copyright 2006, The Android Open Source Project
**
diff --git a/core/jni/android_media_ToneGenerator.cpp b/core/jni/android_media_ToneGenerator.cpp
index 0a337fae781e..544b4c09661f 100644
--- a/core/jni/android_media_ToneGenerator.cpp
+++ b/core/jni/android_media_ToneGenerator.cpp
@@ -1,4 +1,4 @@
-/* //device/libs/android_runtime/android_media_AudioSystem.cpp
+/*
**
** Copyright 2008, The Android Open Source Project
**
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index 25397b5d078f..8a1c4a9dba0d 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -59,21 +59,20 @@ private:
sp<Looper> mLooper;
DisplayEventReceiver mReceiver;
bool mWaitingForVsync;
- bool mFdCallbackRegistered;
};
NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env,
jobject receiverObj, const sp<Looper>& looper) :
mReceiverObjGlobal(env->NewGlobalRef(receiverObj)),
- mLooper(looper), mWaitingForVsync(false), mFdCallbackRegistered(false) {
+ mLooper(looper), mWaitingForVsync(false) {
ALOGV("receiver %p ~ Initializing input event receiver.", this);
}
NativeDisplayEventReceiver::~NativeDisplayEventReceiver() {
ALOGV("receiver %p ~ Disposing display event receiver.", this);
- if (mFdCallbackRegistered) {
+ if (!mReceiver.initCheck()) {
mLooper->removeFd(mReceiver.getFd());
}
@@ -88,6 +87,11 @@ status_t NativeDisplayEventReceiver::initialize() {
return result;
}
+ int rc = mLooper->addFd(mReceiver.getFd(), 0, ALOOPER_EVENT_INPUT,
+ handleReceiveCallback, this);
+ if (rc < 0) {
+ return UNKNOWN_ERROR;
+ }
return OK;
}
@@ -113,15 +117,6 @@ status_t NativeDisplayEventReceiver::scheduleVsync() {
return status;
}
- if (!mFdCallbackRegistered) {
- int rc = mLooper->addFd(mReceiver.getFd(), 0, ALOOPER_EVENT_INPUT,
- handleReceiveCallback, this);
- if (rc < 0) {
- return UNKNOWN_ERROR;
- }
- mFdCallbackRegistered = true;
- }
-
mWaitingForVsync = true;
}
return OK;
@@ -133,7 +128,6 @@ int NativeDisplayEventReceiver::handleReceiveCallback(int receiveFd, int events,
if (events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP)) {
ALOGE("Display event receiver pipe was closed or an error occurred. "
"events=0x%x", events);
- r->mFdCallbackRegistered = false;
return 0; // remove the callback
}
@@ -150,7 +144,7 @@ int NativeDisplayEventReceiver::handleReceiveCallback(int receiveFd, int events,
DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
ssize_t n;
while ((n = r->mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
- ALOGV("receiver %p ~ Read %d events.", this, int(n));
+ ALOGV("receiver %p ~ Read %d events.", data, int(n));
while (n-- > 0) {
if (buf[n].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
vsyncTimestamp = buf[n].header.timestamp;
@@ -161,20 +155,20 @@ int NativeDisplayEventReceiver::handleReceiveCallback(int receiveFd, int events,
}
if (vsyncTimestamp < 0) {
- ALOGV("receiver %p ~ Woke up but there was no vsync pulse!", this);
+ ALOGV("receiver %p ~ Woke up but there was no vsync pulse!", data);
return 1; // keep the callback, did not obtain a vsync pulse
}
ALOGV("receiver %p ~ Vsync pulse: timestamp=%lld, count=%d",
- this, vsyncTimestamp, vsyncCount);
+ data, vsyncTimestamp, vsyncCount);
r->mWaitingForVsync = false;
JNIEnv* env = AndroidRuntime::getJNIEnv();
- ALOGV("receiver %p ~ Invoking vsync handler.", this);
+ ALOGV("receiver %p ~ Invoking vsync handler.", data);
env->CallVoidMethod(r->mReceiverObjGlobal,
gDisplayEventReceiverClassInfo.dispatchVsync, vsyncTimestamp, vsyncCount);
- ALOGV("receiver %p ~ Returned from vsync handler.", this);
+ ALOGV("receiver %p ~ Returned from vsync handler.", data);
if (env->ExceptionCheck()) {
ALOGE("An exception occurred while dispatching a vsync event.");
@@ -182,13 +176,7 @@ int NativeDisplayEventReceiver::handleReceiveCallback(int receiveFd, int events,
env->ExceptionClear();
}
- // Check whether dispatchVsync called scheduleVsync reentrantly and set mWaitingForVsync.
- // If so, keep the callback, otherwise remove it.
- if (r->mWaitingForVsync) {
- return 1; // keep the callback
- }
- r->mFdCallbackRegistered = false;
- return 0; // remove the callback
+ return 1; // keep the callback
}
diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp
index fce432bf5d0d..53774251a43e 100644
--- a/core/jni/android_view_InputChannel.cpp
+++ b/core/jni/android_view_InputChannel.cpp
@@ -199,32 +199,16 @@ static void android_view_InputChannel_nativeReadFromParcel(JNIEnv* env, jobject
bool isInitialized = parcel->readInt32();
if (isInitialized) {
String8 name = parcel->readString8();
- int32_t parcelAshmemFd = parcel->readFileDescriptor();
- int32_t ashmemFd = dup(parcelAshmemFd);
- if (ashmemFd < 0) {
- ALOGE("Error %d dup ashmem fd %d.", errno, parcelAshmemFd);
- }
- int32_t parcelReceivePipeFd = parcel->readFileDescriptor();
- int32_t receivePipeFd = dup(parcelReceivePipeFd);
- if (receivePipeFd < 0) {
- ALOGE("Error %d dup receive pipe fd %d.", errno, parcelReceivePipeFd);
- }
- int32_t parcelSendPipeFd = parcel->readFileDescriptor();
- int32_t sendPipeFd = dup(parcelSendPipeFd);
- if (sendPipeFd < 0) {
- ALOGE("Error %d dup send pipe fd %d.", errno, parcelSendPipeFd);
- }
- if (ashmemFd < 0 || receivePipeFd < 0 || sendPipeFd < 0) {
- if (ashmemFd >= 0) ::close(ashmemFd);
- if (receivePipeFd >= 0) ::close(receivePipeFd);
- if (sendPipeFd >= 0) ::close(sendPipeFd);
+ int32_t rawFd = parcel->readFileDescriptor();
+ int32_t dupFd = dup(rawFd);
+ if (rawFd < 0) {
+ ALOGE("Error %d dup channel fd %d.", errno, rawFd);
jniThrowRuntimeException(env,
"Could not read input channel file descriptors from parcel.");
return;
}
- InputChannel* inputChannel = new InputChannel(name, ashmemFd,
- receivePipeFd, sendPipeFd);
+ InputChannel* inputChannel = new InputChannel(name, dupFd);
NativeInputChannel* nativeInputChannel = new NativeInputChannel(inputChannel);
android_view_InputChannel_setNativeInputChannel(env, obj, nativeInputChannel);
@@ -243,9 +227,7 @@ static void android_view_InputChannel_nativeWriteToParcel(JNIEnv* env, jobject o
parcel->writeInt32(1);
parcel->writeString8(inputChannel->getName());
- parcel->writeDupFileDescriptor(inputChannel->getAshmemFd());
- parcel->writeDupFileDescriptor(inputChannel->getReceivePipeFd());
- parcel->writeDupFileDescriptor(inputChannel->getSendPipeFd());
+ parcel->writeDupFileDescriptor(inputChannel->getFd());
} else {
parcel->writeInt32(0);
}
diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp
index ed0acce699b9..4b737edeea09 100644
--- a/core/jni/android_view_InputEventReceiver.cpp
+++ b/core/jni/android_view_InputEventReceiver.cpp
@@ -40,6 +40,7 @@ static struct {
jclass clazz;
jmethodID dispatchInputEvent;
+ jmethodID dispatchBatchedInputEventPending;
} gInputEventReceiverClassInfo;
@@ -50,7 +51,8 @@ public:
const sp<Looper>& looper);
status_t initialize();
- status_t finishInputEvent(bool handled);
+ status_t finishInputEvent(uint32_t seq, bool handled);
+ status_t consumeEvents(bool consumeBatches);
static int handleReceiveCallback(int receiveFd, int events, void* data);
protected:
@@ -60,8 +62,8 @@ private:
jobject mReceiverObjGlobal;
InputConsumer mInputConsumer;
sp<Looper> mLooper;
- bool mEventInProgress;
PreallocatedInputEventFactory mInputEventFactory;
+ bool mBatchedInputEventPending;
const char* getInputChannelName() {
return mInputConsumer.getChannel()->getName().string();
@@ -72,7 +74,8 @@ private:
NativeInputEventReceiver::NativeInputEventReceiver(JNIEnv* env,
jobject receiverObj, const sp<InputChannel>& inputChannel, const sp<Looper>& looper) :
mReceiverObjGlobal(env->NewGlobalRef(receiverObj)),
- mInputConsumer(inputChannel), mLooper(looper), mEventInProgress(false) {
+ mInputConsumer(inputChannel), mLooper(looper),
+ mBatchedInputEventPending(false) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ Initializing input event receiver.", getInputChannelName());
#endif
@@ -83,45 +86,29 @@ NativeInputEventReceiver::~NativeInputEventReceiver() {
ALOGD("channel '%s' ~ Disposing input event receiver.", getInputChannelName());
#endif
- mLooper->removeFd(mInputConsumer.getChannel()->getReceivePipeFd());
- if (mEventInProgress) {
- mInputConsumer.sendFinishedSignal(false); // ignoring result
- }
+ mLooper->removeFd(mInputConsumer.getChannel()->getFd());
JNIEnv* env = AndroidRuntime::getJNIEnv();
env->DeleteGlobalRef(mReceiverObjGlobal);
}
status_t NativeInputEventReceiver::initialize() {
- status_t result = mInputConsumer.initialize();
- if (result) {
- ALOGW("Failed to initialize input consumer for input channel '%s', status=%d",
- getInputChannelName(), result);
- return result;
- }
-
- int32_t receiveFd = mInputConsumer.getChannel()->getReceivePipeFd();
+ int32_t receiveFd = mInputConsumer.getChannel()->getFd();
mLooper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
return OK;
}
-status_t NativeInputEventReceiver::finishInputEvent(bool handled) {
- if (mEventInProgress) {
+status_t NativeInputEventReceiver::finishInputEvent(uint32_t seq, bool handled) {
#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ Finished input event.", getInputChannelName());
+ ALOGD("channel '%s' ~ Finished input event.", getInputChannelName());
#endif
- mEventInProgress = false;
- status_t status = mInputConsumer.sendFinishedSignal(handled);
- if (status) {
- ALOGW("Failed to send finished signal on channel '%s'. status=%d",
- getInputChannelName(), status);
- }
- return status;
- } else {
- ALOGW("Ignoring attempt to finish input event while no event is in progress.");
- return OK;
+ status_t status = mInputConsumer.sendFinishedSignal(seq, handled);
+ if (status) {
+ ALOGW("Failed to send finished signal on channel '%s'. status=%d",
+ getInputChannelName(), status);
}
+ return status;
}
int NativeInputEventReceiver::handleReceiveCallback(int receiveFd, int events, void* data) {
@@ -139,86 +126,101 @@ int NativeInputEventReceiver::handleReceiveCallback(int receiveFd, int events, v
return 1;
}
- status_t status = r->mInputConsumer.receiveDispatchSignal();
- if (status) {
- ALOGE("channel '%s' ~ Failed to receive dispatch signal. status=%d",
- r->getInputChannelName(), status);
- return 0; // remove the callback
- }
+ status_t status = r->consumeEvents(false /*consumeBatches*/);
+ return status == OK || status == NO_MEMORY ? 1 : 0;
+}
- if (r->mEventInProgress) {
- ALOGW("channel '%s' ~ Publisher sent spurious dispatch signal.",
- r->getInputChannelName());
- return 1;
- }
+status_t NativeInputEventReceiver::consumeEvents(bool consumeBatches) {
+#if DEBUG_DISPATCH_CYCLE
+ ALOGD("channel '%s' ~ Consuming input events, consumeBatches=%s.", getInputChannelName(),
+ consumeBatches ? "true" : "false");
+#endif
- InputEvent* inputEvent;
- status = r->mInputConsumer.consume(&r->mInputEventFactory, &inputEvent);
- if (status) {
- ALOGW("channel '%s' ~ Failed to consume input event. status=%d",
- r->getInputChannelName(), status);
- r->mInputConsumer.sendFinishedSignal(false);
- return 1;
+ if (consumeBatches) {
+ mBatchedInputEventPending = false;
}
JNIEnv* env = AndroidRuntime::getJNIEnv();
- jobject inputEventObj;
- switch (inputEvent->getType()) {
- case AINPUT_EVENT_TYPE_KEY:
+ for (;;) {
+ uint32_t seq;
+ InputEvent* inputEvent;
+ status_t status = mInputConsumer.consume(&mInputEventFactory,
+ consumeBatches, &seq, &inputEvent);
+ if (status) {
+ if (status == WOULD_BLOCK) {
+ if (mInputConsumer.hasPendingBatch() && !mBatchedInputEventPending) {
+ // There is a pending batch. Come back later.
+ mBatchedInputEventPending = true;
#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ Received key event.",
- r->getInputChannelName());
+ ALOGD("channel '%s' ~ Dispatching batched input event pending notification.",
+ getInputChannelName());
#endif
- inputEventObj = android_view_KeyEvent_fromNative(env,
- static_cast<KeyEvent*>(inputEvent));
- break;
+ env->CallVoidMethod(mReceiverObjGlobal,
+ gInputEventReceiverClassInfo.dispatchBatchedInputEventPending);
+
+ if (env->ExceptionCheck()) {
+ ALOGE("channel '%s' ~ An exception occurred while dispatching that "
+ "batched input events are pending.", getInputChannelName());
+ LOGE_EX(env);
+ env->ExceptionClear();
+ mBatchedInputEventPending = false; // try again later
+ }
+ }
+ return OK;
+ }
+ ALOGE("channel '%s' ~ Failed to consume input event. status=%d",
+ getInputChannelName(), status);
+ return status;
+ }
+ assert(inputEvent);
- case AINPUT_EVENT_TYPE_MOTION:
+ jobject inputEventObj;
+ switch (inputEvent->getType()) {
+ case AINPUT_EVENT_TYPE_KEY:
#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ Received motion event.",
- r->getInputChannelName());
+ ALOGD("channel '%s' ~ Received key event.", getInputChannelName());
#endif
- inputEventObj = android_view_MotionEvent_obtainAsCopy(env,
- static_cast<MotionEvent*>(inputEvent));
- break;
+ inputEventObj = android_view_KeyEvent_fromNative(env,
+ static_cast<KeyEvent*>(inputEvent));
+ break;
- default:
- assert(false); // InputConsumer should prevent this from ever happening
- inputEventObj = NULL;
- }
+ case AINPUT_EVENT_TYPE_MOTION:
+#if DEBUG_DISPATCH_CYCLE
+ ALOGD("channel '%s' ~ Received motion event.", getInputChannelName());
+#endif
+ inputEventObj = android_view_MotionEvent_obtainAsCopy(env,
+ static_cast<MotionEvent*>(inputEvent));
+ break;
- if (!inputEventObj) {
- ALOGW("channel '%s' ~ Failed to obtain event object.",
- r->getInputChannelName());
- r->mInputConsumer.sendFinishedSignal(false);
- return 1;
- }
+ default:
+ assert(false); // InputConsumer should prevent this from ever happening
+ inputEventObj = NULL;
+ }
- r->mEventInProgress = true;
+ if (!inputEventObj) {
+ ALOGW("channel '%s' ~ Failed to obtain event object.", getInputChannelName());
+ mInputConsumer.sendFinishedSignal(seq, false);
+ return NO_MEMORY;
+ }
#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ Invoking input handler.", r->getInputChannelName());
-#endif
- env->CallVoidMethod(r->mReceiverObjGlobal,
- gInputEventReceiverClassInfo.dispatchInputEvent, inputEventObj);
-#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ Returned from input handler.", r->getInputChannelName());
+ ALOGD("channel '%s' ~ Dispatching input event.", getInputChannelName());
#endif
+ env->CallVoidMethod(mReceiverObjGlobal,
+ gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
+
+ env->DeleteLocalRef(inputEventObj);
- if (env->ExceptionCheck()) {
- ALOGE("channel '%s' ~ An exception occurred while dispatching an event.",
- r->getInputChannelName());
- LOGE_EX(env);
- env->ExceptionClear();
+ if (env->ExceptionCheck()) {
+ ALOGE("channel '%s' ~ An exception occurred while dispatching an event.",
+ getInputChannelName());
+ LOGE_EX(env);
+ env->ExceptionClear();
- if (r->mEventInProgress) {
- r->mInputConsumer.sendFinishedSignal(false);
- r->mEventInProgress = false;
+ mInputConsumer.sendFinishedSignal(seq, false);
+ return OK;
}
}
-
- env->DeleteLocalRef(inputEventObj);
- return 1;
}
@@ -257,10 +259,11 @@ static void nativeDispose(JNIEnv* env, jclass clazz, jint receiverPtr) {
receiver->decStrong(gInputEventReceiverClassInfo.clazz); // drop reference held by the object
}
-static void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jint receiverPtr, jboolean handled) {
+static void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jint receiverPtr,
+ jint seq, jboolean handled) {
sp<NativeInputEventReceiver> receiver =
reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
- status_t status = receiver->finishInputEvent(handled);
+ status_t status = receiver->finishInputEvent(seq, handled);
if (status) {
String8 message;
message.appendFormat("Failed to finish input event. status=%d", status);
@@ -268,17 +271,29 @@ static void nativeFinishInputEvent(JNIEnv* env, jclass clazz, jint receiverPtr,
}
}
+static void nativeConsumeBatchedInputEvents(JNIEnv* env, jclass clazz, jint receiverPtr) {
+ sp<NativeInputEventReceiver> receiver =
+ reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
+ status_t status = receiver->consumeEvents(true /*consumeBatches*/);
+ if (status) {
+ String8 message;
+ message.appendFormat("Failed to consume batched input event. status=%d", status);
+ jniThrowRuntimeException(env, message.string());
+ }
+}
+
static JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{ "nativeInit",
"(Landroid/view/InputEventReceiver;Landroid/view/InputChannel;Landroid/os/MessageQueue;)I",
(void*)nativeInit },
- { "nativeDispose",
- "(I)V",
+ { "nativeDispose", "(I)V",
(void*)nativeDispose },
- { "nativeFinishInputEvent", "(IZ)V",
- (void*)nativeFinishInputEvent }
+ { "nativeFinishInputEvent", "(IIZ)V",
+ (void*)nativeFinishInputEvent },
+ { "nativeConsumeBatchedInputEvents", "(I)V",
+ (void*)nativeConsumeBatchedInputEvents },
};
#define FIND_CLASS(var, className) \
@@ -299,7 +314,10 @@ int register_android_view_InputEventReceiver(JNIEnv* env) {
GET_METHOD_ID(gInputEventReceiverClassInfo.dispatchInputEvent,
gInputEventReceiverClassInfo.clazz,
- "dispatchInputEvent", "(Landroid/view/InputEvent;)V");
+ "dispatchInputEvent", "(ILandroid/view/InputEvent;)V");
+ GET_METHOD_ID(gInputEventReceiverClassInfo.dispatchBatchedInputEventPending,
+ gInputEventReceiverClassInfo.clazz,
+ "dispatchBatchedInputEventPending", "()V");
return 0;
}
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index bba4b4714979..18bcea1e89e7 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -572,7 +572,7 @@ static jobject Surface_screenshotAll(JNIEnv* env, jobject clazz, jint width, jin
}
static jobject Surface_screenshot(JNIEnv* env, jobject clazz, jint width, jint height,
- jint minLayer, jint maxLayer, bool allLayers)
+ jint minLayer, jint maxLayer)
{
return doScreenshot(env, clazz, width, height, minLayer, maxLayer, false);
}
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 96c125c479f7..19398cf3bebd 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -543,30 +543,30 @@
<item msgid="1735177144948329370">"Tuisfaks"</item>
<item msgid="603878674477207394">"Roeper"</item>
<item msgid="1650824275177931637">"Ander"</item>
- <item msgid="9192514806975898961">"Gepasmaakte"</item>
+ <item msgid="9192514806975898961">"Gepasmaak"</item>
</string-array>
<string-array name="emailAddressTypes">
<item msgid="8073994352956129127">"Tuis"</item>
<item msgid="7084237356602625604">"Werk"</item>
<item msgid="1112044410659011023">"Ander"</item>
- <item msgid="2374913952870110618">"Gepasmaakte"</item>
+ <item msgid="2374913952870110618">"Gepasmaak"</item>
</string-array>
<string-array name="postalAddressTypes">
<item msgid="6880257626740047286">"Tuis"</item>
<item msgid="5629153956045109251">"Werk"</item>
<item msgid="4966604264500343469">"Ander"</item>
- <item msgid="4932682847595299369">"Gepasmaakte"</item>
+ <item msgid="4932682847595299369">"Gepasmaak"</item>
</string-array>
<string-array name="imAddressTypes">
<item msgid="1738585194601476694">"Tuis"</item>
<item msgid="1359644565647383708">"Werk"</item>
<item msgid="7868549401053615677">"Ander"</item>
- <item msgid="3145118944639869809">"Gepasmaakte"</item>
+ <item msgid="3145118944639869809">"Gepasmaak"</item>
</string-array>
<string-array name="organizationTypes">
<item msgid="7546335612189115615">"Werk"</item>
<item msgid="4378074129049520373">"Ander"</item>
- <item msgid="3455047468583965104">"Gepasmaakte"</item>
+ <item msgid="3455047468583965104">"Gepasmaak"</item>
</string-array>
<string-array name="imProtocols">
<item msgid="8595261363518459565">"AIM"</item>
@@ -578,7 +578,7 @@
<item msgid="2506857312718630823">"ICQ"</item>
<item msgid="1648797903785279353">"Jabber"</item>
</string-array>
- <string name="phoneTypeCustom" msgid="1644738059053355820">"Gepasmaakte"</string>
+ <string name="phoneTypeCustom" msgid="1644738059053355820">"Gepasmaak"</string>
<string name="phoneTypeHome" msgid="2570923463033985887">"Tuis"</string>
<string name="phoneTypeMobile" msgid="6501463557754751037">"Mobiel"</string>
<string name="phoneTypeWork" msgid="8863939667059911633">"Werk"</string>
@@ -599,24 +599,24 @@
<string name="phoneTypeWorkPager" msgid="649938731231157056">"Werkroeper"</string>
<string name="phoneTypeAssistant" msgid="5596772636128562884">"Assistent"</string>
<string name="phoneTypeMms" msgid="7254492275502768992">"MMS"</string>
- <string name="eventTypeCustom" msgid="7837586198458073404">"Gepasmaakte"</string>
+ <string name="eventTypeCustom" msgid="7837586198458073404">"Gepasmaak"</string>
<string name="eventTypeBirthday" msgid="2813379844211390740">"Verjaardag"</string>
<string name="eventTypeAnniversary" msgid="3876779744518284000">"Herdenking"</string>
<string name="eventTypeOther" msgid="7388178939010143077">"Ander"</string>
- <string name="emailTypeCustom" msgid="8525960257804213846">"Gepasmaakte"</string>
+ <string name="emailTypeCustom" msgid="8525960257804213846">"Gepasmaak"</string>
<string name="emailTypeHome" msgid="449227236140433919">"Tuis"</string>
<string name="emailTypeWork" msgid="3548058059601149973">"Werk"</string>
<string name="emailTypeOther" msgid="2923008695272639549">"Ander"</string>
<string name="emailTypeMobile" msgid="119919005321166205">"Mobiel"</string>
- <string name="postalTypeCustom" msgid="8903206903060479902">"Gepasmaakte"</string>
+ <string name="postalTypeCustom" msgid="8903206903060479902">"Gepasmaak"</string>
<string name="postalTypeHome" msgid="8165756977184483097">"Tuis"</string>
<string name="postalTypeWork" msgid="5268172772387694495">"Werk"</string>
<string name="postalTypeOther" msgid="2726111966623584341">"Ander"</string>
- <string name="imTypeCustom" msgid="2074028755527826046">"Gepasmaakte"</string>
+ <string name="imTypeCustom" msgid="2074028755527826046">"Gepasmaak"</string>
<string name="imTypeHome" msgid="6241181032954263892">"Tuis"</string>
<string name="imTypeWork" msgid="1371489290242433090">"Werk"</string>
<string name="imTypeOther" msgid="5377007495735915478">"Ander"</string>
- <string name="imProtocolCustom" msgid="6919453836618749992">"Gepasmaakte"</string>
+ <string name="imProtocolCustom" msgid="6919453836618749992">"Gepasmaak"</string>
<string name="imProtocolAim" msgid="7050360612368383417">"AIM"</string>
<string name="imProtocolMsn" msgid="144556545420769442">"Windows Live"</string>
<string name="imProtocolYahoo" msgid="8271439408469021273">"Yahoo"</string>
@@ -628,8 +628,8 @@
<string name="imProtocolNetMeeting" msgid="8287625655986827971">"NetMeeting"</string>
<string name="orgTypeWork" msgid="29268870505363872">"Werk"</string>
<string name="orgTypeOther" msgid="3951781131570124082">"Ander"</string>
- <string name="orgTypeCustom" msgid="225523415372088322">"Gepasmaakte"</string>
- <string name="relationTypeCustom" msgid="3542403679827297300">"Gepasmaakte"</string>
+ <string name="orgTypeCustom" msgid="225523415372088322">"Gepasmaak"</string>
+ <string name="relationTypeCustom" msgid="3542403679827297300">"Gepasmaak"</string>
<string name="relationTypeAssistant" msgid="6274334825195379076">"Assistent"</string>
<string name="relationTypeBrother" msgid="8757913506784067713">"Broer"</string>
<string name="relationTypeChild" msgid="1890746277276881626">"Kind"</string>
@@ -644,7 +644,7 @@
<string name="relationTypeRelative" msgid="1799819930085610271">"Familielid"</string>
<string name="relationTypeSister" msgid="1735983554479076481">"Suster"</string>
<string name="relationTypeSpouse" msgid="394136939428698117">"Eggenoot"</string>
- <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Gepasmaakte"</string>
+ <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Gepasmaak"</string>
<string name="sipAddressTypeHome" msgid="6093598181069359295">"Tuis"</string>
<string name="sipAddressTypeWork" msgid="6920725730797099047">"Werk"</string>
<string name="sipAddressTypeOther" msgid="4408436162950119849">"Ander"</string>
@@ -764,6 +764,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Laat die program toe om te verifieer dat \'n pakket installeerbaar is."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bind aan \'n pakkieverifieerder"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Laat die houer toe om versoeke aan pakketverifieerders te rig. Dit moet nooit vir normale programme nodig wees nie."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"kry toegang tot reekspoorte"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Laat die houer toe om toegang te verkry tot reekspoorte wat die SerialManager API gebruik."</string>
<string name="save_password_message" msgid="767344687139195790">"Wil jy hê die blaaier moet hierdie wagwoord onthou?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Nie nou nie"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Onthou"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 52b690dc320f..8f7b70f10c7b 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"ወደ ግንባር ዎይ እና ዳራ ስራዎችን ለማንቀሳቀስ ለመተግበሪያው ይፈቅዳሉ፡፡ ያለአንተ ቁጥጥር ተንኮል አዘል መተግበሪያዎች ራሳቸውን ወደፊት መምጣት ሊያስገድዱ ይችላሉ፡፡"</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"የአሂድ ትግበራዎች አቁም"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"ተግባሮችን ለማስወገድ እና መተግበሪያዎቻቸውን ለመግደል ለመተግበሪያ ይፈቅዳል። ጎጂ የሆኑ መተግበሪያዎች የሌሎችን መተግበሪያዎችን ባህሪ ሊያውኩ ይችላሉ።"</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"የማያ ገጽ ተኳኋኝነት መድብ"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"መተግበሪያው የሌሎች መተግበሪያዎች የማያ ገጽ ተኳኋኝነት ሁናቴ እንዲቆጣጠር ይፈቅዳል። ተንኮለኛ መተግበሪያዎች የሌሎች መተግበሪያዎች ባህሪ ሊሰብሩ ይችላሉ።"</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"የትግበራ ማረሚያ አንቃ"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"ለሌላ መተግበሪያ አርምን አብራ ለመተግበሪያው ይፈቅዳሉ። ሌሎች መተግበሪያዎች ለመግደል ተንኮል አዘል መተግበሪያዎች ይሄንን ሊጠቀሙት ይችላሉ።"</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"የUI ቅንብሮችን ለውጥ"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"ፓኬጅ መጫን የሚችል መሆኑን ለማረጋገጥ ለመተግበሪያው ይፈቅዳሉ፡፡"</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"በፓኬጅ አረጋጋጭ የተወሰነ"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"የፓኬጅ አረጋጋጮችን ጥየቃ ለማድረግ ያዡ ይፈቅዳሉ። ለመደበኛ ትግበራዎች በፍፁም አያስፈልግም።"</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"ተከታታይ ወደቦችን ድረስ"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Allows the holder to access serial ports using the SerialManager API. የተከታታይ አደራጅ APIን በመጠቀም ያዡ የተከታታይ ወደቦችን እንዲደርስ ይፈቅዳል።"</string>
<string name="save_password_message" msgid="767344687139195790">"አሳሹ ይህን ይለፍ ቃል እንዲያስታወስ ይፈልጋሉ?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"አሁን አይደለም"</string>
<string name="save_password_remember" msgid="6491879678996749466">"አስታውስ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 2c02f665cabd..c9de7de2cc31 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"للسماح لتطبيق ما بنقل المهام إلى المقدمة والخلفية. قد تفرض التطبيقات الضارة نفسها إلى المقدمة بدون تحكم منك."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"إيقاف التطبيقات التي قيد التشغيل"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"للسماح للتطبيق بإزالة المهام وإنهاء تطبيقاتها. قد تعطل التطبيقات الضارة عمل التطبيقات الأخرى."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"تعيين توافق الشاشة"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"السماح للتطبيق بالتحكم في وضع التوافق مع شاشة التطبيقات الأخرى. قد تتسبب التطبيقات الضارة في تعطيل سلوك التطبيقات الأخرى."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"تمكين تصحيح أخطاء التطبيق"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"للسماح للتطبيق بتشغيل تصحيح الأخطاء لتطبيق آخر. قد تستخدم التطبيقات الضارة هذا لإنهاء التطبيقات الأخرى."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"تغيير إعدادات واجهة المستخدم"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"السماح للتطبيق بالتحقق من إمكانية تثبيت حزمة."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"الالتزام بمحقق حزمة"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"السماح للمالك بإجراء طلبات محققي الحزمة. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"الدخول إلى المنافذ التسلسلية"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"يسمح لحامله بالدخول إلى المنافذ التسلسلية باستخدام واجهة برمجة التطبيقات."</string>
<string name="save_password_message" msgid="767344687139195790">"هل تريد من المتصفح تذكر كلمة المرور هذه؟"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"ليس الآن"</string>
<string name="save_password_remember" msgid="6491879678996749466">"تذكّر"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index d17447e6c41a..adb13388b67f 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Дазваляе прыкладанням перамяшчаць заданні на ​​пярэдні план і фон. Шкоднасныя прыкладанні могуць прымусова рабіць сябе асноўнымі без вашага ведама."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"спыніць запушчаныя прыкладанні"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Дазваляе прыкладанням выдаляць заданні і спыняць прыкладанні, якія іх выкарыстоўваюць. Шкоднасныя прыкладаннi могуць перашкодзiць працы іншых прыкладанняў."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"усталяваць сумяшчальнасць экранаў"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Дазваляе прыкладанню кіраваць рэжымам сумяшчальнасці экранаў іншых прыкладанняў. Шкоднаснае ПЗ можа перашкодзiць працы іншых прыкладанняў."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"уключыць адладку прыкладання"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Дазваляе прыкладанням уключаць адладку для іншага прыкладання. Шкоднасныя прыкладанні могуць выкарыстоўваць гэта, каб спыняць іншыя прыкладанні."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"змяняць налады карыстальніцкага інтэрфейса"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Дазваляе прыкладанням правяраць магчымасць усталявання пакету."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"прывязаць да верыфікатару пакету"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Дазваляе ўладальніку рабіць запыты верыфікатараў пакету. Не патрабуецца для звычайных прыкладанняў."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"атрымаць доступ да паслядоўных партоў"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Дазваляе ўладальніку атрымліваць доступ да паслядоўных партоў з дапамогай API SerialManager."</string>
<string name="save_password_message" msgid="767344687139195790">"Вы хочаце, каб браўзэр запомніў гэты пароль?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Не цяпер"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Запомніць"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 5c54a6015910..23ae6c22ad24 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -764,6 +764,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Разрешава на приложението да провери дали пакетът може да се инсталира."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"обвързване с верификатор на пакета"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Разрешава на притежателя да прави заявки за верификатори на пакета. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"достъп до серийни портове"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Разрешава на притежателя достъп до серийни портове посредством приложния програмен интерфейс (API) SerialManager."</string>
<string name="save_password_message" msgid="767344687139195790">"Искате ли браузърът да запомни тази парола?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Не сега"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Запомняне"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 6faa7ff6814e..460fcb7f504a 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permet que l\'aplicació desplaci tasques en primer o segon pla. Les aplicacions malicioses poden aparèixer en primer pla sense el teu consentiment."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"atura les aplicacions que s\'estan executant"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Permet que l\'aplicació elimini tasques i finalitzi les seves aplicacions. Les aplicacions malicioses poden alterar el comportament d\'altres aplicacions."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"definició de la compatibilitat de pantalla"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Permet que l\'aplicació controli el mode de compatibilitat de pantalla d\'altres aplicacions. És possible que les aplicacions malicioses interrompin el comportament d\'altres aplicacions."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"activa la depuració d\'aplicacions"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permet que una aplicació activi la depuració per a una altra aplicació. Les aplicacions malicioses poden utilitzar aquesta funció per finalitzar altres aplicacions."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"canviar la configuració de la IU"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permet que l\'aplicació verifiqui si un paquet es pot instal·lar."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"vincula a un verificador de paquets"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permet que el titular sol·liciti verificadors de paquets. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"accedeix a ports sèrie"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Permet que el titular accedeixi a ports sèrie amb l\'API SerialManager."</string>
<string name="save_password_message" msgid="767344687139195790">"Voleu que el navegador recordi aquesta contrasenya?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Ara no"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Recorda-ho"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index d0cdd0dc3558..c801fb4bb67f 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -764,6 +764,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Umožňuje aplikaci ověřit, zda balíček lze nainstalovat."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"navázat na ověřovatele balíčků"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Umožňuje držiteli podávat žádosti o ověření balíčků. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"přístup k sériovým portům"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Umožňuje držiteli přístup k sériovým portům pomocí rozhraní SerialManager API."</string>
<string name="save_password_message" msgid="767344687139195790">"Chcete, aby si prohlížeč zapamatoval toto heslo?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Nyní ne"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Zapamatovat"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 44a770718cde..65d7cdce5f13 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Tillader, at appen kan flytte opgaver til forgrunden og baggrunden. Ondsindede apps kan tvinge sig selv i forgrunden uden din kontrol."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"stoppe kørsel af apps"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Tillader, at en app kan fjerne opgaver og lukke deres apps. Ondsindede apps kan forstyrre adfærden for andre apps."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"indstil skærmens kompatibilitet"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Tillader, at appen kontrollerer kompatibilitetstilstanden for skærme i andre applikationer. Ondsindede applikationer kan forstyrre andre applikationers adfærd."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"aktivere fejlretning af appen"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Tillader, at appen kan slå fejlretning til for en anden app. Ondsindede apps kan bruge dette til at afslutte andre apps."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"skift indstillinger for brugergrænsefladen"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Tillader, at appen kan bekræfte, at en pakke kan installeres."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bind til en bekræftelse af pakker"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Tillader, at indehaveren kan sende anmodninger om bekræftelser af pakker. Dette bør aldrig være nødvendigt for almindelige apps."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"adgang til serielle porte"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Tillader, at indehaveren kan få adgang til serielle porte ved hjælp af SerialManager API."</string>
<string name="save_password_message" msgid="767344687139195790">"Ønsker du, at browseren skal huske denne adgangskode?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Ikke nu"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Husk"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 7d0ce02b954e..dbe81373bcfc 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Ermöglicht der App, Aufgaben in den Vorder- und Hintergrund zu verschieben. Schädliche Apps können so ohne Ihr Zutun eine Anzeige im Vordergrund erzwingen."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"Aktive Apps beenden"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Ermöglicht der App, Aufgaben zu entfernen und die entsprechenden Apps zu beenden. Schädliche Apps können das Verhalten anderer Apps stören."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"Bildschirmkompatibilität festlegen"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Ermöglicht der App, den Bildschirmkompatibilitätsmodus anderer Apps zu steuern. Schädliche Apps können das Verhalten anderer Apps stören."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"Fehlerbeseitigung für App aktivieren"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Ermöglicht der App, die Fehlerbeseitigung für eine andere App zu aktivieren. Schädliche Apps können so andere Apps beenden."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"UI-Einstellungen ändern"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Ermöglicht der App die Überprüfung, ob ein Paket installiert werden kann"</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"An Paketprüfung binden"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Ermöglicht dem Halter, Anfragen für die Paketprüfung zu senden. Sollte nie für normale Apps benötigt werden."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"Zugriff auf serielle Schnittstellen"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Ermöglicht dem Inhaber den Zugriff auf serielle Schnittstellen über das SerialManager-API"</string>
<string name="save_password_message" msgid="767344687139195790">"Möchten Sie, dass der Browser dieses Passwort speichert?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Nicht jetzt"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Speichern"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 49465e8d065f..154ca55f578a 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -764,6 +764,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Επιτρέπει στην εφαρμογή να επαληθεύσει τη δυνατότητα εγκατάστασης ενός πακέτου."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"δέσμευση με επαλήθευση πακέτου"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Επιτρέπει στον κάτοχο να υποβάλλει ερωτήματα σε προγράμματα επαλήθευσης πακέτου. Δεν απαιτείται για συνήθεις εφαρμογές."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"πρόσβαση στις σειριακές θύρες"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Επιτρέπει στον κάτοχο την πρόσβαση στις σειριακές θύρες με τη χρήση του SerialManager API."</string>
<string name="save_password_message" msgid="767344687139195790">"Θέλετε το πρόγραμμα περιήγησης να διατηρήσει αυτόν τον κωδικό πρόσβασης;"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Να μην γίνει τώρα"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Διατήρηση"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 33a3b7ac3d97..0429c8b7f3f6 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Allows the app to move tasks to the foreground and background. Malicious apps may force themselves to the front without your control."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"stop running apps"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Allows the app to remove tasks and kill their apps. Malicious apps may disrupt the behaviour of other apps."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"set screen compatibility"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Allows the app to control the screen compatibility mode of other applications. Malicious applications may break the behaviour of other applications."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"enable app debugging"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Allows the app to turn on debugging for another app. Malicious apps may use this to kill other apps."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"change your UI settings"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Allows the app to verify a package is installable."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bind to a package verifier"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Allows the holder to make requests of package verifiers. Should never be needed for normal apps."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"access serial ports"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Allows the holder to access serial ports using the SerialManager API."</string>
<string name="save_password_message" msgid="767344687139195790">"Do you want the browser to remember this password?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Not now"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Remember"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 41d2a47d0869..ad3e949899a8 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permite que la aplicación mueva tareas al primero o segundo plano. Las aplicaciones maliciosas pueden forzar su paso al primer plano sin que tú las controles."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"detener las aplicaciones en ejecución"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite que la aplicación elimine tareas y cierre sus aplicaciones. Las aplicaciones malintencionadas pueden usar este permiso para interferir en el comportamiento de otras aplicaciones."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"Configurar el modo de la compatibilidad de otras pantalla"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Permite a la aplicación controlar el modo de la compatibilidad de las pantallas de otras aplicaciones. Las aplicaciones malintencionadas pueden interrumpir el funcionamiento de otras aplicaciones."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"activar depuración de aplicación"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permite que la aplicación active la depuración de otra aplicación. Las aplicaciones malintencionadas pueden usar este permiso para interrumpir la ejecución de otras aplicaciones."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"cambiar tu configuración de la interfaz de usuario"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permite que la aplicación verifique si se puede instalar un paquete."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"Vincular a un verificador de paquetes"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite que el titular solicite verificadores de paquetes. Las aplicaciones normales no deberían necesitar este permiso."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"Acceder a los puertos serie"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite acceder a puertos serie a través de la API SerialManager."</string>
<string name="save_password_message" msgid="767344687139195790">"¿Quieres recordar esta contraseña en el navegador?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Ahora no."</string>
<string name="save_password_remember" msgid="6491879678996749466">"Recuerda"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index e9b1ab36df03..1bd13bd2b320 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permite que la aplicación mueva tareas a segundo o a primer plano. Algunas aplicaciones malintencionadas pueden aparecer en primer plano sin el control del usuario."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"detener aplicaciones en ejecución"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite que la aplicación termine tareas y cierre sus aplicaciones. Las aplicaciones malintencionadas pueden usar este permiso para interferir en el comportamiento de otras aplicaciones."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"establecer compatibilidad de pantalla"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Permite que la aplicación controle el modo de compatibilidad de la pantalla de otras aplicaciones. Las aplicaciones malintencionadas pueden influir de forma negativa en el funcionamiento de otras aplicaciones."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"habilitar depuración de aplicación"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permite que la aplicación active la depuración de otra aplicación. Las aplicaciones malintencionadas pueden usar este permiso para interrumpir la ejecución de otras aplicaciones."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"cambiar la configuración de la interfaz de usuario"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permite que la aplicación verifique si se puede instalar un paquete."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"enlazar con un detector de paquetes"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite que se envíen solicitudes de detectores de paquetes. Las aplicaciones normales no deberían necesitar este permiso."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"acceder a puertos serie"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite acceder a puertos serie a través de SerialManager API."</string>
<string name="save_password_message" msgid="767344687139195790">"¿Quieres que el navegador recuerde esta contraseña?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Ahora no"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Recordar"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 8dfebb6d9c4e..2f42a70d72e9 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Võimaldab rakendusel teisaldada ülesanded esiplaanile ja taustale. Pahatahtlikud rakendused võivad sundida end esiplaanile tulema teie loata."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"käitatud rakenduste peatamine"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Võimaldab rakendusel eemaldada ülesanded ja peatada nende rakendused. Pahatahtlikud rakendused võivad häirida teiste rakenduste käitumist."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"kuva ühilduvuse seadmine"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Võimaldab rakendusel juhtida teiste rakenduste kuva ühilduvuse režiimi. Pahatahtlikud rakendused võivad teisi rakendusi häirida."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"Rakenduse silumise lubamine"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Võimaldab rakendusel lülitada sisse teise rakenduse silumise. Pahatahtlikud rakendused võivad seda kasutada teiste rakenduste peatamiseks."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"muuda UI-seadeid"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Võimaldab rakendusel kinnitada, et paketti saab installida."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"sidumine paketi kinnitajaga"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Lubab omanikul teha taotlusi paketi kinnitajate kohta. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"juurdepääs jadaportidele"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Võimaldab omanikul SerialManageri API-liidese abil jadaportidele juurde pääseda."</string>
<string name="save_password_message" msgid="767344687139195790">"Kas soovite, et brauser jätaks selle parooli meelde?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Mitte praegu"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Pidage meeles"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index a5bf61ae329a..fd7a77190b7e 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"به برنامه اجازه می‎دهد تا کارها را به پیش زمینه و پس زمینه منتقل کند. برنامه‎های مخرب می‎توانند بدون کنترل به اجبار خود را به جلو منتقل کنند."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"متوقف کردن برنامه‎های در حال اجرا"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"به برنامه اجازه می‎دهد تا کارها را حذف کند و برنامه‎های آنها را متوقف کند. برنامه‎های مخرب می‌توانند در اجرای برنامه‎های دیگر اختلال ایجاد ‎کنند."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"تنظیم سازگاری با صفحه نمایش"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"به برنامه کاربردی اجازه کنترل حالت سازگاری صفحه نمایش برای برنامه‌های دیگر را می‌دهد. برنامه‌های خرابکار ممکن است باعث کارکرد نادرست دیگر برنامه‌ها شوند."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"فعال کردن عیب‌یابی برنامه"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"به برنامه اجازه می‎دهد تا عیب‌یابی را برای برنامه‌ای دیگر فعال کند. برنامه‎های مخرب می‎توانند از آن استفاده کنند تا اجرای برنامه‎های دیگر را متوقف کنند."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"تغییر تنظیمات UI"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"به برنامه اجازه می‌دهد قابل نصب بودن بسته را تأیید کند."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"اتصال به یک تأیید کننده بسته"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"به دارنده اجازه می‎دهد تا تاییدکنندگان بسته را درخواست کند. برای برنامه‎های عادی نیاز نیست."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"دسترسی به درگاه‌های سریال"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"به دارنده اجازه می‌دهد با استفاده از SerialManager API به درگاه‌های سریال دسترسی داشته باشد."</string>
<string name="save_password_message" msgid="767344687139195790">"می خواهید مرورگر این رمز ورود را به خاطر داشته باشد؟"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"اکنون خیر"</string>
<string name="save_password_remember" msgid="6491879678996749466">"به خاطر سپردن"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 801f815c1309..9cf18ecc6237 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Antaa sovelluksen siirtää tehtäviä etualalle ja taustalle. Haitalliset sovellukset voivat pakottaa itsensä etualalle ilman käyttäjän hallintaa."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"käynnissä olevien sovellusten pysäyttäminen"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Antaa sovelluksen poistaa tehtäviä ja lopettaa niiden sovelluksia. Haitalliset sovellukset voivat häiritä muiden sovellusten toimintaa."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"aseta näytön yhteensopivuus"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Sallii sovelluksen hallita toisten sovellusten näytön yhteensopivuustilaa. Haittasovellukset voivat häiritä toisten sovellusten toimintaa."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"sovellusten vianetsinnän käyttöönotto"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Antaa sovelluksen ottaa vianetsinnän käyttöön toisessa sovelluksessa. Haitalliset ohjelmat voivat lopettaa tällä muita sovelluksia."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"muuta käyttöliittymäsi asetuksia"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Antaa sovelluksen vahvistaa, että pakkaus on asennettavissa."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"sitoudu paketin vahvistajaan"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Antaa sovelluksen tehdä pakettien vahvistuspyyntöjä. Ei tavallisten sovellusten käyttöön."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"käytä sarjaportteja"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Luvan haltija voi käyttää sarjaportteja SerialManager-sovellusliittymän avulla."</string>
<string name="save_password_message" msgid="767344687139195790">"Haluatko selaimen muistavan tämän salasanan?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Ei nyt"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Muista"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 2848cd582a2e..33b0f45bd664 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permet à l\'application de faire passer les tâches de premier plan en arrière-plan. Des applications malveillantes peuvent exploiter cette fonctionnalité pour passer au premier plan sans votre consentement."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"arrêter les applications en cours d\'exécution"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Permet à l\'application de supprimer des tâches et de fermer les applications qui les exécutent. Des applications malveillantes peuvent exploiter cette fonctionnalité pour perturber le comportement des autres applications."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"définir la compatibilité de l\'écran"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Permettre de contrôler le mode de compatibilité de l\'écran des autres applications. Des applications malveillantes peuvent perturber le fonctionnement d\'autres applications."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"activer le débogage des applications"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permet à l\'application d\'activer le débogage d\'une autre application. Des applications malveillantes peuvent exploiter cette fonctionnalité pour en fermer d\'autres."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"Modification des paramètres de l\'IU"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permet à l\'application de vérifier qu\'un package peut être installé."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"associer à un vérificateur de package"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permet à l\'application autorisée d\'effectuer des requêtes de vérificateurs de package. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"accéder aux ports série"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Permet à l\'application autorisée d\'accéder aux ports série avec l\'API SerialManager."</string>
<string name="save_password_message" msgid="767344687139195790">"Voulez-vous que le navigateur se souvienne de ce mot de passe ?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Pas maintenant"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Mémoriser"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index f56871a3d5f3..91ac5a370f31 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"एप्लिकेशन को अग्रभूमि और पृष्ठभूमि में कार्यों को ले जाने देता है. दुर्भावनापूर्ण एप्लिकेशन आपके नियंत्रण के बिना स्वयं को बलपूर्वक आगे कर सकते हैं."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"चलने वाले एप्लिकेशन रोकें"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"किसी एप्‍लिकेशन को कार्यों को निकालने और उनके एप्‍लिकेशन समाप्त करने देता है. दुर्भावनापूर्ण एप्‍लिकेशन अन्‍य एप्‍लिकेशन का व्‍यवहार बाधित कर सकते हैं."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"स्‍क्रीन संगतता सेट करें"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"एप्‍लिकेशन को अन्‍य एप्‍लिकेशन के स्‍क्रीन संगतता मोड को नियंत्रित करने देता है. दुर्भावनापूर्ण एप्‍लिकेशन अन्‍य एप्‍लिकेशन का व्‍यवहार बाधित कर सकते हैं."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"एप्‍लिकेशन डीबग करना सक्षम करें"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"एप्लिकेशन को अन्य एप्लिकेशन के लिए डीबग किया जाना चालू करने देता है. दुर्भावनापूर्ण एप्लिकेशन इसका उपयोग अन्य एप्लिकेशन को समाप्त करने के लिए कर सकते हैं."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"अपनी UI सेटिंग बदलें"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"एप्‍लि‍केशन को इंस्‍टॉल करने योग्‍य पैकेज सत्‍यापि‍त करने देता है."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"पैकेज प्रमाणक से आबद्ध करें"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"धारक को पैकेज प्रमाणक के अनुरोध की अनुमति‍ देता है. सामान्‍य एप्‍लिकेशन के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"सीरियल पोर्ट पर पहुंचें"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager API का उपयोग करके धारक को सीरियल पोर्ट पर पहुंच प्रदान करता है."</string>
<string name="save_password_message" msgid="767344687139195790">"क्‍या आप चाहते हैं कि ब्राउज़र पासवर्ड को याद रखे?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"अभी नहीं"</string>
<string name="save_password_remember" msgid="6491879678996749466">"याद रखें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 7c4a9d7a2cbb..a60dcfaddff7 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Omogućuje aplikaciji da premjesti zadatke u prednji plan ili pozadinu. Zlonamjerne aplikacije mogu na silu doći u prednji plan bez vašeg nadzora."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"zaustavljanje pokrenutih aplikacija"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Omogućuje aplikaciji uklanjanje zadataka i uklanjanje njihovih aplikacija. Zlonamjerne aplikacije mogu poremetiti rad drugih aplikacija."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"postavljanje zaslona kompatibilnost"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Aplikaciji omogućuje upravljanje načinom kompatibilnosti zaslona drugih aplikacija. Zlonamjerne aplikacije mogu prekinuti takvo ponašanje ostalih aplikacija."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"omogućavanje rješavanja programskih pogrešaka u aplikaciji"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Omogućuje aplikaciji uključivanje uklanjanja programskih pogrešaka za drugu aplikaciju. Zlonamjerne aplikacije mogu na taj način ukloniti druge aplikacije."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"promjena postavki korisničkog sučelja"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Aplikaciji omogućuje da provjeri je li paket moguće instalirati."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"vezano uz paketnu provjeru"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Nositelju omogućuje da traži paketnu provjeru. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"pristup serijskim priključcima"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Rukovatelju omogućuje pristup serijskim priključcima pomoću značajke SerialManager API."</string>
<string name="save_password_message" msgid="767344687139195790">"Želite li da preglednik zapamti ovu zaporku?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Ne sada"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Zapamti"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index e8920bceb4d7..6b789ea5da70 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Lehetővé teszi az alkalmazás számára, hogy feladatokat helyezzen át az előtérből a háttérbe és fordítva. A rosszindulatú alkalmazások az előtérbe helyezhetik magukat az Ön engedélye nélkül."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"futó alkalmazások leállítása"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Lehetővé teszi, hogy az alkalmazás feladatokat távolítson el és leállítsa azok alkalmazásait. Rosszindulatú alkalmazások megzavarhatják más alkalmazások viselkedését."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"Képernyő-kompatibilitás beállítása"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Lehetővé teszi, hogy az alkalmazás szabályozza az egyéb alkalmazások képernyő-kompatibilitási módját. A kártékony alkalmazások megzavarhatják a többi alkalmazás viselkedését."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"alkalmazások hibakeresésének bekapcsolása"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Lehetővé teszi az alkalmazás számára, hogy hibakeresést végezzen egy másik alkalmazáson. A rosszindulatú alkalmazások ezzel leállíthatnak más alkalmazásokat."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"a felhasználói felület beállításainak módosítása"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Lehetővé teszi az alkalmazás számára, hogy ellenőrizze, egy csomag telepíthető-e."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"egy csomaghitelesítőhöz kötődnek"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Lehetővé teszi, hogy a tulajdonos kérelmeket nyújtson be a csomag hitelesítőivel kapcsolatban. A normál alkalmazásoknak erre soha nincs szüksége."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"soros portok elérése"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Lehetővé teszi a tulajdonos számára a soros portok elérését a SerialManager API segítségével."</string>
<string name="save_password_message" msgid="767344687139195790">"Szeretné, hogy a böngésző megjegyezze a jelszót?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Most nem"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Megjegyzés"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 49b368f44627..6ed5c0e4b600 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Mengizinkan apl memindah tugas ke latar depan dan latar belakang. Apl berbahaya dapat memaksa berpindah ke depan tanpa kontrol Anda."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"menghentikan apl yang berjalan"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Memungkinkan apl menghapus tugas dan menutup aplikasinya. Apl berbahaya dapat mengganggu perilaku apl lain."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"menyetel kompatibilitas layar"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Memungkinkan apl mengontrol mode kompatibilitas layar aplikasi lain. Aplikasi berbahaya dapat merusak perilaku aplikasi lain."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"mengaktifkan debugging apl"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Mengizinkan apl mengaktifkan debugging untuk apl lain. Apl berbahaya dapat menggunakan cara ini untuk menutup apl lain."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"ubah setelan UI Anda"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Mengizinkan apl memverifikasi bahwa suatu paket dapat dipasang."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"mengikat ke pemverifikasi paket"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Mengizinkan pemegang mengajukan permintaan pemverifikasian paket. Tidak pernah dibutuhkan oleh apl normal."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"akses port serial"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Memungkinkan pemegangnya mengakses port serial menggunakan API SerialManager."</string>
<string name="save_password_message" msgid="767344687139195790">"Apakah Anda ingin peramban menyimpan sandi ini?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Tidak sekarang"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Ingat"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 46e90d379f82..8af1f5eee701 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Consente all\'applicazione di spostare attività in primo piano e in background. Le applicazioni dannose potrebbero forzare la loro impostazione in primo piano senza il tuo controllo."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"interruzione applicazioni in esecuzione"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Consente all\'applicazione di rimuovere le attività e terminare le loro applicazioni. Le applicazioni dannose potrebbero interferire con il comportamento di altre applicazioni."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"impostazione compatibilità schermo"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Consente all\'applicazione di controllare la modalità di compatibilità dello schermo di altre applicazioni. Le applicazioni dannose potrebbero disturbare il comportamento di altre applicazioni."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"attivazione debug delle applicazioni"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Consente all\'applicazione di attivare il debug per un\'altra applicazione. Le applicazioni dannose potrebbero farne uso per terminare altre applicazioni."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"modifica impostazioni UI"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Consente all\'applicazione di verificare se un pacchetto è installabile."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"associazione a verifica pacchetto"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Consente al proprietario di effettuare richieste relative alle verifiche dei pacchetti. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"accesso alle porte seriali"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Permette al proprietario di accedere alle porte seriali utilizzando l\'API SerialManager."</string>
<string name="save_password_message" msgid="767344687139195790">"Memorizzare la password nel browser?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Non ora"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Memorizza"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 9cde4b3a60c4..5d5b9daed4d2 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"מאפשר ליישום להעביר משימות לחזית ולרקע. יישומים זדוניים עלולים לאלץ את עצמם לעבור לחזית ללא שליטה מצדך."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"עצירת יישומים פעילים"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"הרשאה זו מאפשרת ליישום להסיר משימות ולסגור את היישומים שבהם הן פועלות. יישומים זדוניים עלולים לשבש את פעולתם של יישומים אחרים."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"הגדרת תאימות מסך"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"מאפשר ליישום לשלוט במצב תאימות המסך של יישומים אחרים. יישומים זדוניים עלולים לפגוע בהתנהגות של יישומים אחרים."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"הפעלה של ניקוי באגים ביישומים"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"הרשאה זו מאפשרת ליישום להפעיל ניקוי באגים עבור יישום אחר. יישומים זדוניים עלולים להשתמש באפשרות זו כדי לסגור יישומים אחרים."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"שנה את הגדרות ממשק המשתמש שלך"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"מאפשר ליישום לאמת שחבילה ניתנת להתקנה."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"הכפפה למאמת חבילה"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"מאפשר למשתמש להגיש בקשות של מאמתי חבילות. הרשאה זו לעולם אינה נחוצה ליישומים רגילים."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"גישה ליציאות טוריות"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"מאפשר לבעלים לגשת ליציאות טוריות באמצעות ממשק ה- API של SerialManager."</string>
<string name="save_password_message" msgid="767344687139195790">"האם ברצונך שהדפדפן יזכור סיסמה זו?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"לא כעת"</string>
<string name="save_password_remember" msgid="6491879678996749466">"זכור"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 827644edfbac..ea4af6610ae0 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -764,6 +764,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"パッケージがインストール可能かどうか確認することをアプリに許可します。"</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"パッケージベリファイアにバインド"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"パッケージベリファイアのリクエストを所有者に許可します。通常のアプリでは不要です。"</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"シリアルポートへのアクセス"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager APIを使用してシリアルポートにアクセスすることを所有者に許可します。"</string>
<string name="save_password_message" msgid="767344687139195790">"このパスワードをブラウザで保存しますか?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"今は保存しない"</string>
<string name="save_password_remember" msgid="6491879678996749466">"保存"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 14735b0c002f..2c664c9be230 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -764,6 +764,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"앱이 패키지가 설치 가능한지 확인할 수 있도록 허용합니다."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"패키지 인증 연결"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"권한을 가진 프로그램이 패키지 인증을 요청할 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"직렬 포트에 액세스"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager API를 사용하여 권한을 가진 프로그램이 직렬 포트에 액세스할 수 있도록 합니다."</string>
<string name="save_password_message" msgid="767344687139195790">"브라우저에 이 비밀번호를 저장하시겠습니까?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"나중에"</string>
<string name="save_password_remember" msgid="6491879678996749466">"저장"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index a83b0640cd4e..22830ac6a146 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Leidžiama programai užduotis perkelti į priekinį planą ir į foną. Kenkėjiškos programos gali priverstinai persikelti į priekį be jūsų įsikišimo."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"sustabdyti vykdomas programas"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Leidžiama programai pašalinti užduotis ir panaikinti jų programas. Kenkėjiškos programos gali trikdyti kitų programų veikimą."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"nustatyti ekrano suderinamumo režimą"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Programai leidžiama valdyti kitų programų ekrano suderinamumo režimą. Kenkėjiškos programos gali kliudyti veikti kitoms programoms."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"įgalinti programos derinimą"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Leidžiama programai įjungti kitos programos derinimą. Kenkėjiškos programos gali tai naudoti, kad išjungtų kitas programas."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"keisti UI nustatymus"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Leidžiama programai patikrinti, ar paketą galima įdiegti."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"susaistyti su paketo tikrinimo programa"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Savininkui leidžiama teikti užklausas patikrinti paketą. Įprastoms programoms to neturėtų prireikti."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"pasiekti nuosekliuosius prievadus"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Leidžiama savininkui pasiekti nuosekliuosius prievadus naudojant „SerialManager“ API."</string>
<string name="save_password_message" msgid="767344687139195790">"Ar norite, kad naršyklė atsimintų šį slaptažodį?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Ne dabar"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Atsiminti"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 170653a59b97..f716cb99f65c 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Ļauj lietotnei pārvietot uzdevumus priekšplānā un fonā. Ļaunprātīgas lietotnes var tikt izvirzītas priekšplānā bez jūsu vadības."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"apturēt izmantoto lietotņu darbību"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Ļauj lietotnei noņemt uzdevumus un pārtraukt to lietotņu darbību. Ļaunprātīgas lietotnes var traucēt citu lietotņu darbību."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"Ekrāna saderības noteikšana"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Ļauj lietotnei kontrolēt citu lietotņu ekrāna saderības režīmu. Ļaunprātīgas lietojumprogrammas var mainīt citu lietojumprogrammu darbību."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"iespējot lietotnes atkļūdošanu"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Ļauj lietotnei ieslēgt citas lietotnes atkļūdošanu. Ļaunprātīgas lietotnes to var izmantot, lai pārtrauktu citu lietotņu darbību."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"mainīt lietotāja saskarnes iestatījumus"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Ļauj lietotnei verificēt, vai pakotne ir instalējama."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"saistīšana ar pakotnes verificētāju"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Ļauj īpašniekam sūtīt pakotņu verificētāju pieprasījumus. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"piekļuve seriālajiem portiem"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Ļauj īpašniekam piekļūt seriālajiem portiem, izmantojot SerialManager API."</string>
<string name="save_password_message" msgid="767344687139195790">"Vai vēlaties, lai pārlūkprogrammā tiktu saglabāta šī parole?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Ne tagad"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Atcerēties"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 498bd8394dd0..659a7ad9efdc 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -764,6 +764,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Membenarkan apl untuk mengesahkan bahawa pakej boleh dipasang."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"ikat kepada pengesah pakej"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Membenarkan pemegang membuat permintaan pengesah pakej. Tidak sekali-kali diperlukan untuk apl normal."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"akses port bersiri"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Membenarkan pemegang mengakses port bersiri menggunakan API SerialManager."</string>
<string name="save_password_message" msgid="767344687139195790">"Adakah anda mahu penyemak imbas mengingati kata laluan ini?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Bukan sekarang"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Ingat"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 084b281f6fde..b1b3cbef1cbb 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Lar appen flytte oppgaver til forgrunnen eller bakgrunnen. Ondsinnede apper kan tvinge seg frem til forgrunnen utenfor din kontroll."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"avslutte apper som kjører"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Lar appen fjerne oppgaver og avslutte apper. Ondsinnede apper kan forstyrre atferden til andre apper."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"angi skjermkompatibilitet"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Lar appen kontrollere modus for skjermkompatibilitet i andre apper. Skadelige apper kan ødelegge funksjoner i andre apper."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"aktivere feilsøking av app"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Lar appen slå av feilsøking for andre apper. Ondsinnede apper kan bruke dette til å avslutte andre apper."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"endre innstillingene for brukergrensesnitt"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Lar appen bekrefte om en pakke kan installeres."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bind til en pakkeverifikator"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Lar innehaveren sende forespørsler om pakkeverifikatorer. Skal aldri være nødvendig for normale apper."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"tilgang til serielle porter"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Gir innehaveren tilgang til serielle porter ved hjelp av SerialManager API."</string>
<string name="save_password_message" msgid="767344687139195790">"Ønsker du at nettleseren skal huske dette passordet?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Ikke nå"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Husk"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index bc236971dcf3..94094455845d 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Hiermee kan de app taken naar de voor- en achtergrond verplaatsen. Schadelijke apps kunnen zichzelf op de voorgrond plaatsen zonder dat u hier iets aan kunt doen."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"actieve apps stoppen"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Hiermee kan de app taken verwijderen en apps sluiten. Schadelijke apps kunnen het gedrag van andere apps verstoren."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"schermcompatibiliteit instellen"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Toestaan dat de app de schermcompatibiliteitsmodus van andere apps beheert. Schadelijke apps kunnen het gedrag van andere apps verstoren."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"foutopsporing in apps inschakelen"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Hiermee kan de app de foutopsporing voor een andere app inschakelen. Schadelijke apps kunnen dit gebruiken om andere apps af te sluiten."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"uw UI-instellingen wijzigen"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Hiermee kan de app controleren of een pakket kan worden geïnstalleerd."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"koppelen aan pakketcontroleprogramma"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Hiermee kan de houder verzoeken indienen voor pakketcontroles. Nooit vereist voor normale apps."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"toegang krijgen tot seriële poorten"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"De houder toestaan toegang tot seriële poorten te krijgen met de SerialManager API."</string>
<string name="save_password_message" msgid="767344687139195790">"Wilt u dat de browser dit wachtwoord onthoudt?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Niet nu"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Onthouden"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 565fa792ed01..8564dc793658 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Pozwala aplikacji na przenoszenie zadań między tłem i pierwszym planem. Złośliwe aplikacje mogą wymusić przeniesienie się na pierwszy plan bez Twojego udziału."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"zatrzymywanie uruchomionych aplikacji"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Umożliwia aplikacji usuwanie zadań i kończenie powiązanych z nimi aplikacji. Złośliwe aplikacje mogą zakłócić działanie innych aplikacji."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"ustaw zgodność ekranu"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Pozwala aplikacji na sterowanie trybem zgodności ekranu innych aplikacji. Złośliwe aplikacje mogą zmienić zachowanie innych aplikacji."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"włączenie debugowania aplikacji"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Pozwala aplikacji na włączenie debugowania innej aplikacji. Złośliwe aplikacje mogą to wykorzystać do kończenia pracy innych programów."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"zmienianie ustawień interfejsu użytkownika"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Pozwala aplikacji na zweryfikowanie, czy pakiet można zainstalować."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"powiązanie z weryfikatorem pakietów"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Pozwala na wysyłanie żądań weryfikacji pakietu. To uprawnienie nie powinno być potrzebne zwykłym aplikacjom."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"dostęp do portów szeregowych"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Umożliwia posiadaczowi dostęp do portów szeregowych przy użyciu interfejsu API narzędzia SerialManager."</string>
<string name="save_password_message" msgid="767344687139195790">"Czy chcesz, aby zapamiętać to hasło w przeglądarce?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Nie teraz"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Zapamiętaj"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 28b846390e25..a162aa086f3c 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permite à aplicação mover tarefas para primeiro e segundo plano. As aplicações maliciosas podem impor-se em primeiro plano sem o controlo do utilizador."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"parar aplicações em execução"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite que a aplicação remova tarefas e elimine as respetivas aplicações. As aplicações maliciosas podem perturbar o comportamento de outras aplicações."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"definir compatibilidade de ecrã"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Permite que a aplicação controle o modo de compatibilidade de ecrã de outras aplicações. As aplicações maliciosas poderão afetar o comportamento de outras aplicações."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"ativar depuração da aplicação"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permite que a aplicação ative a depuração para outra aplicação. As aplicações maliciosas podem utilizar isto para eliminar outras aplicações."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"alterar definições da IU"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permite que a aplicação verifique se um pacote é instalável."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"vincular a um verificador de pacotes"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite ao titular solicitar verificadores de pacotes. Nunca deverá ser necessário para aplicações normais."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"aceder a portas série"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite ao titular aceder a portas de série através da API SerialManager."</string>
<string name="save_password_message" msgid="767344687139195790">"Quer que o browser memorize esta palavra-passe?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Agora não"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Lembrar"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index cf6627e094e0..4915a2337bec 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -764,6 +764,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permite que o aplicativo verifique se um pacote pode ser instalado."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"vincular a um verificador de pacote"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite que o titular solicite verificadores de pacote. Nunca deve ser necessário para aplicativos normais."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"acessar portas seriais"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite que o detentor tenha acesso a portas seriais usando a API SerialManager."</string>
<string name="save_password_message" msgid="767344687139195790">"Deseja que o navegador lembre desta senha?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Agora não"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Lembrar"</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index a900840ad73e..57daee71770e 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -1151,6 +1151,10 @@
<skip />
<!-- no translation found for permdesc_bindPackageVerifier (3180741773233862126) -->
<skip />
+ <!-- no translation found for permlab_serialPort (546083327654631076) -->
+ <skip />
+ <!-- no translation found for permdesc_serialPort (2991639985224598193) -->
+ <skip />
<string name="save_password_message" msgid="767344687139195790">"Vulais Vus ch\'il navigatur memorisescha quest pled-clav?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Betg ussa"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Memorisar"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 44919ac1aaab..fe3687fbfd79 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Permite aplicaţiei să mute activităţile în prim-plan şi în fundal. Aplicaţiile rău intenţionate pot să apară forţat în prim-plan, fără ca dvs. să puteţi controla acest lucru."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"oprire aplicaţii care rulează"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Permite aplicaţiei să elimine sarcini şi să închidă aplicaţiile corespunzătoare acestora. Aplicaţiile rău intenţionate pot perturba comportamentul altor aplicaţii."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"setaţi compatibilitatea ecranului"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Permite aplicaţiei să controleze modul de compatibilitate a ecranului pentru alte aplicaţii. Aplicaţiile rău intenţionate pot afecta comportamentul altor aplicaţii."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"activare depanare aplicaţie"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Permite aplicaţiei să activeze depanarea pentru o altă aplicaţie. Aplicaţiile rău intenţionate pot să utilizeze această permisiune pentru a închide alte aplicaţii."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"modificare setări UI"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Permite aplicaţiei să verifice dacă un pachet poate fi instalat."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"conectare la un verificator de pachete"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite proprietarului să efectueze solicitări pentru verificatori de pachete. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"acces la porturi seriale"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite posesorului accesul la porturile serial utilizând API-ul SerialManager."</string>
<string name="save_password_message" msgid="767344687139195790">"Doriţi ca browserul să reţină această parolă?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Nu acum"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Reţineţi"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index ace79d36489e..55468a07c6b2 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Приложение сможет перемещать задачи в режим активного или фонового выполнения. Вредоносные программы смогут переводить себя в активный режим без вашего ведома."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"остановка запущенных приложений"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Приложение сможет удалять задачи и собственные программы. Вредоносное ПО при этом сможет нарушать работу других приложений."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"Установка режима совместимости"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Приложение сможет управлять режимом совместимости экрана других приложений. Вредоносное ПО может привести к сбоям в работе других программ."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"включение отладки приложений"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Приложение сможет включать отладку для другой программы. Вредоносное ПО сможет таким образом останавливать работу других приложений."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"изменять настройки пользовательского интерфейса"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Приложение сможет проверять возможность установки пакетов."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"связываться с верификатором пакетов"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Приложение сможет запрашивать проверку пакетов. Это разрешение не используется обычными приложениями."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"доступ к последовательным портам"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Открыть владельцу доступ к последовательным портам с помощью SerialManager API."</string>
<string name="save_password_message" msgid="767344687139195790">"Вы хотите, чтобы браузер запомнил этот пароль?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Не сейчас"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Запомнить"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 8cb518cd9bc6..69bc4b84a5c9 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -764,6 +764,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Umožňuje aplikácii overiť, či je možné balík nainštalovať."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"naviazať na overovateľa balíka"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Umožňuje držiteľovi podávať žiadosti o overenie balíkov. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"prístup k sériovým portom"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Držiteľa oprávňuje na prístup k sériovým portom pomocou rozhrania API SerialManager."</string>
<string name="save_password_message" msgid="767344687139195790">"Chcete, aby si prehliadač zapamätal toto heslo?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Teraz nie"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Zapamätať"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index e7a6c077ecb9..dfedb9af8372 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Programu omogoča premikanje opravil v ospredje in ozadje. Zlonamerni programi se lahko brez vašega nadzora vsilijo v ospredje."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"ustavitev programov, ki se izvajajo"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Programu omogoča odstranjevanje opravil in zapiranje njihovih programov. Zlonamerni programi lahko motijo delovanje drugih programov."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"nastavitev združljivosti zaslona"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Programu omogoča nadzor združljivostnega načina zaslona drugih programov. Zlonamerni programi lahko prekinejo delovanje drugih programov."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"omogočanje iskanja in odpravljanja napak v programu"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Programu omogoča vklop funkcije za odpravljanje napak za drug program. Zlonamerni programi lahko to uporabijo za zapiranje drugih programov."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"spreminjanje nastavitev UV"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Programu omogoča, da preveri, ali je paket mogoče namestiti."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"poveži s preverjanjem paketov"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Imetniku omogoča zahtevanje preverjanja paketov. Tega nikoli ni treba uporabiti za navadne programe."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"dostop do serijskih vrat"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Imetniku omogoča, da z API-jem za SerialManager dostopa do serijskih vrat."</string>
<string name="save_password_message" msgid="767344687139195790">"Ali želite, da si brskalnik zapomni to geslo?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Ne zdaj"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Zapomni si"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 2374f59609c8..2a2104fc1631 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Дозвољава апликацији да премешта задатке у први план и у позадину. Злонамерне апликације могу на тај начин да принудно пређу у први план без ваше контроле."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"заустављање покренутих апликација"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Дозвољава апликацији да уклања задатке и уништава њихове апликације. Злонамерне апликације могу да поремете понашање других апликација."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"подешавање компатибилности екрана"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Дозвољава апликацији да контролише режим компатибилности екрана других апликација. Злонамерне апликације могу да угрозе понашање других апликација."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"омогућавање отклањања грешака у апликацији"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Дозвољава апликацији да укључи уклањање грешака за другу апликацију. Злонамерне апликације могу то да искористе за онемогућавање других апликација."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"промена подешавања корисничког интерфејса"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Дозвољава апликацији да верификује да ли је пакет могуће инсталирати."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"обавезивање на верификатор пакета"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Омогућава да власник упућује захтеве верификаторима пакета. Уобичајене апликације никада не би требало да је користе."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"приступ серијским портовима"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Омогућава власнику да приступи серијским портовима помоћу SerialManager API-ја."</string>
<string name="save_password_message" msgid="767344687139195790">"Желите ли да прегледач запамти ову лозинку?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Не сада"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Запамти"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 26e1ea52eedf..0067a12f4b09 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Tillåter att appen flyttar uppgifter till förgrunden eller bakgrunden. Skadliga appar kan tvinga sig till förgrunden utan att du kan styra det."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"avsluta appar som körs"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Tillåter att appen tar bort uppgifter och avslutar appar. Skadliga appar kan störa funktionen i andra appar."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"ange skärmkompatibilitet"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Tillåter att appen styr skärmkompatibilitetsläget i andra appar. Skadliga appar kan störa andra appars funktion."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"aktivera felsökning av appar"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Tillåter att appen aktiverar felsökning för en annan app. Skadliga appar kan använda detta för att avsluta andra appar."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"ändra dina gränssnittsinställningar"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Tillåter att appen kontrollerar om ett paket går att installera."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"binda till en paketverifierare"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Tillåter att innehavaren skickar förfrågningar till paketverifierare. Det ska inte behövas för vanliga appar."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"åtkomst till serieportar"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Innebär att innehavaren får åtkomst till serieportar med programmeringsgränssnittet för SerialManager."</string>
<string name="save_password_message" msgid="767344687139195790">"Vill du att webbläsaren ska komma ihåg lösenordet?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Inte nu"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Kom ihåg"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 22ce6609ad37..369853c34966 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Inaruhusu programu kusongesha kazi kwenye mandhari-mbele na mandhari-nyuma. Programu hasidi zinaweza kujilazimisha mbele bila udhibiti wako."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"Komesha programu zinazoendeshwa"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Huruhusu programu kuondoa majukumu na kuua programu zao. Programu hasidi zinaweza kutatiza tabia ya programu zingine."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"weka utangamano wa skrini"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Huruhusu programu kudhibiti hali ya utangamano wa skrini ya programu zingine. Programu hasidi zinaweza kuvunja mwenendo wa programu zingine."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"wezesha utatuaji wa programu"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Huruhusu programu kuwasha kueua cha programu nyingine. Programu hasidi huenda zikatumia hii ili kuua programu nyingine."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"badilisha mipangilio yako ya onyesho"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Inaruhusu programu kuthibitisha kuwa furushi linaweza kusakinishwa."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"Funga kwa kithibitishaji cha furushi"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Inaruhusu mmiliki kutuma maombi ya vibainishi furushi. Kamwe hazitahitajika kwa programu za kawaida."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"kituo tambulishi cha ufikivu"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Inaruhusu mmiliki kufikia vituo tambulishi kwa kutumia KisimamiziTambulishi cha API."</string>
<string name="save_password_message" msgid="767344687139195790">"Unataka kuvinjari ili ukumbuke nenosiri hili?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Si Sasa"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Kumbuka"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 0ff883d8a875..debe568bc8c3 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"อนุญาตให้แอปพลิเคชันย้ายงานไปยังส่วนหน้าและพื้นหลัง แอปพลิเคชันที่เป็นอันตรายอาจบังคับตัวเองให้ไปที่ส่วนหน้าโดยไม่มีการควบคุมจากคุณ"</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"หยุดแอปพลิเคชันที่ทำงานอยู่"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"อนุญาตให้แอปพลิเคชันลบงานออกและยุติแอปพลิเคชันต่างๆ ของงานนั้น แอปพลิเคชันที่เป็นอันตรายอาจทำให้แอปพลิเคชันอื่นๆ ทำงานได้ไม่ถูกต้อง"</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"ตั้งค่าความเข้ากันได้ของหน้าจอ"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"อนุญาตให้แอปพลิเคชันควบคุมโหมดความเข้ากันได้ของหน้าจอของแอปพลิเคชันอื่น แอปพลิเคชันที่เป็นอันตรายอาจทำให้แอปพลิเคชันอื่นทำงานผิดพลาด"</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"เปิดใช้งานการแก้ไขบกพร่องของแอปพลิเคชัน"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"อนุญาตให้แอปพลิเคชันเปิดการแก้ไขข้อบกพร่องสำหรับแอปพลิเคชันอื่น แอปพลิเคชันที่เป็นอันตรายอาจใช้การอนุญาตนี้ยุติการทำงานของแอปพลิเคชันอื่นๆ ได้"</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"เปลี่ยนการตั้งค่า UI ของคุณ"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"อนุญาตให้แอปพลิเคชันยืนยันว่าแพคเกจสามารถติดตั้งได้หรือไม่"</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"เชื่อมโยงกับการยืนยันแพคเกจ"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"อนุญาตให้ผู้ใช้ส่งคำขอให้มีการยืนยันแพคเกจ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"เข้าถึงพอร์ตอนุกรม"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"อนุญาตให้ผู้ถือสามารถเข้าถึงพอร์ตอนุกรมโดยใช้ SerialManager API"</string>
<string name="save_password_message" msgid="767344687139195790">"คุณต้องการให้เบราว์เซอร์จำรหัสผ่านนี้หรือไม่"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"ยังไม่ใช้งานขณะนี้"</string>
<string name="save_password_remember" msgid="6491879678996749466">"จำไว้"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 889b3a956c8a..e74e309c3b1e 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Pinapayagan ang app na ilipat ang mga gawain sa foreground at background. Maaaring puwersahin ng nakakahamak na apps ang mga sarili nito sa harapan nang wala ang iyong pagkontrol."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"ihinto ang pagpapatakbo ng apps"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Pinapayagan ang app na mag-alis ng mga gawain at i-off ang apps nito. Maaaring maantala ng nakakahamak na apps ang pagkilos ng iba pang apps."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"itakda ang pagkakatugma ng screen"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Pinapayagan ang app na kontrolin ang mode ng pagkakatugma ng screen ng iba pang mga application. Maaaring sirain ng mga nakakahamak na application ang pag-uugali ng iba pang mga application."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"paganahin ang pag-debug ng app"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Pinapayagan ang app na i-on ang pag-debug para sa isa pang app. Maaari itong gamitin ng nakakahamak na apps upang i-off ang iba pang apps."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"baguhin ang iyong mga setting ng UI"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Pinapayagan ang app na i-verify kung ang isang package ay nai-install."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"sumailalim sa taga-verify ng package"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Pinapayagan ang may-ari na gumawa ng mga kahilingan ng mga taga-verify ng package. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"mag-access sa mga serial port"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Binibigyang-daan ang may-ari na mag-access ng mga serial port gamit ang SerialManager API."</string>
<string name="save_password_message" msgid="767344687139195790">"Gusto mo bang tandaan ng browser ang password na ito?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Hindi ngayon"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Tandaan"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 07e4ec9738be..20d3e15cc40d 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -764,6 +764,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Uygulamaya, bir paketin yüklenebilir olduğunu doğrulama izni verir."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"paket doğrulayıcıya bağlan"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Cihazın sahibine, paket doğrulayıcıları için istek yapma izni verir. Normal uygulamalar için gerekli olmaz."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"seri bağlantı noktalarına eriş"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"İzin sahibinin, SerialManager API\'sını kullanarak seri bağlantı noktalarına erişmesine olanak sağlar."</string>
<string name="save_password_message" msgid="767344687139195790">"Tarayıcının bu şifreyi anımsamasını istiyor musunuz?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Şimdi değil"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Anımsa"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index ac2ea3caa8de..9d049cf05cf1 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Дозволяє програмі переміщувати завдання в активні чи фонові вікна. Шкідливі програми можуть примусово ставати активними без вашого відома."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"зупиняти запущені програми"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Дозволяє програмі видаляти завдання та примусово припиняти роботу відповідних програм. Шкідливі програми можуть переривати роботу інших програм."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"установити сумісність екрана"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Дозволяє програмі контролювати режим сумісності екрана інших програм. Шкідливі програми можуть переривати роботу інших програм."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"вмикати налагодження програми"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Дозволяє програмі вмикати налагодження для іншої програми. Шкідливі програми можуть використовувати це для примусового припинення роботи інших програм."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"змін. налашт. інтерф. кор."</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Дозволяє програмі перевіряти можливість встановлення пакета."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"прив’язуватися до програми перевірки пакетів"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Дозволяє власникові робити запити на програми перевірки пакетів. Ніколи не застосовується для звичайних програм."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"отримувати доступ до послідовних портів"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Дозволяє власнику отримувати доступ до послідовних портів за допомогою API SerialManager."</string>
<string name="save_password_message" msgid="767344687139195790">"Хочете, щоб переглядач запам\'ятав цей пароль?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Не зараз"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Запам\'ятати"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 9f2fe0c37e86..81666068ae8e 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -215,10 +215,8 @@
<string name="permdesc_reorderTasks" msgid="4175137612205663399">"Cho phép ứng dụng di chuyển công việc sang nền trước và nền sau. Ứng dụng độc hại có thể tự hiển thị ở nền trước mà không chịu sự kiểm soát của bạn."</string>
<string name="permlab_removeTasks" msgid="6821513401870377403">"dừng các ứng dụng đang chạy"</string>
<string name="permdesc_removeTasks" msgid="1394714352062635493">"Cho phép ứng dụng xóa công việc và loại bỏ các ứng dụng của chúng. Ứng dụng độc hại có thể làm gián đoạn hoạt động của các ứng dụng khác."</string>
- <!-- no translation found for permlab_setScreenCompatibility (6975387118861842061) -->
- <skip />
- <!-- no translation found for permdesc_setScreenCompatibility (692043618693917374) -->
- <skip />
+ <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"đặt độ tương thích màn hình"</string>
+ <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Cho phép ứng dụng kiểm soát chế độ tương thích màn hình của ứng dụng khác. Các ứng dụng độc hại có thể phá vỡ hoạt động của các ứng dụng khác."</string>
<string name="permlab_setDebugApp" msgid="3022107198686584052">"bật gỡ lỗi ứng dụng"</string>
<string name="permdesc_setDebugApp" msgid="4474512416299013256">"Cho phép ứng dụng bật gỡ lỗi cho một ứng dụng khác. Ứng dụng độc hại có thể sử dụng quyền này để loại bỏ những ứng dụng khác."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"thay đổi cài đặt giao diện người dùng của bạn"</string>
@@ -764,6 +762,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Cho phép ứng dụng xác minh gói có thể cài đặt."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"liên kết với trình xác minh gói"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Cho phép chủ sở hữu yêu cầu trình xác minh gói. Không cần thiết cho các ứng dụng thông thường."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"truy cập cổng nối tiếp"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Cho phép chủ sở hữu truy cập cổng nối tiếp sử dụng API SerialManager."</string>
<string name="save_password_message" msgid="767344687139195790">"Bạn có muốn trình duyệt nhớ mật khẩu này không?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Không phải bây giờ"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Nhớ"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 89f5ad001b6d..1065183b52b3 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -764,6 +764,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"允许应用程序验证程序包是否可以安装。"</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"绑定到软件包验证程序"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"允许用户请求使用程序包验证程序。普通应用程序绝不需要此权限。"</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"访问串行端口"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"允许持有人使用 SerialManager API 访问串行端口。"</string>
<string name="save_password_message" msgid="767344687139195790">"是否希望浏览器记住此密码?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"暂不保存"</string>
<string name="save_password_remember" msgid="6491879678996749466">"记住"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index ededae8fa17e..659c2de62049 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -764,6 +764,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"允許應用程式驗證是否可安裝特定套件。"</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"繫結至套件驗證程序"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"允許應用程式要求驗證套件 (一般應用程式不需使用)。"</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"存取序列埠"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"允許應用程式使用 SerialManager API 存取序列埠。"</string>
<string name="save_password_message" msgid="767344687139195790">"是否記住此密碼?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"現在不要"</string>
<string name="save_password_remember" msgid="6491879678996749466">"記住"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 3ee95bef5ced..84f4319b57e9 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -764,6 +764,8 @@
<string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Ivumela ukuthi isisetshenziswa siqinisekise ukuthi ngabe iphakheji iyafakeka."</string>
<string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bopha okokuqinisekisa iphakheji"</string>
<string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Ivumela umnikazi ukuthi enze izicelo zezinsiza eziqinisekisa iphakheji. Akumele kudingeke ekusetshenzisweni okujwayelekile."</string>
+ <string name="permlab_serialPort" msgid="546083327654631076">"finyelela kuma- serial port"</string>
+ <string name="permdesc_serialPort" msgid="2991639985224598193">"Ivumela umnikai ukuthi athole inombolo ye-serial ukue angene kwiindawo ze-serial esebenzisa i-SerialManager API."</string>
<string name="save_password_message" msgid="767344687139195790">"Ingabe ufuna ukuba isiphequluli sikhumbule lephasiwedi?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Hha yi manje"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Khumbula"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index d2207af1c1b3..3a7225ed1daf 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -65,6 +65,21 @@
master volume stream and nothing else . -->
<bool name="config_useMasterVolume">false</bool>
+ <!-- Array of integer pairs controlling the rate at which the master volume changes
+ in response to volume up and down key events.
+ The first integer of each pair is compared against the current master volume
+ (in range 0 to 100).
+ The last pair with first integer <= the current volume is chosen,
+ and the second integer of the pair indicates the amount to increase the master volume
+ when volume up is pressed. -->
+ <integer-array name="config_masterVolumeRamp">
+ <item>0</item> <item>5</item> <!-- default: always increase volume by 5% -->
+ </integer-array>
+
+ <!-- Flag indicating whether the AUDIO_BECOMING_NOISY notification should
+ be sent during an change to the audio output device. -->
+ <bool name="config_sendAudioBecomingNoisy">true</bool>
+
<!-- The duration (in milliseconds) of a short animation. -->
<integer name="config_shortAnimTime">200</integer>
@@ -773,4 +788,10 @@
movement threshold where scrolling should begin. -->
<dimen name="config_viewConfigurationTouchSlop">8dp</dimen>
+ <!-- Array of OEM specific USB mode override config.
+ OEM can override a certain USB mode depending on ro.bootmode.
+ Specify an array of below items to set override rule.
+ [bootmode]:[original USB mode]:[USB mode used]-->
+ <integer-array translatable="false" name="config_oemUsbModeOverride">
+ </integer-array>
</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 381ec7f616f2..e84cb5c2ee6b 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -236,6 +236,7 @@
<java-symbol type="bool" name="split_action_bar_is_narrow" />
<java-symbol type="bool" name="config_useMasterVolume" />
<java-symbol type="bool" name="config_enableWallpaperService" />
+ <java-symbol type="bool" name="config_sendAudioBecomingNoisy" />
<java-symbol type="integer" name="config_cursorWindowSize" />
<java-symbol type="integer" name="config_longPressOnPowerBehavior" />
@@ -861,6 +862,7 @@
<java-symbol type="array" name="preloaded_drawables" />
<java-symbol type="array" name="special_locale_codes" />
<java-symbol type="array" name="special_locale_names" />
+ <java-symbol type="array" name="config_masterVolumeRamp" />
<java-symbol type="drawable" name="default_wallpaper" />
<java-symbol type="drawable" name="ic_suggestions_add" />
@@ -1292,6 +1294,7 @@
<java-symbol type="array" name="config_usbHostBlacklist" />
<java-symbol type="array" name="config_serialPorts" />
<java-symbol type="array" name="radioAttributes" />
+ <java-symbol type="array" name="config_oemUsbModeOverride" />
<java-symbol type="bool" name="config_animateScreenLights" />
<java-symbol type="bool" name="config_automatic_brightness_available" />
<java-symbol type="bool" name="config_sf_limitedAlpha" />
diff --git a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
index a781472a9af7..76b702ecc87b 100644
--- a/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
+++ b/core/tests/bandwidthtests/src/com/android/bandwidthtest/BandwidthTest.java
@@ -90,6 +90,7 @@ public class BandwidthTest extends InstrumentationTestCase {
*/
@LargeTest
public void testWifiDownload() throws Exception {
+ mConnectionUtil.wifiTestInit();
assertTrue("Could not connect to wifi!", setDeviceWifiAndAirplaneMode(mSsid));
downloadFile();
}
@@ -143,6 +144,7 @@ public class BandwidthTest extends InstrumentationTestCase {
*/
@LargeTest
public void testWifiUpload() throws Exception {
+ mConnectionUtil.wifiTestInit();
assertTrue(setDeviceWifiAndAirplaneMode(mSsid));
uploadFile();
}
@@ -197,6 +199,7 @@ public class BandwidthTest extends InstrumentationTestCase {
*/
@LargeTest
public void testWifiDownloadWithDownloadManager() throws Exception {
+ mConnectionUtil.wifiTestInit();
assertTrue(setDeviceWifiAndAirplaneMode(mSsid));
downloadFileUsingDownloadManager();
}
@@ -286,6 +289,8 @@ public class BandwidthTest extends InstrumentationTestCase {
* @return true if we successfully connect to mobile data.
*/
public boolean hasMobileData() {
+ assertTrue(mConnectionUtil.waitForNetworkState(ConnectivityManager.TYPE_MOBILE,
+ State.CONNECTED, ConnectionUtil.LONG_TIMEOUT));
assertTrue("Not connected to mobile", mConnectionUtil.isConnectedToMobile());
assertFalse("Still connected to wifi.", mConnectionUtil.isConnectedToWifi());
return mConnectionUtil.hasData();
diff --git a/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java b/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
index dfcbba950b99..7499f68f87f6 100644
--- a/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
+++ b/core/tests/bandwidthtests/src/com/android/bandwidthtest/util/ConnectionUtil.java
@@ -57,7 +57,7 @@ public class ConnectionUtil {
private static final int WAIT_FOR_SCAN_RESULT = 10 * 1000; // 10 seconds
private static final int WIFI_SCAN_TIMEOUT = 50 * 1000;
public static final int SHORT_TIMEOUT = 5 * 1000;
- public static final int LONG_TIMEOUT = 10 * 1000;
+ public static final int LONG_TIMEOUT = 120 * 1000; // 2 minutes
private ConnectivityReceiver mConnectivityReceiver = null;
private WifiReceiver mWifiReceiver = null;
private DownloadReceiver mDownloadReceiver = null;
@@ -118,8 +118,14 @@ public class ConnectionUtil {
initializeNetworkStates();
- mWifiManager.setWifiEnabled(true);
+ }
+
+ /**
+ * Additional initialization needed for wifi related tests.
+ */
+ public void wifiTestInit() {
+ mWifiManager.setWifiEnabled(true);
Log.v(LOG_TAG, "Clear Wifi before we start the test.");
sleep(SHORT_TIMEOUT);
removeConfiguredNetworksAndDisableWifi();
@@ -525,7 +531,7 @@ public class ConnectionUtil {
/**
* Connect to Wi-Fi with the given configuration.
* @param config
- * @return true if we ar connected to a given
+ * @return true if we are connected to a given AP.
*/
public boolean connectToWifiWithConfiguration(WifiConfiguration config) {
// The SSID in the configuration is a pure string, need to convert it to a quoted string.
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index 02d2f3d79217..ef38a60d14d9 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -51,6 +51,11 @@ ALL_MODULES.$(LOCAL_MODULE).INSTALLED := \
$(ALL_MODULES.$(LOCAL_MODULE).INSTALLED) $(font_symlink)
################################
+# On space-constrained devices, we include a subset of fonts:
+ifeq ($(SMALLER_FONT_FOOTPRINT),true)
+droidsans_fallback_src := DroidSansFallback.ttf
+extra_droidsans_fonts := DroidSans.ttf DroidSans-Bold.ttf
+else
include $(CLEAR_VARS)
LOCAL_MODULE := DroidSansEthiopic-Regular.ttf
LOCAL_SRC_FILES := $(LOCAL_MODULE)
@@ -59,15 +64,11 @@ LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts
include $(BUILD_PREBUILT)
-################################
-ifeq ($(SMALLER_FONT_FOOTPRINT),true)
-droidsans_fallback_src := DroidSansFallback.ttf
-extra_droidsans_fonts := DroidSans.ttf DroidSans-Bold.ttf
-else
droidsans_fallback_src := DroidSansFallbackFull.ttf
extra_droidsans_fonts := DroidSans.ttf DroidSans-Bold.ttf DroidSansEthiopic-Regular.ttf
endif # SMALLER_FONT_FOOTPRINT
+################################
include $(CLEAR_VARS)
LOCAL_MODULE := DroidSansFallback.ttf
LOCAL_SRC_FILES := $(droidsans_fallback_src)
@@ -81,3 +82,46 @@ font_symlink_src :=
font_symlink :=
droidsans_fallback_src :=
extra_droidsans_fonts :=
+
+################################
+# Build the rest font files as prebuilt.
+
+# $(1): The source file name in LOCAL_PATH.
+# It also serves as the module name and the dest file name.
+define build-one-font-module
+$(eval include $(CLEAR_VARS))\
+$(eval LOCAL_MODULE := $(1))\
+$(eval LOCAL_SRC_FILES := $(1))\
+$(eval LOCAL_MODULE_CLASS := ETC)\
+$(eval LOCAL_MODULE_TAGS := optional)\
+$(eval LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts)\
+$(eval include $(BUILD_PREBUILT))
+endef
+
+font_src_files := \
+ Roboto-Regular.ttf \
+ Roboto-Bold.ttf \
+ Roboto-Italic.ttf \
+ Roboto-BoldItalic.ttf \
+ DroidSansArabic.ttf \
+ DroidNaskh-Regular.ttf \
+ DroidSansHebrew-Regular.ttf \
+ DroidSansHebrew-Bold.ttf \
+ DroidSansThai.ttf \
+ DroidSerif-Regular.ttf \
+ DroidSerif-Bold.ttf \
+ DroidSerif-Italic.ttf \
+ DroidSerif-BoldItalic.ttf \
+ DroidSansMono.ttf \
+ DroidSansArmenian.ttf \
+ DroidSansGeorgian.ttf \
+ AndroidEmoji.ttf \
+ Clockopia.ttf \
+ AndroidClock.ttf \
+ AndroidClock_Highlight.ttf \
+ AndroidClock_Solid.ttf \
+
+$(foreach f, $(font_src_files), $(call build-one-font-module, $(f)))
+
+build-one-font-module :=
+font_src_files :=
diff --git a/data/fonts/fonts.mk b/data/fonts/fonts.mk
index 6a9ed539bfc9..458f85b7d0a7 100644
--- a/data/fonts/fonts.mk
+++ b/data/fonts/fonts.mk
@@ -14,34 +14,30 @@
# Warning: this is actually a product definition, to be inherited from
-# On space-constrained devices, we include a subset of fonts:
-# First, core/required fonts
PRODUCT_COPY_FILES := \
- frameworks/base/data/fonts/Roboto-Regular.ttf:system/fonts/Roboto-Regular.ttf \
- frameworks/base/data/fonts/Roboto-Bold.ttf:system/fonts/Roboto-Bold.ttf \
- frameworks/base/data/fonts/Roboto-Italic.ttf:system/fonts/Roboto-Italic.ttf \
- frameworks/base/data/fonts/Roboto-BoldItalic.ttf:system/fonts/Roboto-BoldItalic.ttf \
- frameworks/base/data/fonts/DroidSansArabic.ttf:system/fonts/DroidSansArabic.ttf \
- frameworks/base/data/fonts/DroidNaskh-Regular.ttf:system/fonts/DroidNaskh-Regular.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 \
- frameworks/base/data/fonts/DroidSerif-Italic.ttf:system/fonts/DroidSerif-Italic.ttf \
- frameworks/base/data/fonts/DroidSerif-BoldItalic.ttf:system/fonts/DroidSerif-BoldItalic.ttf \
- frameworks/base/data/fonts/DroidSansMono.ttf:system/fonts/DroidSansMono.ttf \
- frameworks/base/data/fonts/DroidSansArmenian.ttf:system/fonts/DroidSansArmenian.ttf \
- frameworks/base/data/fonts/DroidSansGeorgian.ttf:system/fonts/DroidSansGeorgian.ttf \
- frameworks/base/data/fonts/AndroidEmoji.ttf:system/fonts/AndroidEmoji.ttf \
- frameworks/base/data/fonts/Clockopia.ttf:system/fonts/Clockopia.ttf \
- frameworks/base/data/fonts/AndroidClock.ttf:system/fonts/AndroidClock.ttf \
- frameworks/base/data/fonts/AndroidClock_Highlight.ttf:system/fonts/AndroidClock_Highlight.ttf \
- frameworks/base/data/fonts/AndroidClock_Solid.ttf:system/fonts/AndroidClock_Solid.ttf \
frameworks/base/data/fonts/system_fonts.xml:system/etc/system_fonts.xml \
frameworks/base/data/fonts/fallback_fonts.xml:system/etc/fallback_fonts.xml
-# Next, include additional fonts, depending on how much space we have.
-# Details see module definitions in Android.mk.
PRODUCT_PACKAGES := \
- DroidSansFallback.ttf
+ DroidSansFallback.ttf \
+ Roboto-Regular.ttf \
+ Roboto-Bold.ttf \
+ Roboto-Italic.ttf \
+ Roboto-BoldItalic.ttf \
+ DroidSansArabic.ttf \
+ DroidNaskh-Regular.ttf \
+ DroidSansHebrew-Regular.ttf \
+ DroidSansHebrew-Bold.ttf \
+ DroidSansThai.ttf \
+ DroidSerif-Regular.ttf \
+ DroidSerif-Bold.ttf \
+ DroidSerif-Italic.ttf \
+ DroidSerif-BoldItalic.ttf \
+ DroidSansMono.ttf \
+ DroidSansArmenian.ttf \
+ DroidSansGeorgian.ttf \
+ AndroidEmoji.ttf \
+ Clockopia.ttf \
+ AndroidClock.ttf \
+ AndroidClock_Highlight.ttf \
+ AndroidClock_Solid.ttf \
diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java
index 509b9726e326..88ee3626027c 100644
--- a/graphics/java/android/renderscript/Allocation.java
+++ b/graphics/java/android/renderscript/Allocation.java
@@ -921,7 +921,31 @@ public class Allocation extends BaseObj {
if (type.getID() == 0) {
throw new RSInvalidStateException("Bad Type");
}
- int id = rs.nAllocationCreateTyped(type.getID(), mips.mID, usage);
+ int id = rs.nAllocationCreateTyped(type.getID(), mips.mID, usage, 0);
+ if (id == 0) {
+ throw new RSRuntimeException("Allocation creation failed.");
+ }
+ return new Allocation(id, rs, type, usage);
+ }
+
+ /**
+ * @hide
+ * This API is hidden and only intended to be used for
+ * transitional purposes.
+ *
+ * @param type renderscript type describing data layout
+ * @param mips specifies desired mipmap behaviour for the
+ * allocation
+ * @param usage bit field specifying how the allocation is
+ * utilized
+ */
+ static public Allocation createTyped(RenderScript rs, Type type, MipmapControl mips,
+ int usage, int pointer) {
+ rs.validate();
+ if (type.getID() == 0) {
+ throw new RSInvalidStateException("Bad Type");
+ }
+ int id = rs.nAllocationCreateTyped(type.getID(), mips.mID, usage, pointer);
if (id == 0) {
throw new RSRuntimeException("Allocation creation failed.");
}
@@ -976,7 +1000,7 @@ public class Allocation extends BaseObj {
b.setX(count);
Type t = b.create();
- int id = rs.nAllocationCreateTyped(t.getID(), MipmapControl.MIPMAP_NONE.mID, usage);
+ int id = rs.nAllocationCreateTyped(t.getID(), MipmapControl.MIPMAP_NONE.mID, usage, 0);
if (id == 0) {
throw new RSRuntimeException("Allocation creation failed.");
}
diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java
index 22ef7bb08f47..f6a02817a573 100644
--- a/graphics/java/android/renderscript/Element.java
+++ b/graphics/java/android/renderscript/Element.java
@@ -54,26 +54,59 @@ public class Element extends BaseObj {
int[] mArraySizes;
int[] mOffsetInBytes;
+ int[] mVisibleElementMap;
+
DataType mType;
DataKind mKind;
boolean mNormalized;
int mVectorSize;
+ private void updateVisibleSubElements() {
+ if (mElements == null) {
+ return;
+ }
+
+ int noPaddingFieldCount = 0;
+ int fieldCount = mElementNames.length;
+ // Find out how many elements are not padding
+ for (int ct = 0; ct < fieldCount; ct ++) {
+ if (mElementNames[ct].charAt(0) != '#') {
+ noPaddingFieldCount ++;
+ }
+ }
+ mVisibleElementMap = new int[noPaddingFieldCount];
+
+ // Make a map that points us at non-padding elements
+ for (int ct = 0, ctNoPadding = 0; ct < fieldCount; ct ++) {
+ if (mElementNames[ct].charAt(0) != '#') {
+ mVisibleElementMap[ctNoPadding ++] = ct;
+ }
+ }
+ }
+
/**
* @hide
* @return element size in bytes
*/
public int getSizeBytes() {return mSize;}
+ /**
+ * @hide
+ * @return element vector size
+ */
+ public int getVectorSize() {return mVectorSize;}
+
/**
* DataType represents the basic type information for a basic element. The
- * naming convention follows. For numeric types its FLOAT, SIGNED, UNSIGNED
- * followed by the _BITS where BITS is the size of the data. BOOLEAN is a
- * true / false (1,0) represented in an 8 bit container. The UNSIGNED
- * variants with multiple bit definitions are for packed graphical data
- * formats and represents vectors with per vector member sizes which are
- * treated as a single unit for packing and alignment purposes.
+ * naming convention follows. For numeric types it is FLOAT,
+ * SIGNED, or UNSIGNED followed by the _BITS where BITS is the
+ * size of the data. BOOLEAN is a true / false (1,0)
+ * represented in an 8 bit container. The UNSIGNED variants
+ * with multiple bit definitions are for packed graphical data
+ * formats and represent vectors with per vector member sizes
+ * which are treated as a single unit for packing and alignment
+ * purposes.
*
* MATRIX the three matrix types contain FLOAT_32 elements and are treated
* as 32 bits for alignment purposes.
@@ -81,6 +114,11 @@ public class Element extends BaseObj {
* RS_* objects. 32 bit opaque handles.
*/
public enum DataType {
+ /**
+ * @hide
+ * new enum
+ */
+ NONE (0, 0),
//FLOAT_16 (1, 2),
FLOAT_32 (2, 4),
FLOAT_64 (3, 8),
@@ -167,10 +205,10 @@ public class Element extends BaseObj {
* @return number of sub-elements in this element
*/
public int getSubElementCount() {
- if (mElements == null) {
+ if (mVisibleElementMap == null) {
return 0;
}
- return mElements.length;
+ return mVisibleElementMap.length;
}
/**
@@ -179,13 +217,13 @@ public class Element extends BaseObj {
* @return sub-element in this element at given index
*/
public Element getSubElement(int index) {
- if (mElements == null) {
+ if (mVisibleElementMap == null) {
throw new RSIllegalArgumentException("Element contains no sub-elements");
}
- if (index < 0 || index >= mElements.length) {
+ if (index < 0 || index >= mVisibleElementMap.length) {
throw new RSIllegalArgumentException("Illegal sub-element index");
}
- return mElements[index];
+ return mElements[mVisibleElementMap[index]];
}
/**
@@ -194,13 +232,13 @@ public class Element extends BaseObj {
* @return sub-element in this element at given index
*/
public String getSubElementName(int index) {
- if (mElements == null) {
+ if (mVisibleElementMap == null) {
throw new RSIllegalArgumentException("Element contains no sub-elements");
}
- if (index < 0 || index >= mElements.length) {
+ if (index < 0 || index >= mVisibleElementMap.length) {
throw new RSIllegalArgumentException("Illegal sub-element index");
}
- return mElementNames[index];
+ return mElementNames[mVisibleElementMap[index]];
}
/**
@@ -209,13 +247,13 @@ public class Element extends BaseObj {
* @return array size of sub-element in this element at given index
*/
public int getSubElementArraySize(int index) {
- if (mElements == null) {
+ if (mVisibleElementMap == null) {
throw new RSIllegalArgumentException("Element contains no sub-elements");
}
- if (index < 0 || index >= mElements.length) {
+ if (index < 0 || index >= mVisibleElementMap.length) {
throw new RSIllegalArgumentException("Illegal sub-element index");
}
- return mArraySizes[index];
+ return mArraySizes[mVisibleElementMap[index]];
}
/**
@@ -224,13 +262,29 @@ public class Element extends BaseObj {
* @return offset in bytes of sub-element in this element at given index
*/
public int getSubElementOffsetBytes(int index) {
- if (mElements == null) {
+ if (mVisibleElementMap == null) {
throw new RSIllegalArgumentException("Element contains no sub-elements");
}
- if (index < 0 || index >= mElements.length) {
+ if (index < 0 || index >= mVisibleElementMap.length) {
throw new RSIllegalArgumentException("Illegal sub-element index");
}
- return mOffsetInBytes[index];
+ return mOffsetInBytes[mVisibleElementMap[index]];
+ }
+
+ /**
+ * @hide
+ * @return element data type
+ */
+ public DataType getDataType() {
+ return mType;
+ }
+
+ /**
+ * @hide
+ * @return element data kind
+ */
+ public DataKind getDataKind() {
+ return mKind;
}
/**
@@ -681,14 +735,18 @@ public class Element extends BaseObj {
Element(int id, RenderScript rs, Element[] e, String[] n, int[] as) {
super(id, rs);
mSize = 0;
+ mVectorSize = 1;
mElements = e;
mElementNames = n;
mArraySizes = as;
+ mType = DataType.NONE;
+ mKind = DataKind.USER;
mOffsetInBytes = new int[mElements.length];
for (int ct = 0; ct < mElements.length; ct++ ) {
mOffsetInBytes[ct] = mSize;
mSize += mElements[ct].mSize * mArraySizes[ct];
}
+ updateVisibleSubElements();
}
Element(int id, RenderScript rs, DataType dt, DataKind dk, boolean norm, int size) {
@@ -753,7 +811,7 @@ public class Element extends BaseObj {
mSize += mElements[i].mSize * mArraySizes[i];
}
}
-
+ updateVisibleSubElements();
}
/**
diff --git a/graphics/java/android/renderscript/Path.java b/graphics/java/android/renderscript/Path.java
new file mode 100644
index 000000000000..83ae150abd13
--- /dev/null
+++ b/graphics/java/android/renderscript/Path.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.renderscript;
+
+import java.util.Vector;
+import android.util.Log;
+
+/**
+ * @hide
+ *
+ */
+public class Path extends BaseObj {
+
+ public enum Primitive {
+ QUADRATIC_BEZIER(0),
+ CUBIC_BEZIER(1);
+
+ int mID;
+ Primitive(int id) {
+ mID = id;
+ }
+ }
+
+ Allocation mVertexBuffer;
+ Allocation mLoopBuffer;
+ Primitive mPrimitive;
+ float mQuality;
+ boolean mCoverageToAlpha;
+
+ Path(int id, RenderScript rs, Primitive p, Allocation vtx, Allocation loop, float q) {
+ super(id, rs);
+ mVertexBuffer = vtx;
+ mLoopBuffer = loop;
+ mPrimitive = p;
+ mQuality = q;
+ }
+
+ public Allocation getVertexAllocation() {
+ return mVertexBuffer;
+ }
+
+ public Allocation getLoopAllocation() {
+ return mLoopBuffer;
+ }
+
+ public Primitive getPrimitive() {
+ return mPrimitive;
+ }
+
+ @Override
+ void updateFromNative() {
+ }
+
+
+ public static Path createStaticPath(RenderScript rs, Primitive p, float quality, Allocation vtx) {
+ int id = rs.nPathCreate(p.mID, false, vtx.getID(), 0, quality);
+ Path newPath = new Path(id, rs, p, null, null, quality);
+ return newPath;
+ }
+
+ public static Path createStaticPath(RenderScript rs, Primitive p, float quality, Allocation vtx, Allocation loops) {
+ return null;
+ }
+
+ public static Path createDynamicPath(RenderScript rs, Primitive p, float quality, Allocation vtx) {
+ return null;
+ }
+
+ public static Path createDynamicPath(RenderScript rs, Primitive p, float quality, Allocation vtx, Allocation loops) {
+ return null;
+ }
+
+
+}
+
+
diff --git a/graphics/java/android/renderscript/Program.java b/graphics/java/android/renderscript/Program.java
index a1b1ba3dac23..3f769eecdd97 100644
--- a/graphics/java/android/renderscript/Program.java
+++ b/graphics/java/android/renderscript/Program.java
@@ -77,6 +77,40 @@ public class Program extends BaseObj {
}
/**
+ * @hide
+ */
+ public int getConstantCount() {
+ return mConstants != null ? mConstants.length : 0;
+ }
+
+ /**
+ * @hide
+ */
+ public Type getConstant(int slot) {
+ if (slot < 0 || slot >= mConstants.length) {
+ throw new IllegalArgumentException("Slot ID out of range.");
+ }
+ return mConstants[slot];
+ }
+
+ /**
+ * @hide
+ */
+ public int getTextureCount() {
+ return mTextureCount;
+ }
+
+ /**
+ * @hide
+ */
+ public TextureType getTextureType(int slot) {
+ if ((slot < 0) || (slot >= mTextureCount)) {
+ throw new IllegalArgumentException("Slot ID out of range.");
+ }
+ return mTextures[slot];
+ }
+
+ /**
* Binds a constant buffer to be used as uniform inputs to the
* program
*
diff --git a/graphics/java/android/renderscript/ProgramVertex.java b/graphics/java/android/renderscript/ProgramVertex.java
index 56bb8365674d..b3c1bd9ee37a 100644
--- a/graphics/java/android/renderscript/ProgramVertex.java
+++ b/graphics/java/android/renderscript/ProgramVertex.java
@@ -55,6 +55,23 @@ public class ProgramVertex extends Program {
}
/**
+ * @hide
+ */
+ public int getInputCount() {
+ return mInputs != null ? mInputs.length : 0;
+ }
+
+ /**
+ * @hide
+ */
+ public Element getInput(int slot) {
+ if (slot < 0 || slot >= mInputs.length) {
+ throw new IllegalArgumentException("Slot ID out of range.");
+ }
+ return mInputs[slot];
+ }
+
+ /**
* Builder class for creating ProgramVertex objects.
* The builder starts empty and the user must minimally provide
* the GLSL shader code, and the varying inputs. Constant, or
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 3f3033b44a0f..d3c801f2f730 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -231,10 +231,10 @@ public class RenderScript {
rsnTypeGetNativeData(mContext, id, typeData);
}
- native int rsnAllocationCreateTyped(int con, int type, int mip, int usage);
- synchronized int nAllocationCreateTyped(int type, int mip, int usage) {
+ native int rsnAllocationCreateTyped(int con, int type, int mip, int usage, int pointer);
+ synchronized int nAllocationCreateTyped(int type, int mip, int usage, int pointer) {
validate();
- return rsnAllocationCreateTyped(mContext, type, mip, usage);
+ return rsnAllocationCreateTyped(mContext, type, mip, usage, pointer);
}
native int rsnAllocationCreateFromBitmap(int con, int type, int mip, Bitmap bmp, int usage);
synchronized int nAllocationCreateFromBitmap(int type, int mip, Bitmap bmp, int usage) {
@@ -590,6 +590,11 @@ public class RenderScript {
rsnMeshGetIndices(mContext, id, idxIds, primitives, vtxIdCount);
}
+ native int rsnPathCreate(int con, int prim, boolean isStatic, int vtx, int loop, float q);
+ synchronized int nPathCreate(int prim, boolean isStatic, int vtx, int loop, float q) {
+ validate();
+ return rsnPathCreate(mContext, prim, isStatic, vtx, loop, q);
+ }
int mDev;
int mContext;
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index a9f0f1fa1f5a..94f19b34661d 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -430,10 +430,10 @@ nTypeGetNativeData(JNIEnv *_env, jobject _this, RsContext con, jint id, jintArra
// -----------------------------------
static jint
-nAllocationCreateTyped(JNIEnv *_env, jobject _this, RsContext con, jint type, jint mips, jint usage)
+nAllocationCreateTyped(JNIEnv *_env, jobject _this, RsContext con, jint type, jint mips, jint usage, jint pointer)
{
- LOG_API("nAllocationCreateTyped, con(%p), type(%p), mip(%i), usage(%i)", con, (RsElement)type, mips, usage);
- return (jint) rsAllocationCreateTyped(con, (RsType)type, (RsAllocationMipmapControl)mips, (uint32_t)usage);
+ LOG_API("nAllocationCreateTyped, con(%p), type(%p), mip(%i), usage(%i), ptr(%p)", con, (RsElement)type, mips, usage, (void *)pointer);
+ return (jint) rsAllocationCreateTyped(con, (RsType)type, (RsAllocationMipmapControl)mips, (uint32_t)usage, (uint32_t)pointer);
}
static void
@@ -1129,6 +1129,17 @@ nSamplerCreate(JNIEnv *_env, jobject _this, RsContext con, jint magFilter, jint
// ---------------------------------------------------------------------------
+//native int rsnPathCreate(int con, int prim, boolean isStatic, int vtx, int loop, float q);
+static jint
+nPathCreate(JNIEnv *_env, jobject _this, RsContext con, jint prim, jboolean isStatic, jint _vtx, jint _loop, jfloat q) {
+ LOG_API("nPathCreate, con(%p)", con);
+
+ int id = (int)rsPathCreate(con, (RsPathPrimitive)prim, isStatic,
+ (RsAllocation)_vtx,
+ (RsAllocation)_loop, q);
+ return id;
+}
+
static jint
nMeshCreate(JNIEnv *_env, jobject _this, RsContext con, jintArray _vtx, jintArray _idx, jintArray _prim)
{
@@ -1257,7 +1268,7 @@ static JNINativeMethod methods[] = {
{"rsnTypeCreate", "(IIIIIZZ)I", (void*)nTypeCreate },
{"rsnTypeGetNativeData", "(II[I)V", (void*)nTypeGetNativeData },
-{"rsnAllocationCreateTyped", "(IIII)I", (void*)nAllocationCreateTyped },
+{"rsnAllocationCreateTyped", "(IIIII)I", (void*)nAllocationCreateTyped },
{"rsnAllocationCreateFromBitmap", "(IIILandroid/graphics/Bitmap;I)I", (void*)nAllocationCreateFromBitmap },
{"rsnAllocationCubeCreateFromBitmap","(IIILandroid/graphics/Bitmap;I)I", (void*)nAllocationCubeCreateFromBitmap },
@@ -1318,6 +1329,7 @@ static JNINativeMethod methods[] = {
{"rsnSamplerCreate", "(IIIIIIF)I", (void*)nSamplerCreate },
+{"rsnPathCreate", "(IIZIIF)I", (void*)nPathCreate },
{"rsnMeshCreate", "(I[I[I[I)I", (void*)nMeshCreate },
{"rsnMeshGetVertexBufferCount", "(II)I", (void*)nMeshGetVertexBufferCount },
diff --git a/include/android_runtime/android_app_NativeActivity.h b/include/android_runtime/android_app_NativeActivity.h
index 990143b5ca89..93fcf69a17a9 100644
--- a/include/android_runtime/android_app_NativeActivity.h
+++ b/include/android_runtime/android_app_NativeActivity.h
@@ -114,8 +114,8 @@ private:
struct in_flight_event {
android::InputEvent* event;
- int seq;
- bool doFinish;
+ int seq; // internal sequence number for synthetic pre-dispatch events
+ uint32_t finishSeq; // sequence number for sendFinishedSignal, or 0 if finish not required
};
struct finish_pre_dispatch {
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index ca57f9edc9ae..437a89c0b09f 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -341,7 +341,7 @@ private:
private:
friend class AudioRecord;
virtual bool threadLoop();
- virtual status_t readyToRun() { return NO_ERROR; }
+ virtual status_t readyToRun();
virtual void onFirstRef() {}
AudioRecord& mReceiver;
};
@@ -359,7 +359,9 @@ private:
sp<IAudioRecord> mAudioRecord;
sp<IMemory> mCblkMemory;
sp<ClientRecordThread> mClientRecordThread;
+ status_t mReadyToRun;
Mutex mLock;
+ Condition mCondition;
uint32_t mFrameCount;
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index da99620ea039..1916ac5fd781 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -131,7 +131,7 @@ public:
NUM_CONFIG_EVENTS
};
- // audio output descritor used to cache output configurations in client process to avoid frequent calls
+ // audio output descriptor used to cache output configurations in client process to avoid frequent calls
// through IAudioFlinger
class OutputDescriptor {
public:
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 11db81ba52fb..ac7f6cf22c10 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -58,8 +58,8 @@ public:
EVENT_BUFFER_END = 5 // Playback head is at the end of the buffer.
};
- /* Create Buffer on the stack and pass it to obtainBuffer()
- * and releaseBuffer().
+ /* Client should declare Buffer on the stack and pass address to obtainBuffer()
+ * and releaseBuffer(). See also callback_t for EVENT_MORE_DATA.
*/
class Buffer
@@ -68,12 +68,16 @@ public:
enum {
MUTE = 0x00000001
};
- uint32_t flags;
+ uint32_t flags; // 0 or MUTE
audio_format_t format; // but AUDIO_FORMAT_PCM_8_BIT -> AUDIO_FORMAT_PCM_16_BIT
// accessed directly by WebKit ANP callback
int channelCount; // will be removed in the future, do not use
- size_t frameCount;
- size_t size;
+
+ size_t frameCount; // number of sample frames corresponding to size;
+ // on input it is the number of frames desired,
+ // on output is the number of frames actually filled
+
+ size_t size; // input/output in byte units
union {
void* raw;
short* i16; // signed 16-bit
@@ -84,15 +88,15 @@ public:
/* As a convenience, if a callback is supplied, a handler thread
* is automatically created with the appropriate priority. This thread
- * invokes the callback when a new buffer becomes available or an underrun condition occurs.
+ * invokes the callback when a new buffer becomes available or various conditions occur.
* Parameters:
*
* event: type of event notified (see enum AudioTrack::event_type).
* user: Pointer to context for use by the callback receiver.
* info: Pointer to optional parameter according to event type:
* - EVENT_MORE_DATA: pointer to AudioTrack::Buffer struct. The callback must not write
- * more bytes than indicated by 'size' field and update 'size' if less bytes are
- * written.
+ * more bytes than indicated by 'size' field and update 'size' if fewer bytes are
+ * written.
* - EVENT_UNDERRUN: unused.
* - EVENT_LOOP_END: pointer to an int indicating the number of loops remaining.
* - EVENT_MARKER: pointer to an uint32_t containing the marker position in frames.
@@ -225,7 +229,7 @@ public:
*/
uint32_t latency() const;
- /* getters, see constructor */
+ /* getters, see constructors and set() */
audio_stream_type_t streamType() const;
audio_format_t format() const;
@@ -299,7 +303,6 @@ public:
* (loopEnd-loopStart) <= framecount()
*/
status_t setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount);
- status_t getLoop(uint32_t *loopStart, uint32_t *loopEnd, int *loopCount) const;
/* Sets marker position. When playback reaches the number of frames specified, a callback with
* event type EVENT_MARKER is called. Calling setMarkerPosition with marker == 0 cancels marker
@@ -401,13 +404,19 @@ public:
status_t attachAuxEffect(int effectId);
/* Obtains a buffer of "frameCount" frames. The buffer must be
- * filled entirely. If the track is stopped, obtainBuffer() returns
+ * filled entirely, and then released with releaseBuffer().
+ * If the track is stopped, obtainBuffer() returns
* STOPPED instead of NO_ERROR as long as there are buffers available,
* at which point NO_MORE_BUFFERS is returned.
* Buffers will be returned until the pool (buffercount())
* is exhausted, at which point obtainBuffer() will either block
* or return WOULD_BLOCK depending on the value of the "blocking"
* parameter.
+ *
+ * Interpretation of waitCount:
+ * +n limits wait time to n * WAIT_PERIOD_MS,
+ * -1 causes an (almost) infinite wait time,
+ * 0 non-blocking.
*/
enum {
@@ -416,12 +425,19 @@ public:
};
status_t obtainBuffer(Buffer* audioBuffer, int32_t waitCount);
+
+ /* Release a filled buffer of "frameCount" frames for AudioFlinger to process. */
void releaseBuffer(Buffer* audioBuffer);
/* As a convenience we provide a write() interface to the audio buffer.
- * This is implemented on top of lockBuffer/unlockBuffer. For best
- * performance use callbacks. Return actual number of bytes written.
- *
+ * This is implemented on top of obtainBuffer/releaseBuffer. For best
+ * performance use callbacks. Returns actual number of bytes written >= 0,
+ * or one of the following negative status codes:
+ * INVALID_OPERATION AudioTrack is configured for shared buffer mode
+ * BAD_VALUE size is invalid
+ * STOPPED AudioTrack was stopped during the write
+ * NO_MORE_BUFFERS when obtainBuffer() returns same
+ * or any other error code returned by IAudioTrack::start() or restoreTrack_l().
*/
ssize_t write(const void* buffer, size_t size);
@@ -448,6 +464,7 @@ private:
AudioTrack& mReceiver;
};
+ // body of AudioTrackThread::threadLoop()
bool processAudioBuffer(const sp<AudioTrackThread>& thread);
status_t createTrack_l(audio_stream_type_t streamType,
uint32_t sampleRate,
@@ -484,7 +501,7 @@ private:
bool mActive; // protected by mLock
- callback_t mCbf;
+ callback_t mCbf; // callback handler for events, or NULL
void* mUserData;
uint32_t mNotificationFramesReq; // requested number of frames between each notification callback
uint32_t mNotificationFramesAct; // actual number of frames between each notification callback
diff --git a/include/media/EffectsFactoryApi.h b/include/media/EffectsFactoryApi.h
index df83995aab19..65c26f4794be 100644
--- a/include/media/EffectsFactoryApi.h
+++ b/include/media/EffectsFactoryApi.h
@@ -87,7 +87,7 @@ int EffectQueryEffect(uint32_t index, effect_descriptor_t *pDescriptor);
// Description: Creates an effect engine of the specified type and returns an
// effect control interface on this engine. The function will allocate the
// resources for an instance of the requested effect engine and return
-// a handler on the effect control interface.
+// a handle on the effect control interface.
//
// Input:
// pEffectUuid: pointer to the effect uuid.
@@ -115,17 +115,17 @@ int EffectCreate(const effect_uuid_t *pEffectUuid, int32_t sessionId, int32_t io
//
// Function: EffectRelease
//
-// Description: Releases the effect engine whose handler is given as argument.
+// Description: Releases the effect engine whose handle is given as argument.
// All resources allocated to this particular instance of the effect are
// released.
//
// Input:
-// handle: handler on the effect interface to be released.
+// handle: handle on the effect interface to be released.
//
// Output:
// returned value: 0 successful operation.
// -ENODEV factory failed to initialize
-// -EINVAL invalid interface handler
+// -EINVAL invalid interface handle
//
////////////////////////////////////////////////////////////////////////////////
int EffectRelease(effect_handle_t handle);
diff --git a/include/media/IAudioRecord.h b/include/media/IAudioRecord.h
index 46735def2f52..7869020e9e06 100644
--- a/include/media/IAudioRecord.h
+++ b/include/media/IAudioRecord.h
@@ -37,8 +37,9 @@ public:
/* After it's created the track is not active. Call start() to
* make it active. If set, the callback will start being called.
+ * tid identifies the client callback thread, or 0 if not needed.
*/
- virtual status_t start() = 0;
+ virtual status_t start(pid_t tid) = 0;
/* Stop a track. If set, the callback will cease being called and
* obtainBuffer will return an error. Buffers that are already released
diff --git a/include/media/IAudioTrack.h b/include/media/IAudioTrack.h
index b83e552dcd97..e4772a17edec 100644
--- a/include/media/IAudioTrack.h
+++ b/include/media/IAudioTrack.h
@@ -40,17 +40,18 @@ public:
/* After it's created the track is not active. Call start() to
* make it active. If set, the callback will start being called.
+ * tid identifies the client callback thread, or 0 if not needed.
*/
- virtual status_t start() = 0;
+ virtual status_t start(pid_t tid) = 0;
/* Stop a track. If set, the callback will cease being called and
* obtainBuffer will return an error. Buffers that are already released
- * will be processed, unless flush() is called.
+ * will continue to be processed, unless/until flush() is called.
*/
virtual void stop() = 0;
- /* Flush a stopped track. All pending buffers are discarded.
- * This function has no effect if the track is not stopped.
+ /* Flush a stopped or paused track. All pending/released buffers are discarded.
+ * This function has no effect if the track is not stopped or paused.
*/
virtual void flush() = 0;
@@ -61,7 +62,7 @@ public:
/* Pause a track. If set, the callback will cease being called and
* obtainBuffer will return an error. Buffers that are already released
- * will be processed, unless flush() is called.
+ * will continue to be processed, unless/until flush() is called.
*/
virtual void pause() = 0;
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 7beb1766d209..77c82b27ba1b 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -96,6 +96,8 @@ public:
virtual void flush() = 0;
virtual void pause() = 0;
virtual void close() = 0;
+
+ virtual status_t setPlaybackRatePermille(int32_t rate) { return INVALID_OPERATION; }
};
MediaPlayerBase() : mCookie(0), mNotify(0) {}
diff --git a/include/media/MemoryLeakTrackUtil.h b/include/media/MemoryLeakTrackUtil.h
index 290b7481712f..ac0f6b266b6d 100644
--- a/include/media/MemoryLeakTrackUtil.h
+++ b/include/media/MemoryLeakTrackUtil.h
@@ -19,7 +19,7 @@
namespace android {
/*
- * Dump the memory adddress of the calling process to the given fd.
+ * Dump the memory address of the calling process to the given fd.
*/
extern void dumpMemoryAddresses(int fd);
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 00b7dd584135..d0b87c8e6888 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -145,6 +145,9 @@ enum media_parameter_keys {
// audio track, or zero for error (e.g. no audio track) or unknown.
KEY_PARAMETER_AUDIO_CHANNEL_COUNT = 1200, // get only
+ // Playback rate expressed in permille (1000 is normal speed), saved as int32_t, with negative
+ // values used for rewinding or reverse playback.
+ KEY_PARAMETER_PLAYBACK_RATE_PERMILLE = 1300, // set only
};
// ----------------------------------------------------------------------------
diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h
index 0b79324db69d..70c47aeb7b9a 100644
--- a/include/media/stagefright/AudioPlayer.h
+++ b/include/media/stagefright/AudioPlayer.h
@@ -64,6 +64,8 @@ public:
bool isSeeking();
bool reachedEOS(status_t *finalStatus);
+ status_t setPlaybackRatePermille(int32_t ratePermille);
+
private:
friend class VideoEditorAudioPlayer;
sp<MediaSource> mSource;
diff --git a/include/media/stagefright/MediaDebug.h b/include/media/stagefright/MediaDebug.h
deleted file mode 100644
index 2ca96670b14e..000000000000
--- a/include/media/stagefright/MediaDebug.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef MEDIA_DEBUG_H_
-
-#define MEDIA_DEBUG_H_
-
-#include <cutils/log.h>
-
-#define LITERAL_TO_STRING_INTERNAL(x) #x
-#define LITERAL_TO_STRING(x) LITERAL_TO_STRING_INTERNAL(x)
-
-#define CHECK_EQ(x,y) \
- LOG_ALWAYS_FATAL_IF( \
- (x) != (y), \
- __FILE__ ":" LITERAL_TO_STRING(__LINE__) " " #x " != " #y)
-
-#define CHECK(x) \
- LOG_ALWAYS_FATAL_IF( \
- !(x), \
- __FILE__ ":" LITERAL_TO_STRING(__LINE__) " " #x)
-
-#endif // MEDIA_DEBUG_H_
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 23226c0f3505..af2db9379f31 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -62,16 +62,23 @@ struct audio_track_cblk_t
// are in the same line of data cache.
Mutex lock; // sizeof(int)
Condition cv; // sizeof(int)
+
+ // next 4 are offsets within "buffers"
volatile uint32_t user;
volatile uint32_t server;
uint32_t userBase;
uint32_t serverBase;
+
+ // if there is a shared buffer, "buffers" is the value of pointer() for the shared
+ // buffer, otherwise "buffers" points immediately after the control block
void* buffers;
uint32_t frameCount;
+
// Cache line boundary
+
uint32_t loopStart;
- uint32_t loopEnd;
- int loopCount;
+ uint32_t loopEnd; // read-only for server, read/write for client
+ int loopCount; // read/write for client
// Channel volumes are fixed point U4.12, so 0x1000 means 1.0.
// Left channel is in [0:15], right channel is in [16:31].
@@ -82,29 +89,39 @@ private:
public:
uint32_t sampleRate;
+
// NOTE: audio_track_cblk_t::frameSize is not equal to AudioTrack::frameSize() for
// 8 bit PCM data: in this case, mCblk->frameSize is based on a sample size of
// 16 bit because data is converted to 16 bit before being stored in buffer
+ // read-only for client, server writes once at initialization and is then read-only
uint8_t frameSize; // would normally be size_t, but 8 bits is plenty
+
+ // never used
uint8_t pad1;
+
+ // used by client only
uint16_t bufferTimeoutMs; // Maximum cumulated timeout before restarting audioflinger
- uint16_t waitTimeMs; // Cumulated wait time
+ uint16_t waitTimeMs; // Cumulated wait time, used by client only
private:
+ // client write-only, server read-only
uint16_t mSendLevel; // Fixed point U4.12 so 0x1000 means 1.0
public:
volatile int32_t flags;
// Cache line boundary (32 bytes)
+ // Since the control block is always located in shared memory, this constructor
+ // is only used for placement new(). It is never used for regular new() or stack.
audio_track_cblk_t();
- uint32_t stepUser(uint32_t frameCount);
- bool stepServer(uint32_t frameCount);
+ uint32_t stepUser(uint32_t frameCount); // called by client only, where
+ // client includes regular AudioTrack and AudioFlinger::PlaybackThread::OutputTrack
+ bool stepServer(uint32_t frameCount); // called by server only
void* buffer(uint32_t offset) const;
uint32_t framesAvailable();
uint32_t framesAvailable_l();
- uint32_t framesReady();
+ uint32_t framesReady(); // called by server only
bool tryLock();
// No barriers on the following operations, so the ordering of loads/stores
diff --git a/include/ui/InputTransport.h b/include/ui/InputTransport.h
index 95e4447c6a88..1f738cdbdc7a 100644
--- a/include/ui/InputTransport.h
+++ b/include/ui/InputTransport.h
@@ -20,17 +20,13 @@
/**
* Native input transport.
*
- * Uses anonymous shared memory as a whiteboard for sending input events from an
- * InputPublisher to an InputConsumer and ensuring appropriate synchronization.
- * One interesting feature is that published events can be updated in place as long as they
- * have not yet been consumed.
+ * The InputChannel provides a mechanism for exchanging InputMessage structures across processes.
*
- * The InputPublisher and InputConsumer only take care of transferring event data
- * over an InputChannel and sending synchronization signals. The InputDispatcher and InputQueue
- * build on these abstractions to add multiplexing and queueing.
+ * The InputPublisher and InputConsumer each handle one end-point of an input channel.
+ * The InputPublisher is used by the input dispatcher to send events to the application.
+ * The InputConsumer is used by the application to receive events from the input dispatcher.
*/
-#include <semaphore.h>
#include <ui/Input.h>
#include <utils/Errors.h>
#include <utils/Timers.h>
@@ -40,11 +36,85 @@
namespace android {
/*
- * An input channel consists of a shared memory buffer and a pair of pipes
- * used to send input messages from an InputPublisher to an InputConsumer
- * across processes. Each channel has a descriptive name for debugging purposes.
+ * Intermediate representation used to send input events and related signals.
+ */
+struct InputMessage {
+ enum {
+ TYPE_KEY = 1,
+ TYPE_MOTION = 2,
+ TYPE_FINISHED = 3,
+ };
+
+ struct Header {
+ uint32_t type;
+ uint32_t padding; // 8 byte alignment for the body that follows
+ } header;
+
+ union Body {
+ struct Key {
+ uint32_t seq;
+ nsecs_t eventTime;
+ int32_t deviceId;
+ int32_t source;
+ int32_t action;
+ int32_t flags;
+ int32_t keyCode;
+ int32_t scanCode;
+ int32_t metaState;
+ int32_t repeatCount;
+ nsecs_t downTime;
+
+ inline size_t size() const {
+ return sizeof(Key);
+ }
+ } key;
+
+ struct Motion {
+ uint32_t seq;
+ nsecs_t eventTime;
+ int32_t deviceId;
+ int32_t source;
+ int32_t action;
+ int32_t flags;
+ int32_t metaState;
+ int32_t buttonState;
+ int32_t edgeFlags;
+ nsecs_t downTime;
+ float xOffset;
+ float yOffset;
+ float xPrecision;
+ float yPrecision;
+ size_t pointerCount;
+ struct Pointer {
+ PointerProperties properties;
+ PointerCoords coords;
+ } pointers[MAX_POINTERS];
+
+ inline size_t size() const {
+ return sizeof(Motion) - sizeof(Pointer) * MAX_POINTERS
+ + sizeof(Pointer) * pointerCount;
+ }
+ } motion;
+
+ struct Finished {
+ uint32_t seq;
+ bool handled;
+
+ inline size_t size() const {
+ return sizeof(Finished);
+ }
+ } finished;
+ } body;
+
+ bool isValid(size_t actualSize) const;
+ size_t size() const;
+};
+
+/*
+ * An input channel consists of a local unix domain socket used to send and receive
+ * input messages across processes. Each channel has a descriptive name for debugging purposes.
*
- * Each endpoint has its own InputChannel object that specifies its own file descriptors.
+ * Each endpoint has its own InputChannel object that specifies its file descriptor.
*
* The input channel is closed when all references to it are released.
*/
@@ -53,11 +123,9 @@ protected:
virtual ~InputChannel();
public:
- InputChannel(const String8& name, int32_t ashmemFd, int32_t receivePipeFd,
- int32_t sendPipeFd);
+ InputChannel(const String8& name, int32_t fd);
- /* Creates a pair of input channels and their underlying shared memory buffers
- * and pipes.
+ /* Creates a pair of input channels.
*
* Returns OK on success.
*/
@@ -65,107 +133,40 @@ public:
sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel);
inline String8 getName() const { return mName; }
- inline int32_t getAshmemFd() const { return mAshmemFd; }
- inline int32_t getReceivePipeFd() const { return mReceivePipeFd; }
- inline int32_t getSendPipeFd() const { return mSendPipeFd; }
+ inline int32_t getFd() const { return mFd; }
- /* Sends a signal to the other endpoint.
+ /* Sends a message to the other endpoint.
+ *
+ * If the channel is full then the message is guaranteed not to have been sent at all.
+ * Try again after the consumer has sent a finished signal indicating that it has
+ * consumed some of the pending messages from the channel.
*
* Returns OK on success.
+ * Returns WOULD_BLOCK if the channel is full.
* Returns DEAD_OBJECT if the channel's peer has been closed.
* Other errors probably indicate that the channel is broken.
*/
- status_t sendSignal(char signal);
+ status_t sendMessage(const InputMessage* msg);
- /* Receives a signal send by the other endpoint.
- * (Should only call this after poll() indicates that the receivePipeFd has available input.)
+ /* Receives a message sent by the other endpoint.
+ *
+ * If there is no message present, try again after poll() indicates that the fd
+ * is readable.
*
* Returns OK on success.
- * Returns WOULD_BLOCK if there is no signal present.
+ * Returns WOULD_BLOCK if there is no message present.
* Returns DEAD_OBJECT if the channel's peer has been closed.
* Other errors probably indicate that the channel is broken.
*/
- status_t receiveSignal(char* outSignal);
+ status_t receiveMessage(InputMessage* msg);
private:
String8 mName;
- int32_t mAshmemFd;
- int32_t mReceivePipeFd;
- int32_t mSendPipeFd;
+ int32_t mFd;
};
/*
- * Private intermediate representation of input events as messages written into an
- * ashmem buffer.
- */
-struct InputMessage {
- /* Semaphore count is set to 1 when the message is published.
- * It becomes 0 transiently while the publisher updates the message.
- * It becomes 0 permanently when the consumer consumes the message.
- */
- sem_t semaphore;
-
- /* Initialized to false by the publisher.
- * Set to true by the consumer when it consumes the message.
- */
- bool consumed;
-
- int32_t type;
-
- struct SampleData {
- nsecs_t eventTime;
- PointerCoords coords[0]; // variable length
- };
-
- int32_t deviceId;
- int32_t source;
-
- union {
- struct {
- int32_t action;
- int32_t flags;
- int32_t keyCode;
- int32_t scanCode;
- int32_t metaState;
- int32_t repeatCount;
- nsecs_t downTime;
- nsecs_t eventTime;
- } key;
-
- struct {
- int32_t action;
- int32_t flags;
- int32_t metaState;
- int32_t buttonState;
- int32_t edgeFlags;
- nsecs_t downTime;
- float xOffset;
- float yOffset;
- float xPrecision;
- float yPrecision;
- size_t pointerCount;
- PointerProperties pointerProperties[MAX_POINTERS];
- size_t sampleCount;
- SampleData sampleData[0]; // variable length
- } motion;
- };
-
- /* Gets the number of bytes to add to step to the next SampleData object in a motion
- * event message for a given number of pointers.
- */
- static inline size_t sampleDataStride(size_t pointerCount) {
- return sizeof(InputMessage::SampleData) + pointerCount * sizeof(PointerCoords);
- }
-
- /* Adds the SampleData stride to the given pointer. */
- static inline SampleData* sampleDataPtrIncrement(SampleData* ptr, size_t stride) {
- return reinterpret_cast<InputMessage::SampleData*>(reinterpret_cast<char*>(ptr) + stride);
- }
-};
-
-/*
- * Publishes input events to an anonymous shared memory buffer.
- * Uses atomic operations to coordinate shared access with a single concurrent consumer.
+ * Publishes input events to an input channel.
*/
class InputPublisher {
public:
@@ -178,26 +179,16 @@ public:
/* Gets the underlying input channel. */
inline sp<InputChannel> getChannel() { return mChannel; }
- /* Prepares the publisher for use. Must be called before it is used.
- * Returns OK on success.
- *
- * This method implicitly calls reset(). */
- status_t initialize();
-
- /* Resets the publisher to its initial state and unpins its ashmem buffer.
- * Returns OK on success.
- *
- * Should be called after an event has been consumed to release resources used by the
- * publisher until the next event is ready to be published.
- */
- status_t reset();
-
- /* Publishes a key event to the ashmem buffer.
+ /* Publishes a key event to the input channel.
*
* Returns OK on success.
- * Returns INVALID_OPERATION if the publisher has not been reset.
+ * Returns WOULD_BLOCK if the channel is full.
+ * Returns DEAD_OBJECT if the channel's peer has been closed.
+ * Returns BAD_VALUE if seq is 0.
+ * Other errors probably indicate that the channel is broken.
*/
status_t publishKeyEvent(
+ uint32_t seq,
int32_t deviceId,
int32_t source,
int32_t action,
@@ -209,13 +200,16 @@ public:
nsecs_t downTime,
nsecs_t eventTime);
- /* Publishes a motion event to the ashmem buffer.
+ /* Publishes a motion event to the input channel.
*
* Returns OK on success.
- * Returns INVALID_OPERATION if the publisher has not been reset.
- * Returns BAD_VALUE if pointerCount is less than 1 or greater than MAX_POINTERS.
+ * Returns WOULD_BLOCK if the channel is full.
+ * Returns DEAD_OBJECT if the channel's peer has been closed.
+ * Returns BAD_VALUE if seq is 0 or if pointerCount is less than 1 or greater than MAX_POINTERS.
+ * Other errors probably indicate that the channel is broken.
*/
status_t publishMotionEvent(
+ uint32_t seq,
int32_t deviceId,
int32_t source,
int32_t action,
@@ -233,55 +227,25 @@ public:
const PointerProperties* pointerProperties,
const PointerCoords* pointerCoords);
- /* Appends a motion sample to a motion event unless already consumed.
- *
- * Returns OK on success.
- * Returns INVALID_OPERATION if the current event is not a AMOTION_EVENT_ACTION_MOVE event.
- * Returns FAILED_TRANSACTION if the current event has already been consumed.
- * Returns NO_MEMORY if the buffer is full and no additional samples can be added.
- */
- status_t appendMotionSample(
- nsecs_t eventTime,
- const PointerCoords* pointerCoords);
-
- /* Sends a dispatch signal to the consumer to inform it that a new message is available.
- *
- * Returns OK on success.
- * Errors probably indicate that the channel is broken.
- */
- status_t sendDispatchSignal();
-
/* Receives the finished signal from the consumer in reply to the original dispatch signal.
- * Returns whether the consumer handled the message.
+ * If a signal was received, returns the message sequence number,
+ * and whether the consumer handled the message.
+ *
+ * The returned sequence number is never 0 unless the operation failed.
*
* Returns OK on success.
* Returns WOULD_BLOCK if there is no signal present.
+ * Returns DEAD_OBJECT if the channel's peer has been closed.
* Other errors probably indicate that the channel is broken.
*/
- status_t receiveFinishedSignal(bool* outHandled);
+ status_t receiveFinishedSignal(uint32_t* outSeq, bool* outHandled);
private:
sp<InputChannel> mChannel;
-
- size_t mAshmemSize;
- InputMessage* mSharedMessage;
- bool mPinned;
- bool mSemaphoreInitialized;
- bool mWasDispatched;
-
- size_t mMotionEventPointerCount;
- InputMessage::SampleData* mMotionEventSampleDataTail;
- size_t mMotionEventSampleDataStride;
-
- status_t publishInputEvent(
- int32_t type,
- int32_t deviceId,
- int32_t source);
};
/*
- * Consumes input events from an anonymous shared memory buffer.
- * Uses atomic operations to coordinate shared access with a single concurrent publisher.
+ * Consumes input events from an input channel.
*/
class InputConsumer {
public:
@@ -294,43 +258,76 @@ public:
/* Gets the underlying input channel. */
inline sp<InputChannel> getChannel() { return mChannel; }
- /* Prepares the consumer for use. Must be called before it is used. */
- status_t initialize();
-
- /* Consumes the input event in the buffer and copies its contents into
+ /* Consumes an input event from the input channel and copies its contents into
* an InputEvent object created using the specified factory.
- * This operation will block if the publisher is updating the event.
*
- * Returns OK on success.
- * Returns INVALID_OPERATION if there is no currently published event.
- * Returns NO_MEMORY if the event could not be created.
- */
- status_t consume(InputEventFactoryInterface* factory, InputEvent** outEvent);
-
- /* Sends a finished signal to the publisher to inform it that the current message is
- * finished processing and specifies whether the message was handled by the consumer.
+ * Tries to combine a series of move events into larger batches whenever possible.
+ *
+ * If consumeBatches is false, then defers consuming pending batched events if it
+ * is possible for additional samples to be added to them later. Call hasPendingBatch()
+ * to determine whether a pending batch is available to be consumed.
+ *
+ * If consumeBatches is true, then events are still batched but they are consumed
+ * immediately as soon as the input channel is exhausted.
+ *
+ * The returned sequence number is never 0 unless the operation failed.
*
* Returns OK on success.
- * Errors probably indicate that the channel is broken.
+ * Returns WOULD_BLOCK if there is no event present.
+ * Returns DEAD_OBJECT if the channel's peer has been closed.
+ * Returns NO_MEMORY if the event could not be created.
+ * Other errors probably indicate that the channel is broken.
*/
- status_t sendFinishedSignal(bool handled);
+ status_t consume(InputEventFactoryInterface* factory, bool consumeBatches,
+ uint32_t* outSeq, InputEvent** outEvent);
- /* Receives the dispatched signal from the publisher.
+ /* Sends a finished signal to the publisher to inform it that the message
+ * with the specified sequence number has finished being process and whether
+ * the message was handled by the consumer.
*
* Returns OK on success.
- * Returns WOULD_BLOCK if there is no signal present.
+ * Returns BAD_VALUE if seq is 0.
* Other errors probably indicate that the channel is broken.
*/
- status_t receiveDispatchSignal();
+ status_t sendFinishedSignal(uint32_t seq, bool handled);
+
+ /* Returns true if there is a pending batch. */
+ bool hasPendingBatch() const;
private:
sp<InputChannel> mChannel;
- size_t mAshmemSize;
- InputMessage* mSharedMessage;
+ // The current input message.
+ InputMessage mMsg;
+
+ // True if mMsg contains a valid input message that was deferred from the previous
+ // call to consume and that still needs to be handled.
+ bool mMsgDeferred;
+
+ // Batched motion events per device and source.
+ struct Batch {
+ uint32_t seq; // sequence number of last input message batched in the event
+ MotionEvent event;
+ };
+ Vector<Batch> mBatches;
+
+ // Chain of batched sequence numbers. When multiple input messages are combined into
+ // a batch, we append a record here that associates the last sequence number in the
+ // batch with the previous one. When the finished signal is sent, we traverse the
+ // chain to individually finish all input messages that were part of the batch.
+ struct SeqChain {
+ uint32_t seq; // sequence number of batched input message
+ uint32_t chain; // sequence number of previous batched input message
+ };
+ Vector<SeqChain> mSeqChains;
+
+ ssize_t findBatch(int32_t deviceId, int32_t source) const;
+ status_t sendUnchainedFinishedSignal(uint32_t seq, bool handled);
- void populateKeyEvent(KeyEvent* keyEvent) const;
- void populateMotionEvent(MotionEvent* motionEvent) const;
+ static void initializeKeyEvent(KeyEvent* event, const InputMessage* msg);
+ static void initializeMotionEvent(MotionEvent* event, const InputMessage* msg);
+ static bool canAppendSamples(const MotionEvent* event, const InputMessage* msg);
+ static void appendSamples(MotionEvent* event, const InputMessage* msg);
};
} // namespace android
diff --git a/include/utils/KeyedVector.h b/include/utils/KeyedVector.h
index 6bcdea4ff182..fcc3bcfa00a1 100644
--- a/include/utils/KeyedVector.h
+++ b/include/utils/KeyedVector.h
@@ -66,7 +66,7 @@ public:
ssize_t indexOfKey(const KEY& key) const;
/*!
- * modifing the array
+ * modifying the array
*/
VALUE& editValueFor(const KEY& key);
diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk
index 2166ce7dd01f..9c5d06b7333f 100644
--- a/libs/rs/Android.mk
+++ b/libs/rs/Android.mk
@@ -95,6 +95,7 @@ LOCAL_SRC_FILES:= \
rsMatrix4x4.cpp \
rsMesh.cpp \
rsMutex.cpp \
+ rsPath.cpp \
rsProgram.cpp \
rsProgramFragment.cpp \
rsProgramStore.cpp \
@@ -117,6 +118,7 @@ LOCAL_SRC_FILES:= \
driver/rsdGL.cpp \
driver/rsdMesh.cpp \
driver/rsdMeshObj.cpp \
+ driver/rsdPath.cpp \
driver/rsdProgram.cpp \
driver/rsdProgramRaster.cpp \
driver/rsdProgramStore.cpp \
@@ -201,6 +203,7 @@ LOCAL_SRC_FILES:= \
rsMatrix4x4.cpp \
rsMesh.cpp \
rsMutex.cpp \
+ rsPath.cpp \
rsProgram.cpp \
rsProgramFragment.cpp \
rsProgramStore.cpp \
diff --git a/libs/rs/RenderScriptDefines.h b/libs/rs/RenderScriptDefines.h
index 5b0a3daaf045..990ef266f7ec 100644
--- a/libs/rs/RenderScriptDefines.h
+++ b/libs/rs/RenderScriptDefines.h
@@ -41,6 +41,7 @@ typedef void * RsFont;
typedef void * RsSampler;
typedef void * RsScript;
typedef void * RsMesh;
+typedef void * RsPath;
typedef void * RsType;
typedef void * RsObjectBase;
@@ -155,6 +156,8 @@ enum RsDataType {
RS_TYPE_PROGRAM_VERTEX,
RS_TYPE_PROGRAM_RASTER,
RS_TYPE_PROGRAM_STORE,
+
+ RS_TYPE_INVALID = 10000,
};
enum RsDataKind {
@@ -166,6 +169,8 @@ enum RsDataKind {
RS_KIND_PIXEL_RGB,
RS_KIND_PIXEL_RGBA,
RS_KIND_PIXEL_DEPTH,
+
+ RS_KIND_INVALID = 100,
};
enum RsSamplerParam {
@@ -184,6 +189,8 @@ enum RsSamplerValue {
RS_SAMPLER_WRAP,
RS_SAMPLER_CLAMP,
RS_SAMPLER_LINEAR_MIP_NEAREST,
+
+ RS_SAMPLER_INVALID = 100,
};
enum RsTextureTarget {
@@ -224,7 +231,8 @@ enum RsBlendSrcFunc {
RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA, // 5
RS_BLEND_SRC_DST_ALPHA, // 6
RS_BLEND_SRC_ONE_MINUS_DST_ALPHA, // 7
- RS_BLEND_SRC_SRC_ALPHA_SATURATE // 8
+ RS_BLEND_SRC_SRC_ALPHA_SATURATE, // 8
+ RS_BLEND_SRC_INVALID = 100,
};
enum RsBlendDstFunc {
@@ -235,7 +243,9 @@ enum RsBlendDstFunc {
RS_BLEND_DST_SRC_ALPHA, // 4
RS_BLEND_DST_ONE_MINUS_SRC_ALPHA, // 5
RS_BLEND_DST_DST_ALPHA, // 6
- RS_BLEND_DST_ONE_MINUS_DST_ALPHA // 7
+ RS_BLEND_DST_ONE_MINUS_DST_ALPHA, // 7
+
+ RS_BLEND_DST_INVALID = 100,
};
enum RsTexEnvMode {
@@ -258,7 +268,14 @@ enum RsPrimitive {
RS_PRIMITIVE_LINE_STRIP,
RS_PRIMITIVE_TRIANGLE,
RS_PRIMITIVE_TRIANGLE_STRIP,
- RS_PRIMITIVE_TRIANGLE_FAN
+ RS_PRIMITIVE_TRIANGLE_FAN,
+
+ RS_PRIMITIVE_INVALID = 100,
+};
+
+enum RsPathPrimitive {
+ RS_PATH_PRIMITIVE_QUADRATIC_BEZIER,
+ RS_PATH_PRIMITIVE_CUBIC_BEZIER
};
enum RsError {
@@ -312,7 +329,8 @@ enum RsA3DClassID {
enum RsCullMode {
RS_CULL_BACK,
RS_CULL_FRONT,
- RS_CULL_NONE
+ RS_CULL_NONE,
+ RS_CULL_INVALID = 100,
};
typedef struct {
diff --git a/libs/rs/driver/rsdAllocation.cpp b/libs/rs/driver/rsdAllocation.cpp
index fac40f2567cd..ea921923e745 100644
--- a/libs/rs/driver/rsdAllocation.cpp
+++ b/libs/rs/driver/rsdAllocation.cpp
@@ -219,10 +219,13 @@ bool rsdAllocationInit(const Context *rsc, Allocation *alloc, bool forceZero) {
return false;
}
- void * ptr = malloc(alloc->mHal.state.type->getSizeBytes());
+ void * ptr = alloc->mHal.state.usrPtr;
if (!ptr) {
- free(drv);
- return false;
+ ptr = malloc(alloc->mHal.state.type->getSizeBytes());
+ if (!ptr) {
+ free(drv);
+ return false;
+ }
}
drv->glTarget = GL_NONE;
@@ -276,7 +279,7 @@ void rsdAllocationDestroy(const Context *rsc, Allocation *alloc) {
drv->renderTargetID = 0;
}
- if (drv->mallocPtr) {
+ if (drv->mallocPtr && !alloc->mHal.state.usrPtr) {
free(drv->mallocPtr);
drv->mallocPtr = NULL;
}
diff --git a/libs/rs/driver/rsdCore.cpp b/libs/rs/driver/rsdCore.cpp
index 998702785abb..e01195509a87 100644
--- a/libs/rs/driver/rsdCore.cpp
+++ b/libs/rs/driver/rsdCore.cpp
@@ -18,6 +18,7 @@
#include "rsdAllocation.h"
#include "rsdBcc.h"
#include "rsdGL.h"
+#include "rsdPath.h"
#include "rsdProgramStore.h"
#include "rsdProgramRaster.h"
#include "rsdProgramVertex.h"
@@ -115,6 +116,13 @@ static RsdHalFunctions FunctionTable = {
},
{
+ rsdPathInitStatic,
+ rsdPathInitDynamic,
+ rsdPathDraw,
+ rsdPathDestroy
+ },
+
+ {
rsdSamplerInit,
rsdSamplerDestroy
},
@@ -260,6 +268,9 @@ void SetPriority(const Context *rsc, int32_t priority) {
for (uint32_t ct=0; ct < dc->mWorkers.mCount; ct++) {
setpriority(PRIO_PROCESS, dc->mWorkers.mNativeThreadId[ct], priority);
}
+ if (dc->mHasGraphics) {
+ rsdGLSetPriority(rsc, priority);
+ }
}
void Shutdown(Context *rsc) {
diff --git a/libs/rs/driver/rsdCore.h b/libs/rs/driver/rsdCore.h
index 126c87a2f04f..168bdf36e1cb 100644
--- a/libs/rs/driver/rsdCore.h
+++ b/libs/rs/driver/rsdCore.h
@@ -41,6 +41,7 @@ typedef struct ScriptTLSStructRec {
typedef struct RsdHalRec {
uint32_t version_major;
uint32_t version_minor;
+ bool mHasGraphics;
struct Workers {
volatile int mRunningCount;
diff --git a/libs/rs/driver/rsdGL.cpp b/libs/rs/driver/rsdGL.cpp
index 368dd7107268..b136cc7d767c 100644
--- a/libs/rs/driver/rsdGL.cpp
+++ b/libs/rs/driver/rsdGL.cpp
@@ -361,6 +361,7 @@ bool rsdGLInit(const Context *rsc) {
dc->gl.vertexArrayState = new RsdVertexArrayState();
dc->gl.vertexArrayState->init(dc->gl.gl.maxVertexAttribs);
dc->gl.currentFrameBuffer = NULL;
+ dc->mHasGraphics = true;
ALOGV("%p initGLThread end", rsc);
rsc->setWatchdogGL(NULL, 0, NULL);
@@ -421,6 +422,15 @@ void rsdGLSwap(const android::renderscript::Context *rsc) {
RSD_CALL_GL(eglSwapBuffers, dc->gl.egl.display, dc->gl.egl.surface);
}
+void rsdGLSetPriority(const Context *rsc, int32_t priority) {
+ if (priority > 0) {
+ // Mark context as low priority.
+ ALOGV("low pri");
+ } else {
+ ALOGV("normal pri");
+ }
+}
+
void rsdGLCheckError(const android::renderscript::Context *rsc,
const char *msg, bool isFatal) {
GLenum err = glGetError();
diff --git a/libs/rs/driver/rsdGL.h b/libs/rs/driver/rsdGL.h
index 51893c305ec8..e015cb170246 100644
--- a/libs/rs/driver/rsdGL.h
+++ b/libs/rs/driver/rsdGL.h
@@ -82,6 +82,8 @@ bool rsdGLSetSurface(const android::renderscript::Context *rsc,
void rsdGLSwap(const android::renderscript::Context *rsc);
void rsdGLCheckError(const android::renderscript::Context *rsc,
const char *msg, bool isFatal = false);
+void rsdGLSetPriority(const android::renderscript::Context *rsc,
+ int32_t priority);
#endif
diff --git a/libs/rs/driver/rsdMesh.cpp b/libs/rs/driver/rsdMesh.cpp
index eb62ddb6a845..50daf3eec693 100644
--- a/libs/rs/driver/rsdMesh.cpp
+++ b/libs/rs/driver/rsdMesh.cpp
@@ -35,7 +35,7 @@ bool rsdMeshInit(const Context *rsc, const Mesh *m) {
}
drv = new RsdMeshObj(rsc, m);
m->mHal.drv = drv;
- return drv->init();
+ return drv->init(rsc);
}
void rsdMeshDraw(const Context *rsc, const Mesh *m, uint32_t primIndex, uint32_t start, uint32_t len) {
diff --git a/libs/rs/driver/rsdMeshObj.cpp b/libs/rs/driver/rsdMeshObj.cpp
index 99d79dceda79..893f046f8e0b 100644
--- a/libs/rs/driver/rsdMeshObj.cpp
+++ b/libs/rs/driver/rsdMeshObj.cpp
@@ -50,14 +50,9 @@ RsdMeshObj::~RsdMeshObj() {
}
bool RsdMeshObj::isValidGLComponent(const Element *elem, uint32_t fieldIdx) {
- // Do not create attribs for padding
- if (elem->getFieldName(fieldIdx)[0] == '#') {
- return false;
- }
-
// Only GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_FIXED, GL_FLOAT are accepted.
// Filter rs types accordingly
- RsDataType dt = elem->getField(fieldIdx)->getComponent().getType();
+ RsDataType dt = elem->mHal.state.fields[fieldIdx]->mHal.state.dataType;
if (dt != RS_TYPE_FLOAT_32 && dt != RS_TYPE_UNSIGNED_8 &&
dt != RS_TYPE_UNSIGNED_16 && dt != RS_TYPE_SIGNED_8 &&
dt != RS_TYPE_SIGNED_16) {
@@ -65,7 +60,7 @@ bool RsdMeshObj::isValidGLComponent(const Element *elem, uint32_t fieldIdx) {
}
// Now make sure they are not arrays
- uint32_t arraySize = elem->getFieldArraySize(fieldIdx);
+ uint32_t arraySize = elem->mHal.state.fieldArraySizes[fieldIdx];
if (arraySize != 1) {
return false;
}
@@ -73,15 +68,15 @@ bool RsdMeshObj::isValidGLComponent(const Element *elem, uint32_t fieldIdx) {
return true;
}
-bool RsdMeshObj::init() {
+bool RsdMeshObj::init(const Context *rsc) {
- updateGLPrimitives();
+ updateGLPrimitives(rsc);
// Count the number of gl attrs to initialize
mAttribCount = 0;
for (uint32_t ct=0; ct < mRSMesh->mHal.state.vertexBuffersCount; ct++) {
const Element *elem = mRSMesh->mHal.state.vertexBuffers[ct]->getType()->getElement();
- for (uint32_t ct=0; ct < elem->getFieldCount(); ct++) {
+ for (uint32_t ct=0; ct < elem->mHal.state.fieldsCount; ct++) {
if (isValidGLComponent(elem, ct)) {
mAttribCount ++;
}
@@ -104,21 +99,21 @@ bool RsdMeshObj::init() {
uint32_t userNum = 0;
for (uint32_t ct=0; ct < mRSMesh->mHal.state.vertexBuffersCount; ct++) {
const Element *elem = mRSMesh->mHal.state.vertexBuffers[ct]->getType()->getElement();
- uint32_t stride = elem->getSizeBytes();
- for (uint32_t fieldI=0; fieldI < elem->getFieldCount(); fieldI++) {
- const Component &c = elem->getField(fieldI)->getComponent();
+ uint32_t stride = elem->mHal.state.elementSizeBytes;
+ for (uint32_t fieldI=0; fieldI < elem->mHal.state.fieldsCount; fieldI++) {
+ const Element *f = elem->mHal.state.fields[fieldI];
if (!isValidGLComponent(elem, fieldI)) {
continue;
}
- mAttribs[userNum].size = c.getVectorSize();
- mAttribs[userNum].offset = elem->getFieldOffsetBytes(fieldI);
- mAttribs[userNum].type = rsdTypeToGLType(c.getType());
- mAttribs[userNum].normalized = c.getType() != RS_TYPE_FLOAT_32;//c.getIsNormalized();
+ mAttribs[userNum].size = f->mHal.state.vectorSize;
+ mAttribs[userNum].offset = elem->mHal.state.fieldOffsetBytes[fieldI];
+ mAttribs[userNum].type = rsdTypeToGLType(f->mHal.state.dataType);
+ mAttribs[userNum].normalized = f->mHal.state.dataType != RS_TYPE_FLOAT_32;
mAttribs[userNum].stride = stride;
String8 tmp(RS_SHADER_ATTR);
- tmp.append(elem->getFieldName(fieldI));
+ tmp.append(elem->mHal.state.fieldNames[fieldI]);
mAttribs[userNum].name.setTo(tmp.string());
// Remember which allocation this attribute came from
@@ -133,7 +128,7 @@ bool RsdMeshObj::init() {
void RsdMeshObj::renderPrimitiveRange(const Context *rsc, uint32_t primIndex,
uint32_t start, uint32_t len) const {
if (len < 1 || primIndex >= mRSMesh->mHal.state.primitivesCount || mAttribCount == 0) {
- ALOGE("Invalid mesh or parameters");
+ rsc->setError(RS_ERROR_FATAL_DRIVER, "Invalid mesh or parameters");
return;
}
@@ -186,7 +181,7 @@ void RsdMeshObj::renderPrimitiveRange(const Context *rsc, uint32_t primIndex,
rsdGLCheckError(rsc, "Mesh::renderPrimitiveRange");
}
-void RsdMeshObj::updateGLPrimitives() {
+void RsdMeshObj::updateGLPrimitives(const Context *rsc) {
mGLPrimitives = new uint32_t[mRSMesh->mHal.state.primitivesCount];
for (uint32_t i = 0; i < mRSMesh->mHal.state.primitivesCount; i ++) {
switch (mRSMesh->mHal.state.primitives[i]) {
@@ -196,6 +191,7 @@ void RsdMeshObj::updateGLPrimitives() {
case RS_PRIMITIVE_TRIANGLE: mGLPrimitives[i] = GL_TRIANGLES; break;
case RS_PRIMITIVE_TRIANGLE_STRIP: mGLPrimitives[i] = GL_TRIANGLE_STRIP; break;
case RS_PRIMITIVE_TRIANGLE_FAN: mGLPrimitives[i] = GL_TRIANGLE_FAN; break;
+ default: rsc->setError(RS_ERROR_FATAL_DRIVER, "Invalid mesh primitive"); break;
}
}
}
diff --git a/libs/rs/driver/rsdMeshObj.h b/libs/rs/driver/rsdMeshObj.h
index 8b1271baeaf7..1370f0106bd0 100644
--- a/libs/rs/driver/rsdMeshObj.h
+++ b/libs/rs/driver/rsdMeshObj.h
@@ -37,15 +37,16 @@ public:
const android::renderscript::Mesh *);
~RsdMeshObj();
- void renderPrimitiveRange(const android::renderscript::Context *, uint32_t primIndex, uint32_t start, uint32_t len) const;
+ void renderPrimitiveRange(const android::renderscript::Context *,
+ uint32_t primIndex, uint32_t start, uint32_t len) const;
- bool init();
+ bool init(const android::renderscript::Context *rsc);
protected:
const android::renderscript::Mesh *mRSMesh;
uint32_t *mGLPrimitives;
- void updateGLPrimitives();
+ void updateGLPrimitives(const android::renderscript::Context *rsc);
bool isValidGLComponent(const android::renderscript::Element *elem, uint32_t fieldIdx);
// Attribues that allow us to map to GL
diff --git a/libs/rs/driver/rsdPath.cpp b/libs/rs/driver/rsdPath.cpp
new file mode 100644
index 000000000000..e04bc0258ed1
--- /dev/null
+++ b/libs/rs/driver/rsdPath.cpp
@@ -0,0 +1,185 @@
+/*
+ * 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.
+ */
+
+#include <GLES/gl.h>
+#include <GLES2/gl2.h>
+#include <GLES/glext.h>
+
+#include <rs_hal.h>
+#include <rsContext.h>
+#include <rsPath.h>
+
+#include "rsdCore.h"
+#include "rsdPath.h"
+#include "rsdAllocation.h"
+#include "rsdGL.h"
+#include "rsdVertexArray.h"
+#include "rsdShaderCache.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+class DrvPath {
+protected:
+ DrvPath();
+public:
+ virtual ~DrvPath();
+ virtual void draw(Context *) = 0;
+};
+
+class DrvPathStatic : public DrvPath {
+public:
+ typedef struct {
+ float x1, xc, x2;
+ float y1, yc, y2;
+ } segment_t;
+
+ segment_t *mSegments;
+ uint32_t mSegmentCount;
+
+ DrvPathStatic(const Allocation *vtx, const Allocation *loops);
+ virtual ~DrvPathStatic();
+
+ virtual void draw(Context *);
+};
+
+class DrvPathDynamic : public DrvPath {
+public:
+ DrvPathDynamic();
+ virtual ~DrvPathDynamic();
+};
+
+static void cleanup(const Context *rsc, const Path *m) {
+ DrvPath *dp = (DrvPath *)m->mHal.drv;
+ if (dp) {
+ delete dp;
+ }
+}
+
+bool rsdPathInitStatic(const Context *rsc, const Path *m,
+ const Allocation *vtx, const Allocation *loops) {
+ DrvPathStatic *drv = NULL;
+ cleanup(rsc, m);
+
+ DrvPathStatic *dps = new DrvPathStatic(vtx, loops);
+ //LOGE("init path m %p, %p", m, dps);
+ m->mHal.drv = dps;
+ return dps != NULL;
+}
+
+bool rsdPathInitDynamic(const Context *rsc, const Path *m) {
+ return false;
+}
+
+
+void rsdPathDraw(const Context *rsc, const Path *m) {
+ //LOGE("render m=%p", m);
+
+ DrvPath *drv = (DrvPath *)m->mHal.drv;
+ if(drv) {
+ //LOGE("render 2 drv=%p", drv);
+ drv->draw((Context *)rsc);
+ }
+}
+
+void rsdPathDestroy(const Context *rsc, const Path *m) {
+ cleanup(rsc, m);
+ m->mHal.drv = NULL;
+}
+
+
+
+
+DrvPath::DrvPath() {
+}
+
+DrvPath::~DrvPath() {
+}
+
+DrvPathStatic::DrvPathStatic(const Allocation *vtx, const Allocation *loops) {
+ mSegmentCount = vtx->getType()->getDimX() / 3;
+ mSegments = new segment_t[mSegmentCount];
+
+ const float *fin = (const float *)vtx->getPtr();
+ for (uint32_t ct=0; ct < mSegmentCount; ct++) {
+ segment_t *s = &mSegments[ct];
+ s->x1 = fin[0];
+ s->y1 = fin[1];
+
+ s->xc = fin[2];
+ s->yc = fin[3];
+
+ s->x2 = fin[4];
+ s->y2 = fin[5];
+ fin += 6;
+ }
+}
+
+DrvPathStatic::~DrvPathStatic() {
+}
+
+void DrvPathStatic::draw(Context *rsc) {
+ const static float color[24] = {
+ 1.f, 0.f, 0.f, 1.f, 0.5f, 0.f, 0.f, 1.f,
+ 1.f, 0.f, 0.f, 1.f, 0.5f, 0.f, 0.f, 1.f,
+ 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f};
+ float vtx[12];
+
+ //LOGE("draw");
+ if (!rsc->setupCheck()) {
+ return;
+ }
+
+ RsdHal *dc = (RsdHal *)rsc->mHal.drv;
+ if (!dc->gl.shaderCache->setup(rsc)) {
+ return;
+ }
+
+ RsdVertexArray::Attrib attribs[2];
+ attribs[0].set(GL_FLOAT, 2, 8, false, (uint32_t)vtx, "ATTRIB_position");
+ attribs[1].set(GL_FLOAT, 4, 16, false, (uint32_t)color, "ATTRIB_color");
+ RsdVertexArray va(attribs, 2);
+ va.setup(rsc);
+
+ //LOGE("mSegmentCount %i", mSegmentCount);
+ for (uint32_t ct=0; ct < mSegmentCount; ct++) {
+ segment_t *s = &mSegments[ct];
+
+ vtx[0] = s->x1;
+ vtx[1] = s->y1;
+ vtx[2] = s->xc;
+ vtx[3] = s->yc;
+
+ vtx[4] = s->x2;
+ vtx[5] = s->y2;
+ vtx[6] = s->xc;
+ vtx[7] = s->yc;
+
+ vtx[8] = s->x1;
+ vtx[9] = s->y1;
+ vtx[10] = s->x2;
+ vtx[11] = s->y2;
+
+ RSD_CALL_GL(glDrawArrays, GL_LINES, 0, 6);
+ }
+
+}
+
+DrvPathDynamic::DrvPathDynamic() {
+}
+
+DrvPathDynamic::~DrvPathDynamic() {
+}
diff --git a/libs/rs/driver/rsdPath.h b/libs/rs/driver/rsdPath.h
new file mode 100644
index 000000000000..fa0097245e35
--- /dev/null
+++ b/libs/rs/driver/rsdPath.h
@@ -0,0 +1,35 @@
+/*
+ * 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 RSD_PATH_H
+#define RSD_PATH_H
+
+#include <rs_hal.h>
+
+
+bool rsdPathInitStatic(const android::renderscript::Context *rsc,
+ const android::renderscript::Path *m,
+ const android::renderscript::Allocation *vertex,
+ const android::renderscript::Allocation *loops);
+bool rsdPathInitDynamic(const android::renderscript::Context *rsc,
+ const android::renderscript::Path *m);
+void rsdPathDraw(const android::renderscript::Context *rsc,
+ const android::renderscript::Path *m);
+void rsdPathDestroy(const android::renderscript::Context *rsc,
+ const android::renderscript::Path *m);
+
+
+#endif
diff --git a/libs/rs/driver/rsdProgramRaster.cpp b/libs/rs/driver/rsdProgramRaster.cpp
index b4937594ba4d..e5a029132d3b 100644
--- a/libs/rs/driver/rsdProgramRaster.cpp
+++ b/libs/rs/driver/rsdProgramRaster.cpp
@@ -45,6 +45,9 @@ void rsdProgramRasterSetActive(const Context *rsc, const ProgramRaster *pr) {
case RS_CULL_NONE:
RSD_CALL_GL(glDisable, GL_CULL_FACE);
break;
+ default:
+ rsc->setError(RS_ERROR_FATAL_DRIVER, "Invalid cull type");
+ break;
}
}
diff --git a/libs/rs/driver/rsdProgramStore.cpp b/libs/rs/driver/rsdProgramStore.cpp
index fca9ba9e11e8..c1295e8b1d86 100644
--- a/libs/rs/driver/rsdProgramStore.cpp
+++ b/libs/rs/driver/rsdProgramStore.cpp
@@ -111,7 +111,7 @@ bool rsdProgramStoreInit(const Context *rsc, const ProgramStore *ps) {
drv->blendSrc = GL_SRC_ALPHA_SATURATE;
break;
default:
- ALOGE("Unknown blend src mode.");
+ rsc->setError(RS_ERROR_FATAL_DRIVER, "Unknown blend src mode.");
goto error;
}
@@ -141,7 +141,7 @@ bool rsdProgramStoreInit(const Context *rsc, const ProgramStore *ps) {
drv->blendDst = GL_ONE_MINUS_DST_ALPHA;
break;
default:
- ALOGE("Unknown blend dst mode.");
+ rsc->setError(RS_ERROR_FATAL_DRIVER, "Unknown blend dst mode.");
goto error;
}
diff --git a/libs/rs/driver/rsdRuntimeStubs.cpp b/libs/rs/driver/rsdRuntimeStubs.cpp
index 14c297004f44..44bfb1c8fe9f 100644
--- a/libs/rs/driver/rsdRuntimeStubs.cpp
+++ b/libs/rs/driver/rsdRuntimeStubs.cpp
@@ -25,6 +25,7 @@
#include "rsdCore.h"
#include "rsdRuntime.h"
+#include "rsdPath.h"
#include <time.h>
@@ -89,6 +90,16 @@ static void SC_BindTexture(ProgramFragment *pf, uint32_t slot, Allocation *a) {
rsrBindTexture(rsc, sc, pf, slot, a);
}
+static void SC_BindVertexConstant(ProgramVertex *pv, uint32_t slot, Allocation *a) {
+ GET_TLS();
+ rsrBindConstant(rsc, sc, pv, slot, a);
+}
+
+static void SC_BindFragmentConstant(ProgramFragment *pf, uint32_t slot, Allocation *a) {
+ GET_TLS();
+ rsrBindConstant(rsc, sc, pf, slot, a);
+}
+
static void SC_BindSampler(ProgramFragment *pf, uint32_t slot, Sampler *s) {
GET_TLS();
rsrBindSampler(rsc, sc, pf, slot, s);
@@ -204,6 +215,12 @@ static void SC_DrawRect(float x1, float y1, float x2, float y2, float z) {
rsrDrawRect(rsc, sc, x1, y1, x2, y2, z);
}
+static void SC_DrawPath(Path *p) {
+ GET_TLS();
+ //rsrDrawPath(rsc, sc, p);
+ rsdPathDraw(rsc, p);
+}
+
static void SC_DrawMesh(Mesh *m) {
GET_TLS();
rsrDrawMesh(rsc, sc, m);
@@ -533,6 +550,10 @@ static RsdSymbolTable gSyms[] = {
{ "_Z13rsClearObjectP9rs_script", (void *)&SC_ClearObject, true },
{ "_Z10rsIsObject9rs_script", (void *)&SC_IsObject, true },
+ { "_Z11rsSetObjectP7rs_pathS_", (void *)&SC_SetObject, true },
+ { "_Z13rsClearObjectP7rs_path", (void *)&SC_ClearObject, true },
+ { "_Z10rsIsObject7rs_path", (void *)&SC_IsObject, true },
+
{ "_Z11rsSetObjectP7rs_meshS_", (void *)&SC_SetObject, true },
{ "_Z13rsClearObjectP7rs_mesh", (void *)&SC_ClearObject, true },
{ "_Z10rsIsObject7rs_mesh", (void *)&SC_IsObject, true },
@@ -580,6 +601,8 @@ static RsdSymbolTable gSyms[] = {
{ "_Z20rsgBindProgramRaster17rs_program_raster", (void *)&SC_BindProgramRaster, false },
{ "_Z14rsgBindSampler19rs_program_fragmentj10rs_sampler", (void *)&SC_BindSampler, false },
{ "_Z14rsgBindTexture19rs_program_fragmentj13rs_allocation", (void *)&SC_BindTexture, false },
+ { "_Z15rsgBindConstant19rs_program_fragmentj13rs_allocation", (void *)&SC_BindFragmentConstant, false },
+ { "_Z15rsgBindConstant17rs_program_vertexj13rs_allocation", (void *)&SC_BindVertexConstant, false },
{ "_Z36rsgProgramVertexLoadProjectionMatrixPK12rs_matrix4x4", (void *)&SC_VpLoadProjectionMatrix, false },
{ "_Z31rsgProgramVertexLoadModelMatrixPK12rs_matrix4x4", (void *)&SC_VpLoadModelMatrix, false },
@@ -603,6 +626,8 @@ static RsdSymbolTable gSyms[] = {
{ "_Z11rsgDrawMesh7rs_meshjjj", (void *)&SC_DrawMeshPrimitiveRange, false },
{ "_Z25rsgMeshComputeBoundingBox7rs_meshPfS0_S0_S0_S0_S0_", (void *)&SC_MeshComputeBoundingBox, false },
+ { "_Z11rsgDrawPath7rs_path", (void *)&SC_DrawPath, false },
+
{ "_Z13rsgClearColorffff", (void *)&SC_ClearColor, false },
{ "_Z13rsgClearDepthf", (void *)&SC_ClearDepth, false },
diff --git a/libs/rs/driver/rsdShader.cpp b/libs/rs/driver/rsdShader.cpp
index 482f3b8bfc9a..3bca794ea9d6 100644
--- a/libs/rs/driver/rsdShader.cpp
+++ b/libs/rs/driver/rsdShader.cpp
@@ -90,12 +90,12 @@ String8 RsdShader::getGLSLInputString() const {
String8 s;
for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
const Element *e = mRSProgram->mHal.state.inputElements[ct];
- for (uint32_t field=0; field < e->getFieldCount(); field++) {
- const Element *f = e->getField(field);
+ for (uint32_t field=0; field < e->mHal.state.fieldsCount; field++) {
+ const Element *f = e->mHal.state.fields[field];
// Cannot be complex
- rsAssert(!f->getFieldCount());
- switch (f->getComponent().getVectorSize()) {
+ rsAssert(!f->mHal.state.fieldsCount);
+ switch (f->mHal.state.vectorSize) {
case 1: s.append("attribute float ATTRIB_"); break;
case 2: s.append("attribute vec2 ATTRIB_"); break;
case 3: s.append("attribute vec3 ATTRIB_"); break;
@@ -104,7 +104,7 @@ String8 RsdShader::getGLSLInputString() const {
rsAssert(0);
}
- s.append(e->getFieldName(field));
+ s.append(e->mHal.state.fieldNames[field]);
s.append(";\n");
}
}
@@ -114,17 +114,13 @@ String8 RsdShader::getGLSLInputString() const {
void RsdShader::appendAttributes() {
for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
const Element *e = mRSProgram->mHal.state.inputElements[ct];
- for (uint32_t field=0; field < e->getFieldCount(); field++) {
- const Element *f = e->getField(field);
- const char *fn = e->getFieldName(field);
-
- if (fn[0] == '#') {
- continue;
- }
+ for (uint32_t field=0; field < e->mHal.state.fieldsCount; field++) {
+ const Element *f = e->mHal.state.fields[field];
+ const char *fn = e->mHal.state.fieldNames[field];
// Cannot be complex
- rsAssert(!f->getFieldCount());
- switch (f->getComponent().getVectorSize()) {
+ rsAssert(!f->mHal.state.fieldsCount);
+ switch (f->mHal.state.vectorSize) {
case 1: mShader.append("attribute float ATTRIB_"); break;
case 2: mShader.append("attribute vec2 ATTRIB_"); break;
case 3: mShader.append("attribute vec3 ATTRIB_"); break;
@@ -195,12 +191,11 @@ bool RsdShader::loadShader(const Context *rsc) {
char* buf = (char*) malloc(infoLen);
if (buf) {
RSD_CALL_GL(glGetShaderInfoLog, mShaderID, infoLen, NULL, buf);
- ALOGE("Could not compile shader \n%s\n", buf);
+ rsc->setError(RS_ERROR_FATAL_PROGRAM_LINK, buf);
free(buf);
}
RSD_CALL_GL(glDeleteShader, mShaderID);
mShaderID = 0;
- rsc->setError(RS_ERROR_BAD_SHADER, "Error returned from GL driver loading shader text,");
return false;
}
}
@@ -216,24 +211,20 @@ bool RsdShader::loadShader(const Context *rsc) {
void RsdShader::appendUserConstants() {
for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
const Element *e = mRSProgram->mHal.state.constantTypes[ct]->getElement();
- for (uint32_t field=0; field < e->getFieldCount(); field++) {
- const Element *f = e->getField(field);
- const char *fn = e->getFieldName(field);
-
- if (fn[0] == '#') {
- continue;
- }
+ for (uint32_t field=0; field < e->mHal.state.fieldsCount; field++) {
+ const Element *f = e->mHal.state.fields[field];
+ const char *fn = e->mHal.state.fieldNames[field];
// Cannot be complex
- rsAssert(!f->getFieldCount());
- if (f->getType() == RS_TYPE_MATRIX_4X4) {
+ rsAssert(!f->mHal.state.fieldsCount);
+ if (f->mHal.state.dataType == RS_TYPE_MATRIX_4X4) {
mShader.append("uniform mat4 UNI_");
- } else if (f->getType() == RS_TYPE_MATRIX_3X3) {
+ } else if (f->mHal.state.dataType == RS_TYPE_MATRIX_3X3) {
mShader.append("uniform mat3 UNI_");
- } else if (f->getType() == RS_TYPE_MATRIX_2X2) {
+ } else if (f->mHal.state.dataType == RS_TYPE_MATRIX_2X2) {
mShader.append("uniform mat2 UNI_");
} else {
- switch (f->getComponent().getVectorSize()) {
+ switch (f->mHal.state.vectorSize) {
case 1: mShader.append("uniform float UNI_"); break;
case 2: mShader.append("uniform vec2 UNI_"); break;
case 3: mShader.append("uniform vec3 UNI_"); break;
@@ -244,8 +235,8 @@ void RsdShader::appendUserConstants() {
}
mShader.append(fn);
- if (e->getFieldArraySize(field) > 1) {
- mShader.appendFormat("[%d]", e->getFieldArraySize(field));
+ if (e->mHal.state.fieldArraySizes[field] > 1) {
+ mShader.appendFormat("[%d]", e->mHal.state.fieldArraySizes[field]);
}
mShader.append(";\n");
}
@@ -253,8 +244,8 @@ void RsdShader::appendUserConstants() {
}
void RsdShader::logUniform(const Element *field, const float *fd, uint32_t arraySize ) {
- RsDataType dataType = field->getType();
- uint32_t elementSize = field->getSizeBytes() / sizeof(float);
+ RsDataType dataType = field->mHal.state.dataType;
+ uint32_t elementSize = field->mHal.state.elementSizeBytes / sizeof(float);
for (uint32_t i = 0; i < arraySize; i ++) {
if (arraySize > 1) {
ALOGV("Array Element [%u]", i);
@@ -275,7 +266,7 @@ void RsdShader::logUniform(const Element *field, const float *fd, uint32_t array
ALOGV("{%f, %f", fd[0], fd[2]);
ALOGV(" %f, %f}", fd[1], fd[3]);
} else {
- switch (field->getComponent().getVectorSize()) {
+ switch (field->mHal.state.vectorSize) {
case 1:
ALOGV("Uniform 1 = %f", fd[0]);
break;
@@ -300,7 +291,7 @@ void RsdShader::logUniform(const Element *field, const float *fd, uint32_t array
void RsdShader::setUniform(const Context *rsc, const Element *field, const float *fd,
int32_t slot, uint32_t arraySize ) {
- RsDataType dataType = field->getType();
+ RsDataType dataType = field->mHal.state.dataType;
if (dataType == RS_TYPE_MATRIX_4X4) {
RSD_CALL_GL(glUniformMatrix4fv, slot, arraySize, GL_FALSE, fd);
} else if (dataType == RS_TYPE_MATRIX_3X3) {
@@ -308,7 +299,7 @@ void RsdShader::setUniform(const Context *rsc, const Element *field, const float
} else if (dataType == RS_TYPE_MATRIX_2X2) {
RSD_CALL_GL(glUniformMatrix2fv, slot, arraySize, GL_FALSE, fd);
} else {
- switch (field->getComponent().getVectorSize()) {
+ switch (field->mHal.state.vectorSize) {
case 1:
RSD_CALL_GL(glUniform1fv, slot, arraySize, fd);
break;
@@ -463,15 +454,11 @@ void RsdShader::setupUserConstants(const Context *rsc, RsdShaderCache *sc, bool
const uint8_t *data = static_cast<const uint8_t *>(alloc->getPtr());
const Element *e = mRSProgram->mHal.state.constantTypes[ct]->getElement();
- for (uint32_t field=0; field < e->getFieldCount(); field++) {
- const Element *f = e->getField(field);
- const char *fieldName = e->getFieldName(field);
- // If this field is padding, skip it
- if (fieldName[0] == '#') {
- continue;
- }
+ for (uint32_t field=0; field < e->mHal.state.fieldsCount; field++) {
+ const Element *f = e->mHal.state.fields[field];
+ const char *fieldName = e->mHal.state.fieldNames[field];
- uint32_t offset = e->getFieldOffsetBytes(field);
+ uint32_t offset = e->mHal.state.fieldOffsetBytes[field];
const float *fd = reinterpret_cast<const float *>(&data[offset]);
int32_t slot = -1;
@@ -510,22 +497,13 @@ void RsdShader::initAttribAndUniformArray() {
mAttribCount = 0;
for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
const Element *elem = mRSProgram->mHal.state.inputElements[ct];
- for (uint32_t field=0; field < elem->getFieldCount(); field++) {
- if (elem->getFieldName(field)[0] != '#') {
- mAttribCount ++;
- }
- }
+ mAttribCount += elem->mHal.state.fieldsCount;
}
mUniformCount = 0;
for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
const Element *elem = mRSProgram->mHal.state.constantTypes[ct]->getElement();
-
- for (uint32_t field=0; field < elem->getFieldCount(); field++) {
- if (elem->getFieldName(field)[0] != '#') {
- mUniformCount ++;
- }
- }
+ mUniformCount += elem->mHal.state.fieldsCount;
}
mUniformCount += mRSProgram->mHal.state.texturesCount;
@@ -545,17 +523,17 @@ void RsdShader::initAttribAndUniformArray() {
void RsdShader::initAddUserElement(const Element *e, String8 *names, uint32_t *arrayLengths,
uint32_t *count, const char *prefix) {
- rsAssert(e->getFieldCount());
- for (uint32_t ct=0; ct < e->getFieldCount(); ct++) {
- const Element *ce = e->getField(ct);
- if (ce->getFieldCount()) {
+ rsAssert(e->mHal.state.fieldsCount);
+ for (uint32_t ct=0; ct < e->mHal.state.fieldsCount; ct++) {
+ const Element *ce = e->mHal.state.fields[ct];
+ if (ce->mHal.state.fieldsCount) {
initAddUserElement(ce, names, arrayLengths, count, prefix);
- } else if (e->getFieldName(ct)[0] != '#') {
+ } else {
String8 tmp(prefix);
- tmp.append(e->getFieldName(ct));
+ tmp.append(e->mHal.state.fieldNames[ct]);
names[*count].setTo(tmp.string());
if (arrayLengths) {
- arrayLengths[*count] = e->getFieldArraySize(ct);
+ arrayLengths[*count] = e->mHal.state.fieldArraySizes[ct];
}
(*count)++;
}
diff --git a/libs/rs/driver/rsdShaderCache.cpp b/libs/rs/driver/rsdShaderCache.cpp
index f6236e794a07..89d3c45177fa 100644
--- a/libs/rs/driver/rsdShaderCache.cpp
+++ b/libs/rs/driver/rsdShaderCache.cpp
@@ -167,12 +167,11 @@ bool RsdShaderCache::link(const Context *rsc) {
char* buf = (char*) malloc(bufLength);
if (buf) {
glGetProgramInfoLog(pgm, bufLength, NULL, buf);
- ALOGE("Could not link program:\n%s\n", buf);
+ rsc->setError(RS_ERROR_FATAL_PROGRAM_LINK, buf);
free(buf);
}
}
glDeleteProgram(pgm);
- rsc->setError(RS_ERROR_FATAL_PROGRAM_LINK, "Error linking GL Programs");
return false;
}
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index 09a29863f30b..6759bc7bb271 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -42,6 +42,7 @@ AllocationCreateTyped {
param RsType vtype
param RsAllocationMipmapControl mips
param uint32_t usages
+ param uint32_t ptr
ret RsAllocation
}
@@ -392,3 +393,13 @@ MeshCreate {
param uint32_t *primType
ret RsMesh
}
+
+PathCreate {
+ param RsPathPrimitive pp
+ param bool isStatic
+ param RsAllocation vertex
+ param RsAllocation loops
+ param float quality
+ ret RsPath
+ }
+
diff --git a/libs/rs/rsAllocation.cpp b/libs/rs/rsAllocation.cpp
index 5f45abff2b9c..02c680939de3 100644
--- a/libs/rs/rsAllocation.cpp
+++ b/libs/rs/rsAllocation.cpp
@@ -22,21 +22,22 @@ using namespace android;
using namespace android::renderscript;
Allocation::Allocation(Context *rsc, const Type *type, uint32_t usages,
- RsAllocationMipmapControl mc)
+ RsAllocationMipmapControl mc, void * ptr)
: ObjectBase(rsc) {
memset(&mHal, 0, sizeof(mHal));
mHal.state.mipmapControl = RS_ALLOCATION_MIPMAP_NONE;
mHal.state.usageFlags = usages;
mHal.state.mipmapControl = mc;
+ mHal.state.usrPtr = ptr;
setType(type);
updateCache();
}
Allocation * Allocation::createAllocation(Context *rsc, const Type *type, uint32_t usages,
- RsAllocationMipmapControl mc) {
- Allocation *a = new Allocation(rsc, type, usages, mc);
+ RsAllocationMipmapControl mc, void * ptr) {
+ Allocation *a = new Allocation(rsc, type, usages, mc, ptr);
if (!rsc->mHal.funcs.allocation.init(rsc, a, type->getElement()->getHasReferences())) {
rsc->setError(RS_ERROR_FATAL_DRIVER, "Allocation::Allocation, alloc failure");
@@ -577,8 +578,8 @@ static void AllocationGenerateScriptMips(RsContext con, RsAllocation va) {
RsAllocation rsi_AllocationCreateTyped(Context *rsc, RsType vtype,
RsAllocationMipmapControl mips,
- uint32_t usages) {
- Allocation * alloc = Allocation::createAllocation(rsc, static_cast<Type *>(vtype), usages, mips);
+ uint32_t usages, uint32_t ptr) {
+ Allocation * alloc = Allocation::createAllocation(rsc, static_cast<Type *>(vtype), usages, mips, (void *)ptr);
if (!alloc) {
return NULL;
}
@@ -591,7 +592,7 @@ RsAllocation rsi_AllocationCreateFromBitmap(Context *rsc, RsType vtype,
const void *data, size_t data_length, uint32_t usages) {
Type *t = static_cast<Type *>(vtype);
- RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, vtype, mips, usages);
+ RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, vtype, mips, usages, 0);
Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc);
if (texAlloc == NULL) {
ALOGE("Memory allocation failure");
@@ -615,7 +616,7 @@ RsAllocation rsi_AllocationCubeCreateFromBitmap(Context *rsc, RsType vtype,
// Cubemap allocation's faces should be Width by Width each.
// Source data should have 6 * Width by Width pixels
// Error checking is done in the java layer
- RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, vtype, mips, usages);
+ RsAllocation vTexAlloc = rsi_AllocationCreateTyped(rsc, vtype, mips, usages, 0);
Allocation *texAlloc = static_cast<Allocation *>(vTexAlloc);
if (texAlloc == NULL) {
ALOGE("Memory allocation failure");
diff --git a/libs/rs/rsAllocation.h b/libs/rs/rsAllocation.h
index a26d8355bc2f..58a582b75866 100644
--- a/libs/rs/rsAllocation.h
+++ b/libs/rs/rsAllocation.h
@@ -68,7 +68,8 @@ public:
Hal mHal;
static Allocation * createAllocation(Context *rsc, const Type *, uint32_t usages,
- RsAllocationMipmapControl mc = RS_ALLOCATION_MIPMAP_NONE);
+ RsAllocationMipmapControl mc = RS_ALLOCATION_MIPMAP_NONE,
+ void *ptr = 0);
virtual ~Allocation();
void updateCache();
@@ -137,7 +138,7 @@ protected:
private:
void freeChildrenUnlocked();
- Allocation(Context *rsc, const Type *, uint32_t usages, RsAllocationMipmapControl mc);
+ Allocation(Context *rsc, const Type *, uint32_t usages, RsAllocationMipmapControl mc, void *ptr);
uint32_t getPackedSize() const;
static void writePackedData(const Type *type, uint8_t *dst, const uint8_t *src, bool dstPadded);
diff --git a/libs/rs/rsComponent.cpp b/libs/rs/rsComponent.cpp
index 21b98f6193a2..9c2c2005f38d 100644
--- a/libs/rs/rsComponent.cpp
+++ b/libs/rs/rsComponent.cpp
@@ -62,6 +62,7 @@ void Component::set(RsDataType dt, RsDataKind dk, bool norm, uint32_t vecSize) {
rsAssert(mNormalized == true);
break;
default:
+ rsAssert(mKind != RS_KIND_INVALID);
break;
}
@@ -167,6 +168,9 @@ void Component::set(RsDataType dt, RsDataKind dk, bool norm, uint32_t vecSize) {
case RS_TYPE_BOOLEAN:
mTypeBits = 8;
break;
+ default:
+ rsAssert(mType != RS_TYPE_INVALID);
+ break;
}
mBitsUnpadded = mTypeBits * mVectorSize;
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index 1a34bd588aa6..adaefc6017bf 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -361,6 +361,7 @@ void Context::setPriority(int32_t p) {
#else
setpriority(PRIO_PROCESS, mNativeThreadId, p);
#endif
+ mHal.funcs.setPriority(this, mThreadPriority);
}
Context::Context() {
diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h
index a844a20cfc6e..05c799e4a5cc 100644
--- a/libs/rs/rsContext.h
+++ b/libs/rs/rsContext.h
@@ -32,6 +32,7 @@
#include "rsAdapter.h"
#include "rsSampler.h"
#include "rsFont.h"
+#include "rsPath.h"
#include "rsProgramFragment.h"
#include "rsProgramStore.h"
#include "rsProgramRaster.h"
diff --git a/libs/rs/rsElement.cpp b/libs/rs/rsElement.cpp
index dff958532538..fb2892ce0f97 100644
--- a/libs/rs/rsElement.cpp
+++ b/libs/rs/rsElement.cpp
@@ -27,6 +27,7 @@ Element::Element(Context *rsc) : ObjectBase(rsc) {
mFields = NULL;
mFieldCount = 0;
mHasReference = false;
+ memset(&mHal, 0, sizeof(mHal));
}
Element::~Element() {
@@ -47,6 +48,12 @@ void Element::clear() {
mFields = NULL;
mFieldCount = 0;
mHasReference = false;
+
+ delete [] mHal.state.fields;
+ delete [] mHal.state.fieldArraySizes;
+ delete [] mHal.state.fieldNames;
+ delete [] mHal.state.fieldNameLengths;
+ delete [] mHal.state.fieldOffsetBytes;
}
size_t Element::getSizeBits() const {
@@ -157,16 +164,36 @@ Element *Element::createFromStream(Context *rsc, IStream *stream) {
}
void Element::compute() {
+ mHal.state.dataType = mComponent.getType();
+ mHal.state.dataKind = mComponent.getKind();
+ mHal.state.vectorSize = mComponent.getVectorSize();
+
if (mFieldCount == 0) {
mBits = mComponent.getBits();
mBitsUnpadded = mComponent.getBitsUnpadded();
mHasReference = mComponent.isReference();
+
+ mHal.state.elementSizeBytes = getSizeBytes();
return;
}
+ uint32_t noPaddingFieldCount = 0;
+ for (uint32_t ct = 0; ct < mFieldCount; ct ++) {
+ if (mFields[ct].name.string()[0] != '#') {
+ noPaddingFieldCount ++;
+ }
+ }
+
+ mHal.state.fields = new const Element*[noPaddingFieldCount];
+ mHal.state.fieldArraySizes = new uint32_t[noPaddingFieldCount];
+ mHal.state.fieldNames = new const char*[noPaddingFieldCount];
+ mHal.state.fieldNameLengths = new uint32_t[noPaddingFieldCount];
+ mHal.state.fieldOffsetBytes = new uint32_t[noPaddingFieldCount];
+ mHal.state.fieldsCount = noPaddingFieldCount;
+
size_t bits = 0;
size_t bitsUnpadded = 0;
- for (size_t ct=0; ct < mFieldCount; ct++) {
+ for (size_t ct = 0, ctNoPadding = 0; ct < mFieldCount; ct++) {
mFields[ct].offsetBits = bits;
mFields[ct].offsetBitsUnpadded = bitsUnpadded;
bits += mFields[ct].e->getSizeBits() * mFields[ct].arraySize;
@@ -175,8 +202,21 @@ void Element::compute() {
if (mFields[ct].e->mHasReference) {
mHasReference = true;
}
+
+ if (mFields[ct].name.string()[0] == '#') {
+ continue;
+ }
+
+ mHal.state.fields[ctNoPadding] = mFields[ct].e.get();
+ mHal.state.fieldArraySizes[ctNoPadding] = mFields[ct].arraySize;
+ mHal.state.fieldNames[ctNoPadding] = mFields[ct].name.string();
+ mHal.state.fieldNameLengths[ctNoPadding] = mFields[ct].name.length() + 1; // to include 0
+ mHal.state.fieldOffsetBytes[ctNoPadding] = mFields[ct].offsetBits >> 3;
+
+ ctNoPadding ++;
}
+ mHal.state.elementSizeBytes = getSizeBytes();
}
ObjectBaseRef<const Element> Element::createRef(Context *rsc, RsDataType dt, RsDataKind dk,
diff --git a/libs/rs/rsElement.h b/libs/rs/rsElement.h
index 04010faafac8..4b6b46016e3f 100644
--- a/libs/rs/rsElement.h
+++ b/libs/rs/rsElement.h
@@ -24,10 +24,38 @@
// ---------------------------------------------------------------------------
namespace android {
namespace renderscript {
-
+/*****************************************************************************
+ * CAUTION
+ *
+ * Any layout changes for this class may require a corresponding change to be
+ * made to frameworks/compile/libbcc/lib/ScriptCRT/rs_core.c, which contains
+ * a partial copy of the information below.
+ *
+ *****************************************************************************/
// An element is a group of Components that occupies one cell in a structure.
class Element : public ObjectBase {
public:
+ struct Hal {
+ mutable void *drv;
+
+ struct State {
+ RsDataType dataType;
+ RsDataKind dataKind;
+ uint32_t vectorSize;
+ uint32_t elementSizeBytes;
+
+ // Subelements
+ const Element **fields;
+ uint32_t *fieldArraySizes;
+ const char **fieldNames;
+ uint32_t *fieldNameLengths;
+ uint32_t *fieldOffsetBytes;
+ uint32_t fieldsCount;
+ };
+ State state;
+ };
+ Hal mHal;
+
class Builder {
public:
Builder();
diff --git a/libs/rs/rsMesh.h b/libs/rs/rsMesh.h
index 0fc73fba5c95..166b5d3e27c2 100644
--- a/libs/rs/rsMesh.h
+++ b/libs/rs/rsMesh.h
@@ -23,20 +23,18 @@
// ---------------------------------------------------------------------------
namespace android {
namespace renderscript {
-
+/*****************************************************************************
+ * CAUTION
+ *
+ * Any layout changes for this class may require a corresponding change to be
+ * made to frameworks/compile/libbcc/lib/ScriptCRT/rs_core.c, which contains
+ * a partial copy of the information below.
+ *
+ *****************************************************************************/
// An element is a group of Components that occupies one cell in a structure.
class Mesh : public ObjectBase {
public:
- Mesh(Context *);
- Mesh(Context *, uint32_t vertexBuffersCount, uint32_t primitivesCount);
- ~Mesh();
-
- virtual void serialize(OStream *stream) const;
- virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_MESH; }
- static Mesh *createFromStream(Context *rsc, IStream *stream);
- void init();
-
struct Hal {
mutable void *drv;
@@ -57,6 +55,15 @@ public:
};
Hal mHal;
+ Mesh(Context *);
+ Mesh(Context *, uint32_t vertexBuffersCount, uint32_t primitivesCount);
+ ~Mesh();
+
+ virtual void serialize(OStream *stream) const;
+ virtual RsA3DClassID getClassId() const { return RS_A3D_CLASS_ID_MESH; }
+ static Mesh *createFromStream(Context *rsc, IStream *stream);
+ void init();
+
void setVertexBuffer(Allocation *vb, uint32_t index) {
mVertexBuffers[index].set(vb);
mHal.state.vertexBuffers[index] = vb;
diff --git a/libs/rs/rsPath.cpp b/libs/rs/rsPath.cpp
new file mode 100644
index 000000000000..c4f49789bfdc
--- /dev/null
+++ b/libs/rs/rsPath.cpp
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+#include "rsContext.h"
+
+using namespace android;
+using namespace android::renderscript;
+
+
+Path::Path(Context *rsc) : ObjectBase(rsc) {
+}
+
+Path::Path(Context *rsc, RsPathPrimitive pp, bool isStatic,
+ Allocation *vtx, Allocation *loops, float quality)
+: ObjectBase(rsc) {
+
+ memset(&mHal, 0, sizeof(mHal));
+ mHal.state.quality = quality;
+ mHal.state.primitive = pp;
+
+ //LOGE("i1");
+ rsc->mHal.funcs.path.initStatic(rsc, this, vtx, loops);
+
+ //LOGE("i2");
+}
+
+Path::Path(Context *rsc, uint32_t vertexBuffersCount, uint32_t primitivesCount)
+: ObjectBase(rsc) {
+
+}
+
+Path::~Path() {
+
+}
+
+
+void Path::rasterize(const BezierSegment_t *s, uint32_t num, Allocation *alloc) {
+
+ for (uint32_t i=0; i < num; i++) {
+
+ }
+
+}
+
+void Path::render(Context *rsc) {
+}
+
+void Path::serialize(OStream *stream) const {
+
+}
+
+RsA3DClassID Path::getClassId() const {
+ return RS_A3D_CLASS_ID_UNKNOWN;
+}
+
+namespace android {
+namespace renderscript {
+
+RsPath rsi_PathCreate(Context *rsc, RsPathPrimitive pp, bool isStatic,
+ RsAllocation vtx, RsAllocation loops, float quality) {
+ return new Path(rsc, pp, isStatic, (Allocation *)vtx, (Allocation *)loops, quality);
+}
+
+}
+}
diff --git a/libs/rs/rsPath.h b/libs/rs/rsPath.h
new file mode 100644
index 000000000000..dac795ef44b3
--- /dev/null
+++ b/libs/rs/rsPath.h
@@ -0,0 +1,69 @@
+/*
+ * 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 ANDROID_RS_PATH_H
+#define ANDROID_RS_PATH_H
+
+
+#include "RenderScript.h"
+
+// ---------------------------------------------------------------------------
+namespace android {
+namespace renderscript {
+
+class Path : public ObjectBase {
+public:
+ struct {
+ mutable void * drv;
+
+ struct State {
+ RsPathPrimitive primitive;
+ float quality;
+ };
+ State state;
+ } mHal;
+
+ Path(Context *);
+ Path(Context *, uint32_t vertexBuffersCount, uint32_t primitivesCount);
+ Path(Context *, RsPathPrimitive pp, bool isStatic, Allocation *vtx, Allocation *loop, float q);
+
+ ~Path();
+
+ void render(Context *);
+ virtual void serialize(OStream *stream) const;
+ virtual RsA3DClassID getClassId() const;
+
+private:
+
+
+ typedef struct {
+ float x[4];
+ float y[4];
+ } BezierSegment_t;
+
+ bool subdivideCheck(const BezierSegment_t *s, float u1, float u2);
+
+ void rasterize(const BezierSegment_t *s, uint32_t num, Allocation *alloc);
+
+
+};
+
+}
+}
+#endif //ANDROID_RS_PATH_H
+
+
+
diff --git a/libs/rs/rsRuntime.h b/libs/rs/rsRuntime.h
index cb962a815dc3..3bded620e0d3 100644
--- a/libs/rs/rsRuntime.h
+++ b/libs/rs/rsRuntime.h
@@ -30,6 +30,8 @@ namespace renderscript {
//////////////////////////////////////////////////////////////////////////////
void rsrBindTexture(Context *, Script *, ProgramFragment *, uint32_t slot, Allocation *);
+void rsrBindConstant(Context *, Script *, ProgramFragment *, uint32_t slot, Allocation *);
+void rsrBindConstant(Context *, Script *, ProgramVertex*, uint32_t slot, Allocation *);
void rsrBindSampler(Context *, Script *, ProgramFragment *, uint32_t slot, Sampler *);
void rsrBindProgramStore(Context *, Script *, ProgramStore *);
void rsrBindProgramFragment(Context *, Script *, ProgramFragment *);
@@ -68,6 +70,7 @@ void rsrDrawQuad(Context *, Script *,
void rsrDrawSpriteScreenspace(Context *, Script *,
float x, float y, float z, float w, float h);
void rsrDrawRect(Context *, Script *, float x1, float y1, float x2, float y2, float z);
+void rsrDrawPath(Context *, Script *, Path *);
void rsrDrawMesh(Context *, Script *, Mesh *);
void rsrDrawMeshPrimitive(Context *, Script *, Mesh *, uint32_t primIndex);
void rsrDrawMeshPrimitiveRange(Context *, Script *, Mesh *,
diff --git a/libs/rs/rsScriptC_LibGL.cpp b/libs/rs/rsScriptC_LibGL.cpp
index 79647922d5c1..97469d370553 100644
--- a/libs/rs/rsScriptC_LibGL.cpp
+++ b/libs/rs/rsScriptC_LibGL.cpp
@@ -50,6 +50,18 @@ void rsrBindTexture(Context *rsc, Script *sc, ProgramFragment *pf, uint32_t slot
pf->bindTexture(rsc, slot, a);
}
+void rsrBindConstant(Context *rsc, Script *sc, ProgramFragment *pf, uint32_t slot, Allocation *a) {
+ CHECK_OBJ_OR_NULL(a);
+ CHECK_OBJ(pf);
+ pf->bindAllocation(rsc, a, slot);
+}
+
+void rsrBindConstant(Context *rsc, Script *sc, ProgramVertex *pv, uint32_t slot, Allocation *a) {
+ CHECK_OBJ_OR_NULL(a);
+ CHECK_OBJ(pv);
+ pv->bindAllocation(rsc, a, slot);
+}
+
void rsrBindSampler(Context *rsc, Script *sc, ProgramFragment *pf, uint32_t slot, Sampler *s) {
CHECK_OBJ_OR_NULL(vs);
CHECK_OBJ(vpf);
@@ -200,6 +212,14 @@ void rsrDrawRect(Context *rsc, Script *sc, float x1, float y1, float x2, float y
rsrDrawQuad(rsc, sc, x1, y2, z, x2, y2, z, x2, y1, z, x1, y1, z);
}
+void rsrDrawPath(Context *rsc, Script *sc, Path *sm) {
+ CHECK_OBJ(sm);
+ if (!rsc->setupCheck()) {
+ return;
+ }
+ sm->render(rsc);
+}
+
void rsrDrawMesh(Context *rsc, Script *sc, Mesh *sm) {
CHECK_OBJ(sm);
if (!rsc->setupCheck()) {
diff --git a/libs/rs/rsType.cpp b/libs/rs/rsType.cpp
index 79664700b908..70ab7b7ca297 100644
--- a/libs/rs/rsType.cpp
+++ b/libs/rs/rsType.cpp
@@ -46,12 +46,8 @@ void Type::clear() {
delete [] mLODs;
mLODs = NULL;
}
- mDimX = 0;
- mDimY = 0;
- mDimZ = 0;
- mDimLOD = 0;
- mFaces = false;
mElement.clear();
+ memset(&mHal, 0, sizeof(mHal));
}
TypeState::TypeState() {
@@ -62,16 +58,16 @@ TypeState::~TypeState() {
}
size_t Type::getOffsetForFace(uint32_t face) const {
- rsAssert(mFaces);
+ rsAssert(mHal.state.faces);
return 0;
}
void Type::compute() {
uint32_t oldLODCount = mLODCount;
- if (mDimLOD) {
- uint32_t l2x = rsFindHighBit(mDimX) + 1;
- uint32_t l2y = rsFindHighBit(mDimY) + 1;
- uint32_t l2z = rsFindHighBit(mDimZ) + 1;
+ if (mHal.state.dimLOD) {
+ uint32_t l2x = rsFindHighBit(mHal.state.dimX) + 1;
+ uint32_t l2y = rsFindHighBit(mHal.state.dimY) + 1;
+ uint32_t l2z = rsFindHighBit(mHal.state.dimZ) + 1;
mLODCount = rsMax(l2x, l2y);
mLODCount = rsMax(mLODCount, l2z);
@@ -85,9 +81,9 @@ void Type::compute() {
mLODs = new LOD[mLODCount];
}
- uint32_t tx = mDimX;
- uint32_t ty = mDimY;
- uint32_t tz = mDimZ;
+ uint32_t tx = mHal.state.dimX;
+ uint32_t ty = mHal.state.dimY;
+ uint32_t tz = mHal.state.dimZ;
size_t offset = 0;
for (uint32_t lod=0; lod < mLODCount; lod++) {
mLODs[lod].mX = tx;
@@ -103,10 +99,11 @@ void Type::compute() {
// At this point the offset is the size of a mipmap chain;
mMipChainSizeBytes = offset;
- if (mFaces) {
+ if (mHal.state.faces) {
offset *= 6;
}
mTotalSizeBytes = offset;
+ mHal.state.element = mElement.get();
}
uint32_t Type::getLODOffset(uint32_t lod, uint32_t x) const {
@@ -127,7 +124,8 @@ uint32_t Type::getLODOffset(uint32_t lod, uint32_t x, uint32_t y, uint32_t z) co
return offset;
}
-uint32_t Type::getLODFaceOffset(uint32_t lod, RsAllocationCubemapFace face, uint32_t x, uint32_t y) const {
+uint32_t Type::getLODFaceOffset(uint32_t lod, RsAllocationCubemapFace face,
+ uint32_t x, uint32_t y) const {
uint32_t offset = mLODs[lod].mOffset;
offset += (x + y * mLODs[lod].mX) * mElement->getSizeBytes();
@@ -141,7 +139,12 @@ uint32_t Type::getLODFaceOffset(uint32_t lod, RsAllocationCubemapFace face, uint
void Type::dumpLOGV(const char *prefix) const {
char buf[1024];
ObjectBase::dumpLOGV(prefix);
- ALOGV("%s Type: x=%zu y=%zu z=%zu mip=%i face=%i", prefix, mDimX, mDimY, mDimZ, mDimLOD, mFaces);
+ ALOGV("%s Type: x=%u y=%u z=%u mip=%i face=%i", prefix,
+ mHal.state.dimX,
+ mHal.state.dimY,
+ mHal.state.dimZ,
+ mHal.state.dimLOD,
+ mHal.state.faces);
snprintf(buf, sizeof(buf), "%s element: ", prefix);
mElement->dumpLOGV(buf);
}
@@ -155,12 +158,12 @@ void Type::serialize(OStream *stream) const {
mElement->serialize(stream);
- stream->addU32(mDimX);
- stream->addU32(mDimY);
- stream->addU32(mDimZ);
+ stream->addU32(mHal.state.dimX);
+ stream->addU32(mHal.state.dimY);
+ stream->addU32(mHal.state.dimZ);
- stream->addU8((uint8_t)(mDimLOD ? 1 : 0));
- stream->addU8((uint8_t)(mFaces ? 1 : 0));
+ stream->addU8((uint8_t)(mHal.state.dimLOD ? 1 : 0));
+ stream->addU8((uint8_t)(mHal.state.faces ? 1 : 0));
}
Type *Type::createFromStream(Context *rsc, IStream *stream) {
@@ -232,11 +235,11 @@ ObjectBaseRef<Type> Type::getTypeRef(Context *rsc, const Element *e,
Type *nt = new Type(rsc);
returnRef.set(nt);
nt->mElement.set(e);
- nt->mDimX = dimX;
- nt->mDimY = dimY;
- nt->mDimZ = dimZ;
- nt->mDimLOD = dimLOD;
- nt->mFaces = dimFaces;
+ nt->mHal.state.dimX = dimX;
+ nt->mHal.state.dimY = dimY;
+ nt->mHal.state.dimZ = dimZ;
+ nt->mHal.state.dimLOD = dimLOD;
+ nt->mHal.state.faces = dimFaces;
nt->compute();
ObjectBase::asyncLock();
@@ -248,14 +251,14 @@ ObjectBaseRef<Type> Type::getTypeRef(Context *rsc, const Element *e,
ObjectBaseRef<Type> Type::cloneAndResize1D(Context *rsc, uint32_t dimX) const {
return getTypeRef(rsc, mElement.get(), dimX,
- mDimY, mDimZ, mDimLOD, mFaces);
+ mHal.state.dimY, mHal.state.dimZ, mHal.state.dimLOD, mHal.state.faces);
}
ObjectBaseRef<Type> Type::cloneAndResize2D(Context *rsc,
uint32_t dimX,
uint32_t dimY) const {
return getTypeRef(rsc, mElement.get(), dimX, dimY,
- mDimZ, mDimLOD, mFaces);
+ mHal.state.dimZ, mHal.state.dimLOD, mHal.state.faces);
}
@@ -276,8 +279,8 @@ RsType rsi_TypeCreate(Context *rsc, RsElement _e, uint32_t dimX,
void rsaTypeGetNativeData(RsContext con, RsType type, uint32_t *typeData, uint32_t typeDataSize) {
rsAssert(typeDataSize == 6);
- // Pack the data in the follofing way mDimX; mDimY; mDimZ;
- // mDimLOD; mDimFaces; mElement; into typeData
+ // Pack the data in the follofing way mHal.state.dimX; mHal.state.dimY; mHal.state.dimZ;
+ // mHal.state.dimLOD; mHal.state.faces; mElement; into typeData
Type *t = static_cast<Type *>(type);
(*typeData++) = t->getDimX();
diff --git a/libs/rs/rsType.h b/libs/rs/rsType.h
index bc0d9ffdbe46..3878156a2191 100644
--- a/libs/rs/rsType.h
+++ b/libs/rs/rsType.h
@@ -22,10 +22,35 @@
// ---------------------------------------------------------------------------
namespace android {
namespace renderscript {
-
+/*****************************************************************************
+ * CAUTION
+ *
+ * Any layout changes for this class may require a corresponding change to be
+ * made to frameworks/compile/libbcc/lib/ScriptCRT/rs_core.c, which contains
+ * a partial copy of the information below.
+ *
+ *****************************************************************************/
class Type : public ObjectBase {
public:
+ struct Hal {
+ mutable void *drv;
+
+ struct State {
+ const Element * element;
+
+ // Size of the structure in the various dimensions. A missing Dimension is
+ // specified as a 0 and not a 1.
+ uint32_t dimX;
+ uint32_t dimY;
+ uint32_t dimZ;
+ bool dimLOD;
+ bool faces;
+ };
+ State state;
+ };
+ Hal mHal;
+
Type * createTex2D(const Element *, size_t w, size_t h, bool mip);
size_t getOffsetForFace(uint32_t face) const;
@@ -34,22 +59,25 @@ public:
size_t getElementSizeBytes() const {return mElement->getSizeBytes();}
const Element * getElement() const {return mElement.get();}
- uint32_t getDimX() const {return mDimX;}
- uint32_t getDimY() const {return mDimY;}
- uint32_t getDimZ() const {return mDimZ;}
- uint32_t getDimLOD() const {return mDimLOD;}
- bool getDimFaces() const {return mFaces;}
+ uint32_t getDimX() const {return mHal.state.dimX;}
+ uint32_t getDimY() const {return mHal.state.dimY;}
+ uint32_t getDimZ() const {return mHal.state.dimZ;}
+ uint32_t getDimLOD() const {return mHal.state.dimLOD;}
+ bool getDimFaces() const {return mHal.state.faces;}
uint32_t getLODDimX(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mX;}
uint32_t getLODDimY(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mY;}
uint32_t getLODDimZ(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mZ;}
- uint32_t getLODOffset(uint32_t lod) const {rsAssert(lod < mLODCount); return mLODs[lod].mOffset;}
+ uint32_t getLODOffset(uint32_t lod) const {
+ rsAssert(lod < mLODCount); return mLODs[lod].mOffset;
+ }
uint32_t getLODOffset(uint32_t lod, uint32_t x) const;
uint32_t getLODOffset(uint32_t lod, uint32_t x, uint32_t y) const;
uint32_t getLODOffset(uint32_t lod, uint32_t x, uint32_t y, uint32_t z) const;
- uint32_t getLODFaceOffset(uint32_t lod, RsAllocationCubemapFace face, uint32_t x, uint32_t y) const;
+ uint32_t getLODFaceOffset(uint32_t lod, RsAllocationCubemapFace face,
+ uint32_t x, uint32_t y) const;
uint32_t getLODCount() const {return mLODCount;}
bool getIsNp2() const;
@@ -95,14 +123,6 @@ protected:
ObjectBaseRef<const Element> mElement;
- // Size of the structure in the various dimensions. A missing Dimension is
- // specified as a 0 and not a 1.
- size_t mDimX;
- size_t mDimY;
- size_t mDimZ;
- bool mDimLOD;
- bool mFaces;
-
// count of mipmap levels, 0 indicates no mipmapping
size_t mMipChainSizeBytes;
diff --git a/libs/rs/rs_hal.h b/libs/rs/rs_hal.h
index 0afc94b99e9b..1e222e1664cf 100644
--- a/libs/rs/rs_hal.h
+++ b/libs/rs/rs_hal.h
@@ -29,6 +29,7 @@ class Type;
class Allocation;
class Script;
class ScriptC;
+class Path;
class Program;
class ProgramStore;
class ProgramRaster;
@@ -190,6 +191,13 @@ typedef struct {
} mesh;
struct {
+ bool (*initStatic)(const Context *rsc, const Path *m, const Allocation *vtx, const Allocation *loops);
+ bool (*initDynamic)(const Context *rsc, const Path *m);
+ void (*draw)(const Context *rsc, const Path *m);
+ void (*destroy)(const Context *rsc, const Path *m);
+ } path;
+
+ struct {
bool (*init)(const Context *rsc, const Sampler *m);
void (*destroy)(const Context *rsc, const Sampler *m);
} sampler;
diff --git a/libs/rs/scriptc/rs_allocation.rsh b/libs/rs/scriptc/rs_allocation.rsh
index 9ec03bf840ca..a2f69d9942d0 100644
--- a/libs/rs/scriptc/rs_allocation.rsh
+++ b/libs/rs/scriptc/rs_allocation.rsh
@@ -168,5 +168,135 @@ extern const void * __attribute__((overloadable))
extern const void * __attribute__((overloadable))
rsGetElementAt(rs_allocation, uint32_t x, uint32_t y, uint32_t z);
+/**
+ * @param a allocation to get data from
+ * @return element describing allocation layout
+ */
+extern rs_element __attribute__((overloadable))
+ rsAllocationGetElement(rs_allocation a);
+
+/**
+ * @param m mesh to get data from
+ * @return number of allocations in the mesh that contain vertex
+ * data
+ */
+extern uint32_t __attribute__((overloadable))
+ rsMeshGetVertexAllocationCount(rs_mesh m);
+
+/**
+ * @param m mesh to get data from
+ * @return number of primitive groups in the mesh. This would
+ * include simple primitives as well as allocations
+ * containing index data
+ */
+extern uint32_t __attribute__((overloadable))
+ rsMeshGetPrimitiveCount(rs_mesh m);
+
+/**
+ * @param m mesh to get data from
+ * @param index index of the vertex allocation
+ * @return allocation containing vertex data
+ */
+extern rs_allocation __attribute__((overloadable))
+ rsMeshGetVertexAllocation(rs_mesh m, uint32_t index);
+
+/**
+ * @param m mesh to get data from
+ * @param index index of the index allocation
+ * @return allocation containing index data
+ */
+extern rs_allocation __attribute__((overloadable))
+ rsMeshGetIndexAllocation(rs_mesh m, uint32_t index);
+
+/**
+ * @param m mesh to get data from
+ * @param index index of the primitive
+ * @return primitive describing how the mesh is rendered
+ */
+extern rs_primitive __attribute__((overloadable))
+ rsMeshGetPrimitive(rs_mesh m, uint32_t index);
+
+/**
+ * @param e element to get data from
+ * @return number of sub-elements in this element
+ */
+extern uint32_t __attribute__((overloadable))
+ rsElementGetSubElementCount(rs_element e);
+
+/**
+ * @param e element to get data from
+ * @param index index of the sub-element to return
+ * @return sub-element in this element at given index
+ */
+extern rs_element __attribute__((overloadable))
+ rsElementGetSubElement(rs_element, uint32_t index);
+
+/**
+ * @param e element to get data from
+ * @param index index of the sub-element to return
+ * @return length of the sub-element name including the null
+ * terminator (size of buffer needed to write the name)
+ */
+extern uint32_t __attribute__((overloadable))
+ rsElementGetSubElementNameLength(rs_element e, uint32_t index);
+
+/**
+ * @param e element to get data from
+ * @param index index of the sub-element
+ * @param name array to store the name into
+ * @param nameLength length of the provided name array
+ * @return number of characters actually written, excluding the
+ * null terminator
+ */
+extern uint32_t __attribute__((overloadable))
+ rsElementGetSubElementName(rs_element e, uint32_t index, char *name, uint32_t nameLength);
+
+/**
+ * @param e element to get data from
+ * @param index index of the sub-element
+ * @return array size of sub-element in this element at given
+ * index
+ */
+extern uint32_t __attribute__((overloadable))
+ rsElementGetSubElementArraySize(rs_element e, uint32_t index);
+
+/**
+ * @param e element to get data from
+ * @param index index of the sub-element
+ * @return offset in bytes of sub-element in this element at
+ * given index
+ */
+extern uint32_t __attribute__((overloadable))
+ rsElementGetSubElementOffsetBytes(rs_element e, uint32_t index);
+
+/**
+ * @param e element to get data from
+ * @return total size of the element in bytes
+ */
+extern uint32_t __attribute__((overloadable))
+ rsElementGetSizeBytes(rs_element e);
+
+/**
+ * @param e element to get data from
+ * @return element's data type
+ */
+extern rs_data_type __attribute__((overloadable))
+ rsElementGetDataType(rs_element e);
+
+/**
+ * @param e element to get data from
+ * @return element's data size
+ */
+extern rs_data_kind __attribute__((overloadable))
+ rsElementGetDataKind(rs_element e);
+
+/**
+ * @param e element to get data from
+ * @return length of the element vector (for float2, float3,
+ * etc.)
+ */
+extern uint32_t __attribute__((overloadable))
+ rsElementGetVectorSize(rs_element e);
+
#endif
diff --git a/libs/rs/scriptc/rs_graphics.rsh b/libs/rs/scriptc/rs_graphics.rsh
index 25819537e26b..7fdebdcd0468 100644
--- a/libs/rs/scriptc/rs_graphics.rsh
+++ b/libs/rs/scriptc/rs_graphics.rsh
@@ -22,6 +22,66 @@
*/
#ifndef __RS_GRAPHICS_RSH__
#define __RS_GRAPHICS_RSH__
+
+// These are API 15 once it get official
+typedef enum {
+ RS_DEPTH_FUNC_ALWAYS,
+ RS_DEPTH_FUNC_LESS,
+ RS_DEPTH_FUNC_LEQUAL,
+ RS_DEPTH_FUNC_GREATER,
+ RS_DEPTH_FUNC_GEQUAL,
+ RS_DEPTH_FUNC_EQUAL,
+ RS_DEPTH_FUNC_NOTEQUAL,
+
+ RS_DEPTH_FUNC_INVALID = 100,
+} rs_depth_func;
+
+typedef enum {
+ RS_BLEND_SRC_ZERO, // 0
+ RS_BLEND_SRC_ONE, // 1
+ RS_BLEND_SRC_DST_COLOR, // 2
+ RS_BLEND_SRC_ONE_MINUS_DST_COLOR, // 3
+ RS_BLEND_SRC_SRC_ALPHA, // 4
+ RS_BLEND_SRC_ONE_MINUS_SRC_ALPHA, // 5
+ RS_BLEND_SRC_DST_ALPHA, // 6
+ RS_BLEND_SRC_ONE_MINUS_DST_ALPHA, // 7
+ RS_BLEND_SRC_SRC_ALPHA_SATURATE, // 8
+
+ RS_BLEND_SRC_INVALID = 100,
+} rs_blend_src_func;
+
+typedef enum {
+ RS_BLEND_DST_ZERO, // 0
+ RS_BLEND_DST_ONE, // 1
+ RS_BLEND_DST_SRC_COLOR, // 2
+ RS_BLEND_DST_ONE_MINUS_SRC_COLOR, // 3
+ RS_BLEND_DST_SRC_ALPHA, // 4
+ RS_BLEND_DST_ONE_MINUS_SRC_ALPHA, // 5
+ RS_BLEND_DST_DST_ALPHA, // 6
+ RS_BLEND_DST_ONE_MINUS_DST_ALPHA, // 7
+
+ RS_BLEND_DST_INVALID = 100,
+} rs_blend_dst_func;
+
+typedef enum {
+ RS_CULL_BACK,
+ RS_CULL_FRONT,
+ RS_CULL_NONE,
+
+ RS_CULL_INVALID = 100,
+} rs_cull_mode;
+
+typedef enum {
+ RS_SAMPLER_NEAREST,
+ RS_SAMPLER_LINEAR,
+ RS_SAMPLER_LINEAR_MIP_LINEAR,
+ RS_SAMPLER_WRAP,
+ RS_SAMPLER_CLAMP,
+ RS_SAMPLER_LINEAR_MIP_NEAREST,
+
+ RS_SAMPLER_INVALID = 100,
+} rs_sampler_value;
+
#if (defined(RS_VERSION) && (RS_VERSION >= 14))
/**
* Set the color target used for all subsequent rendering calls
@@ -82,6 +142,88 @@ extern void __attribute__((overloadable))
extern void __attribute__((overloadable))
rsgBindProgramStore(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store depth function
+ *
+ * @param ps
+ */
+extern rs_depth_func __attribute__((overloadable))
+ rsgProgramStoreGetDepthFunc(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store depth mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+ rsgProgramStoreGetDepthMask(rs_program_store ps);
+/**
+ * @hide
+ * Get program store red component color mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+ rsgProgramStoreGetColorMaskR(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store green component color mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+ rsgProgramStoreGetColorMaskG(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store blur component color mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+ rsgProgramStoreGetColorMaskB(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store alpha component color mask
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+ rsgProgramStoreGetColorMaskA(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store blend source function
+ *
+ * @param ps
+ */
+extern rs_blend_src_func __attribute__((overloadable))
+ rsgProgramStoreGetBlendSrcFunc(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store blend destination function
+ *
+ * @param ps
+ */
+extern rs_blend_dst_func __attribute__((overloadable))
+ rsgProgramStoreGetBlendDstFunc(rs_program_store ps);
+
+/**
+ * @hide
+ * Get program store dither state
+ *
+ * @param ps
+ */
+extern bool __attribute__((overloadable))
+ rsgProgramStoreGetDitherEnabled(rs_program_store ps);
+
+
/**
* Bind a new ProgramVertex to the rendering context.
*
@@ -99,6 +241,24 @@ extern void __attribute__((overloadable))
rsgBindProgramRaster(rs_program_raster pr);
/**
+ * @hide
+ * Get program raster point sprite state
+ *
+ * @param pr
+ */
+extern bool __attribute__((overloadable))
+ rsgProgramRasterGetPointSpriteEnabled(rs_program_raster pr);
+
+/**
+ * @hide
+ * Get program raster cull mode
+ *
+ * @param pr
+ */
+extern rs_cull_mode __attribute__((overloadable))
+ rsgProgramRasterGetCullMode(rs_program_raster pr);
+
+/**
* Bind a new Sampler object to a ProgramFragment. The sampler will
* operate on the texture bound at the matching slot.
*
@@ -108,6 +268,51 @@ extern void __attribute__((overloadable))
rsgBindSampler(rs_program_fragment, uint slot, rs_sampler);
/**
+ * @hide
+ * Get sampler minification value
+ *
+ * @param pr
+ */
+extern rs_sampler_value __attribute__((overloadable))
+ rsgSamplerGetMinification(rs_sampler s);
+
+/**
+ * @hide
+ * Get sampler magnification value
+ *
+ * @param pr
+ */
+extern rs_sampler_value __attribute__((overloadable))
+ rsgSamplerGetMagnification(rs_sampler s);
+
+/**
+ * @hide
+ * Get sampler wrap S value
+ *
+ * @param pr
+ */
+extern rs_sampler_value __attribute__((overloadable))
+ rsgSamplerGetWrapS(rs_sampler s);
+
+/**
+ * @hide
+ * Get sampler wrap T value
+ *
+ * @param pr
+ */
+extern rs_sampler_value __attribute__((overloadable))
+ rsgSamplerGetWrapT(rs_sampler s);
+
+/**
+ * @hide
+ * Get sampler anisotropy
+ *
+ * @param pr
+ */
+extern float __attribute__((overloadable))
+ rsgSamplerGetAnisotropy(rs_sampler s);
+
+/**
* Bind a new Allocation object to a ProgramFragment. The
* Allocation must be a valid texture for the Program. The sampling
* of the texture will be controled by the Sampler bound at the
@@ -164,6 +369,28 @@ extern void __attribute__((overloadable))
rsgProgramFragmentConstantColor(rs_program_fragment pf, float r, float g, float b, float a);
/**
+ * Bind a new Allocation object to a ProgramFragment. The
+ * Allocation must be a valid constant input for the Program.
+ *
+ * @param ps program object
+ * @param slot index of the constant buffer on the program
+ * @param c constants to bind
+ */
+extern void __attribute__((overloadable))
+ rsgBindConstant(rs_program_fragment ps, uint slot, rs_allocation c);
+
+/**
+ * Bind a new Allocation object to a ProgramVertex. The
+ * Allocation must be a valid constant input for the Program.
+ *
+ * @param pv program object
+ * @param slot index of the constant buffer on the program
+ * @param c constants to bind
+ */
+extern void __attribute__((overloadable))
+ rsgBindConstant(rs_program_vertex pv, uint slot, rs_allocation c);
+
+/**
* Get the width of the current rendering surface.
*
* @return uint
@@ -288,6 +515,9 @@ extern void __attribute__((overloadable))
extern void __attribute__((overloadable))
rsgDrawSpriteScreenspace(float x, float y, float z, float w, float h);
+extern void __attribute__((overloadable))
+ rsgDrawPath(rs_path p);
+
/**
* Draw a mesh using the current context state. The whole mesh is
* rendered.
diff --git a/libs/rs/scriptc/rs_object.rsh b/libs/rs/scriptc/rs_object.rsh
index a43121937ea8..1fc3f83b49d6 100644
--- a/libs/rs/scriptc/rs_object.rsh
+++ b/libs/rs/scriptc/rs_object.rsh
@@ -56,6 +56,11 @@ extern void __attribute__((overloadable))
* \overload
*/
extern void __attribute__((overloadable))
+ rsSetObject(rs_path *dst, rs_path src);
+/**
+ * \overload
+ */
+extern void __attribute__((overloadable))
rsSetObject(rs_mesh *dst, rs_mesh src);
/**
* \overload
@@ -114,6 +119,11 @@ extern void __attribute__((overloadable))
* \overload
*/
extern void __attribute__((overloadable))
+ rsClearObject(rs_path *dst);
+/**
+ * \overload
+ */
+extern void __attribute__((overloadable))
rsClearObject(rs_mesh *dst);
/**
* \overload
@@ -175,6 +185,11 @@ extern bool __attribute__((overloadable))
* \overload
*/
extern bool __attribute__((overloadable))
+ rsIsObject(rs_path);
+/**
+ * \overload
+ */
+extern bool __attribute__((overloadable))
rsIsObject(rs_mesh);
/**
* \overload
diff --git a/libs/rs/scriptc/rs_types.rsh b/libs/rs/scriptc/rs_types.rsh
index 84bca9c8a7e5..5345a48ef895 100644
--- a/libs/rs/scriptc/rs_types.rsh
+++ b/libs/rs/scriptc/rs_types.rsh
@@ -138,6 +138,12 @@ typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_sc
*/
typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_mesh;
/**
+ * \brief Opaque handle to a Renderscript Path object.
+ *
+ * See: android.renderscript.Path
+ */
+typedef struct { const int* const p; } __attribute__((packed, aligned(4))) rs_path;
+/**
* \brief Opaque handle to a Renderscript ProgramFragment object.
*
* See: android.renderscript.ProgramFragment
@@ -396,4 +402,96 @@ typedef enum {
#endif //defined(RS_VERSION) && (RS_VERSION >= 14)
+/**
+ * Describes the way mesh vertex data is interpreted when rendering
+ *
+ **/
+typedef enum {
+ RS_PRIMITIVE_POINT,
+ RS_PRIMITIVE_LINE,
+ RS_PRIMITIVE_LINE_STRIP,
+ RS_PRIMITIVE_TRIANGLE,
+ RS_PRIMITIVE_TRIANGLE_STRIP,
+ RS_PRIMITIVE_TRIANGLE_FAN,
+
+ RS_PRIMITIVE_INVALID = 100,
+} rs_primitive;
+
+/**
+ * \brief Enumeration for possible element data types
+ *
+ * DataType represents the basic type information for a basic element. The
+ * naming convention follows. For numeric types it is FLOAT,
+ * SIGNED, or UNSIGNED followed by the _BITS where BITS is the
+ * size of the data. BOOLEAN is a true / false (1,0)
+ * represented in an 8 bit container. The UNSIGNED variants
+ * with multiple bit definitions are for packed graphical data
+ * formats and represent vectors with per vector member sizes
+ * which are treated as a single unit for packing and alignment
+ * purposes.
+ *
+ * MATRIX the three matrix types contain FLOAT_32 elements and are treated
+ * as 32 bits for alignment purposes.
+ *
+ * RS_* objects. 32 bit opaque handles.
+ */
+typedef enum {
+ RS_TYPE_NONE,
+ //RS_TYPE_FLOAT_16,
+ RS_TYPE_FLOAT_32 = 2,
+ RS_TYPE_FLOAT_64,
+ RS_TYPE_SIGNED_8,
+ RS_TYPE_SIGNED_16,
+ RS_TYPE_SIGNED_32,
+ RS_TYPE_SIGNED_64,
+ RS_TYPE_UNSIGNED_8,
+ RS_TYPE_UNSIGNED_16,
+ RS_TYPE_UNSIGNED_32,
+ RS_TYPE_UNSIGNED_64,
+
+ RS_TYPE_BOOLEAN,
+
+ RS_TYPE_UNSIGNED_5_6_5,
+ RS_TYPE_UNSIGNED_5_5_5_1,
+ RS_TYPE_UNSIGNED_4_4_4_4,
+
+ RS_TYPE_MATRIX_4X4,
+ RS_TYPE_MATRIX_3X3,
+ RS_TYPE_MATRIX_2X2,
+
+ RS_TYPE_ELEMENT = 1000,
+ RS_TYPE_TYPE,
+ RS_TYPE_ALLOCATION,
+ RS_TYPE_SAMPLER,
+ RS_TYPE_SCRIPT,
+ RS_TYPE_MESH,
+ RS_TYPE_PROGRAM_FRAGMENT,
+ RS_TYPE_PROGRAM_VERTEX,
+ RS_TYPE_PROGRAM_RASTER,
+ RS_TYPE_PROGRAM_STORE,
+
+ RS_TYPE_INVALID = 10000,
+} rs_data_type;
+
+/**
+ * \brief Enumeration for possible element data kind
+ *
+ * The special interpretation of the data if required. This is primarly
+ * useful for graphical data. USER indicates no special interpretation is
+ * expected. PIXEL is used in conjunction with the standard data types for
+ * representing texture formats.
+ */
+typedef enum {
+ RS_KIND_USER,
+
+ RS_KIND_PIXEL_L = 7,
+ RS_KIND_PIXEL_A,
+ RS_KIND_PIXEL_LA,
+ RS_KIND_PIXEL_RGB,
+ RS_KIND_PIXEL_RGBA,
+ RS_KIND_PIXEL_DEPTH,
+
+ RS_KIND_INVALID = 100,
+} rs_data_kind;
+
#endif
diff --git a/libs/ui/InputTransport.cpp b/libs/ui/InputTransport.cpp
index 09cbb318cd93..ecb3fb5c9870 100644
--- a/libs/ui/InputTransport.cpp
+++ b/libs/ui/InputTransport.cpp
@@ -7,325 +7,203 @@
//#define LOG_NDEBUG 0
-// Log debug messages about channel signalling (send signal, receive signal)
-#define DEBUG_CHANNEL_SIGNALS 0
+// Log debug messages about channel messages (send message, receive message)
+#define DEBUG_CHANNEL_MESSAGES 0
// Log debug messages whenever InputChannel objects are created/destroyed
#define DEBUG_CHANNEL_LIFECYCLE 0
-// Log debug messages about transport actions (initialize, reset, publish, ...)
+// Log debug messages about transport actions
#define DEBUG_TRANSPORT_ACTIONS 0
-#include <cutils/ashmem.h>
#include <cutils/log.h>
#include <errno.h>
#include <fcntl.h>
-#include <sys/mman.h>
#include <ui/InputTransport.h>
#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
-namespace android {
-
-#define ROUND_UP(value, boundary) (((value) + (boundary) - 1) & ~((boundary) - 1))
-#define MIN_HISTORY_DEPTH 20
-// Must be at least sizeof(InputMessage) + sufficient space for pointer data
-static const int DEFAULT_MESSAGE_BUFFER_SIZE = ROUND_UP(
- sizeof(InputMessage) + MIN_HISTORY_DEPTH
- * (sizeof(InputMessage::SampleData) + MAX_POINTERS * sizeof(PointerCoords)),
- 4096);
-
-// Signal sent by the producer to the consumer to inform it that a new message is
-// available to be consumed in the shared memory buffer.
-static const char INPUT_SIGNAL_DISPATCH = 'D';
+namespace android {
-// Signal sent by the consumer to the producer to inform it that it has finished
-// consuming the most recent message and it handled it.
-static const char INPUT_SIGNAL_FINISHED_HANDLED = 'f';
+// Socket buffer size. The default is typically about 128KB, which is much larger than
+// we really need. So we make it smaller. It just needs to be big enough to hold
+// a few dozen large multi-finger motion events in the case where an application gets
+// behind processing touches.
+static const size_t SOCKET_BUFFER_SIZE = 32 * 1024;
+
+
+// --- InputMessage ---
+
+bool InputMessage::isValid(size_t actualSize) const {
+ if (size() == actualSize) {
+ switch (header.type) {
+ case TYPE_KEY:
+ return true;
+ case TYPE_MOTION:
+ return body.motion.pointerCount > 0
+ && body.motion.pointerCount <= MAX_POINTERS;
+ case TYPE_FINISHED:
+ return true;
+ }
+ }
+ return false;
+}
-// Signal sent by the consumer to the producer to inform it that it has finished
-// consuming the most recent message but it did not handle it.
-static const char INPUT_SIGNAL_FINISHED_UNHANDLED = 'u';
+size_t InputMessage::size() const {
+ switch (header.type) {
+ case TYPE_KEY:
+ return sizeof(Header) + body.key.size();
+ case TYPE_MOTION:
+ return sizeof(Header) + body.motion.size();
+ case TYPE_FINISHED:
+ return sizeof(Header) + body.finished.size();
+ }
+ return sizeof(Header);
+}
// --- InputChannel ---
-InputChannel::InputChannel(const String8& name, int32_t ashmemFd, int32_t receivePipeFd,
- int32_t sendPipeFd) :
- mName(name), mAshmemFd(ashmemFd), mReceivePipeFd(receivePipeFd), mSendPipeFd(sendPipeFd) {
+InputChannel::InputChannel(const String8& name, int fd) :
+ mName(name), mFd(fd) {
#if DEBUG_CHANNEL_LIFECYCLE
- ALOGD("Input channel constructed: name='%s', ashmemFd=%d, receivePipeFd=%d, sendPipeFd=%d",
- mName.string(), ashmemFd, receivePipeFd, sendPipeFd);
+ ALOGD("Input channel constructed: name='%s', fd=%d",
+ mName.string(), fd);
#endif
- int result = fcntl(mReceivePipeFd, F_SETFL, O_NONBLOCK);
- LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make receive pipe "
- "non-blocking. errno=%d", mName.string(), errno);
-
- result = fcntl(mSendPipeFd, F_SETFL, O_NONBLOCK);
- LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make send pipe "
+ int result = fcntl(mFd, F_SETFL, O_NONBLOCK);
+ LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make socket "
"non-blocking. errno=%d", mName.string(), errno);
}
InputChannel::~InputChannel() {
#if DEBUG_CHANNEL_LIFECYCLE
- ALOGD("Input channel destroyed: name='%s', ashmemFd=%d, receivePipeFd=%d, sendPipeFd=%d",
- mName.string(), mAshmemFd, mReceivePipeFd, mSendPipeFd);
+ ALOGD("Input channel destroyed: name='%s', fd=%d",
+ mName.string(), mFd);
#endif
- ::close(mAshmemFd);
- ::close(mReceivePipeFd);
- ::close(mSendPipeFd);
+ ::close(mFd);
}
status_t InputChannel::openInputChannelPair(const String8& name,
sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
- status_t result;
-
- String8 ashmemName("InputChannel ");
- ashmemName.append(name);
- int serverAshmemFd = ashmem_create_region(ashmemName.string(), DEFAULT_MESSAGE_BUFFER_SIZE);
- if (serverAshmemFd < 0) {
- result = -errno;
- ALOGE("channel '%s' ~ Could not create shared memory region. errno=%d",
+ int sockets[2];
+ if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
+ status_t result = -errno;
+ ALOGE("channel '%s' ~ Could not create socket pair. errno=%d",
name.string(), errno);
- } else {
- result = ashmem_set_prot_region(serverAshmemFd, PROT_READ | PROT_WRITE);
- if (result < 0) {
- ALOGE("channel '%s' ~ Error %d trying to set protection of ashmem fd %d.",
- name.string(), result, serverAshmemFd);
- } else {
- // Dup the file descriptor because the server and client input channel objects that
- // are returned may have different lifetimes but they share the same shared memory region.
- int clientAshmemFd;
- clientAshmemFd = dup(serverAshmemFd);
- if (clientAshmemFd < 0) {
- result = -errno;
- ALOGE("channel '%s' ~ Could not dup() shared memory region fd. errno=%d",
- name.string(), errno);
- } else {
- int forward[2];
- if (pipe(forward)) {
- result = -errno;
- ALOGE("channel '%s' ~ Could not create forward pipe. errno=%d",
- name.string(), errno);
- } else {
- int reverse[2];
- if (pipe(reverse)) {
- result = -errno;
- ALOGE("channel '%s' ~ Could not create reverse pipe. errno=%d",
- name.string(), errno);
- } else {
- String8 serverChannelName = name;
- serverChannelName.append(" (server)");
- outServerChannel = new InputChannel(serverChannelName,
- serverAshmemFd, reverse[0], forward[1]);
-
- String8 clientChannelName = name;
- clientChannelName.append(" (client)");
- outClientChannel = new InputChannel(clientChannelName,
- clientAshmemFd, forward[0], reverse[1]);
- return OK;
- }
- ::close(forward[0]);
- ::close(forward[1]);
- }
- ::close(clientAshmemFd);
- }
- }
- ::close(serverAshmemFd);
+ outServerChannel.clear();
+ outClientChannel.clear();
+ return result;
}
- outServerChannel.clear();
- outClientChannel.clear();
- return result;
+ int bufferSize = SOCKET_BUFFER_SIZE;
+ setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
+ setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
+ setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
+ setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
+
+ String8 serverChannelName = name;
+ serverChannelName.append(" (server)");
+ outServerChannel = new InputChannel(serverChannelName, sockets[0]);
+
+ String8 clientChannelName = name;
+ clientChannelName.append(" (client)");
+ outClientChannel = new InputChannel(clientChannelName, sockets[1]);
+ return OK;
}
-status_t InputChannel::sendSignal(char signal) {
+status_t InputChannel::sendMessage(const InputMessage* msg) {
+ size_t msgLength = msg->size();
ssize_t nWrite;
do {
- nWrite = ::write(mSendPipeFd, & signal, 1);
+ nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
} while (nWrite == -1 && errno == EINTR);
- if (nWrite == 1) {
-#if DEBUG_CHANNEL_SIGNALS
- ALOGD("channel '%s' ~ sent signal '%c'", mName.string(), signal);
+ if (nWrite < 0) {
+ int error = errno;
+#if DEBUG_CHANNEL_MESSAGES
+ ALOGD("channel '%s' ~ error sending message of type %d, errno=%d", mName.string(),
+ msg->header.type, error);
#endif
- return OK;
+ if (error == EAGAIN || error == EWOULDBLOCK) {
+ return WOULD_BLOCK;
+ }
+ if (error == EPIPE || error == ENOTCONN) {
+ return DEAD_OBJECT;
+ }
+ return -error;
}
-#if DEBUG_CHANNEL_SIGNALS
- ALOGD("channel '%s' ~ error sending signal '%c', errno=%d", mName.string(), signal, errno);
+ if (size_t(nWrite) != msgLength) {
+#if DEBUG_CHANNEL_MESSAGES
+ ALOGD("channel '%s' ~ error sending message type %d, send was incomplete",
+ mName.string(), msg->header.type);
#endif
- return -errno;
+ return DEAD_OBJECT;
+ }
+
+#if DEBUG_CHANNEL_MESSAGES
+ ALOGD("channel '%s' ~ sent message of type %d", mName.string(), msg->header.type);
+#endif
+ return OK;
}
-status_t InputChannel::receiveSignal(char* outSignal) {
+status_t InputChannel::receiveMessage(InputMessage* msg) {
ssize_t nRead;
do {
- nRead = ::read(mReceivePipeFd, outSignal, 1);
+ nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT);
} while (nRead == -1 && errno == EINTR);
- if (nRead == 1) {
-#if DEBUG_CHANNEL_SIGNALS
- ALOGD("channel '%s' ~ received signal '%c'", mName.string(), *outSignal);
+ if (nRead < 0) {
+ int error = errno;
+#if DEBUG_CHANNEL_MESSAGES
+ ALOGD("channel '%s' ~ receive message failed, errno=%d", mName.string(), errno);
#endif
- return OK;
+ if (error == EAGAIN || error == EWOULDBLOCK) {
+ return WOULD_BLOCK;
+ }
+ if (error == EPIPE || error == ENOTCONN) {
+ return DEAD_OBJECT;
+ }
+ return -error;
}
if (nRead == 0) { // check for EOF
-#if DEBUG_CHANNEL_SIGNALS
- ALOGD("channel '%s' ~ receive signal failed because peer was closed", mName.string());
+#if DEBUG_CHANNEL_MESSAGES
+ ALOGD("channel '%s' ~ receive message failed because peer was closed", mName.string());
#endif
return DEAD_OBJECT;
}
- if (errno == EAGAIN) {
-#if DEBUG_CHANNEL_SIGNALS
- ALOGD("channel '%s' ~ receive signal failed because no signal available", mName.string());
+ if (!msg->isValid(nRead)) {
+#if DEBUG_CHANNEL_MESSAGES
+ ALOGD("channel '%s' ~ received invalid message", mName.string());
#endif
- return WOULD_BLOCK;
+ return BAD_VALUE;
}
-#if DEBUG_CHANNEL_SIGNALS
- ALOGD("channel '%s' ~ receive signal failed, errno=%d", mName.string(), errno);
+#if DEBUG_CHANNEL_MESSAGES
+ ALOGD("channel '%s' ~ received message of type %d", mName.string(), msg->header.type);
#endif
- return -errno;
+ return OK;
}
// --- InputPublisher ---
InputPublisher::InputPublisher(const sp<InputChannel>& channel) :
- mChannel(channel), mSharedMessage(NULL),
- mPinned(false), mSemaphoreInitialized(false), mWasDispatched(false),
- mMotionEventSampleDataTail(NULL) {
+ mChannel(channel) {
}
InputPublisher::~InputPublisher() {
- reset();
-
- if (mSharedMessage) {
- munmap(mSharedMessage, mAshmemSize);
- }
-}
-
-status_t InputPublisher::initialize() {
-#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' publisher ~ initialize",
- mChannel->getName().string());
-#endif
-
- int ashmemFd = mChannel->getAshmemFd();
- int result = ashmem_get_size_region(ashmemFd);
- if (result < 0) {
- ALOGE("channel '%s' publisher ~ Error %d getting size of ashmem fd %d.",
- mChannel->getName().string(), result, ashmemFd);
- return UNKNOWN_ERROR;
- }
- mAshmemSize = (size_t) result;
-
- mSharedMessage = static_cast<InputMessage*>(mmap(NULL, mAshmemSize,
- PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0));
- if (! mSharedMessage) {
- ALOGE("channel '%s' publisher ~ mmap failed on ashmem fd %d.",
- mChannel->getName().string(), ashmemFd);
- return NO_MEMORY;
- }
-
- mPinned = true;
- mSharedMessage->consumed = false;
-
- return reset();
-}
-
-status_t InputPublisher::reset() {
-#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' publisher ~ reset",
- mChannel->getName().string());
-#endif
-
- if (mPinned) {
- // Destroy the semaphore since we are about to unpin the memory region that contains it.
- int result;
- if (mSemaphoreInitialized) {
- if (mSharedMessage->consumed) {
- result = sem_post(& mSharedMessage->semaphore);
- if (result < 0) {
- ALOGE("channel '%s' publisher ~ Error %d in sem_post.",
- mChannel->getName().string(), errno);
- return UNKNOWN_ERROR;
- }
- }
-
- result = sem_destroy(& mSharedMessage->semaphore);
- if (result < 0) {
- ALOGE("channel '%s' publisher ~ Error %d in sem_destroy.",
- mChannel->getName().string(), errno);
- return UNKNOWN_ERROR;
- }
-
- mSemaphoreInitialized = false;
- }
-
- // Unpin the region since we no longer care about its contents.
- int ashmemFd = mChannel->getAshmemFd();
- result = ashmem_unpin_region(ashmemFd, 0, 0);
- if (result < 0) {
- ALOGE("channel '%s' publisher ~ Error %d unpinning ashmem fd %d.",
- mChannel->getName().string(), result, ashmemFd);
- return UNKNOWN_ERROR;
- }
-
- mPinned = false;
- }
-
- mMotionEventSampleDataTail = NULL;
- mWasDispatched = false;
- return OK;
-}
-
-status_t InputPublisher::publishInputEvent(
- int32_t type,
- int32_t deviceId,
- int32_t source) {
- if (mPinned) {
- ALOGE("channel '%s' publisher ~ Attempted to publish a new event but publisher has "
- "not yet been reset.", mChannel->getName().string());
- return INVALID_OPERATION;
- }
-
- // Pin the region.
- // We do not check for ASHMEM_NOT_PURGED because we don't care about the previous
- // contents of the buffer so it does not matter whether it was purged in the meantime.
- int ashmemFd = mChannel->getAshmemFd();
- int result = ashmem_pin_region(ashmemFd, 0, 0);
- if (result < 0) {
- ALOGE("channel '%s' publisher ~ Error %d pinning ashmem fd %d.",
- mChannel->getName().string(), result, ashmemFd);
- return UNKNOWN_ERROR;
- }
-
- mPinned = true;
-
- result = sem_init(& mSharedMessage->semaphore, 1, 1);
- if (result < 0) {
- ALOGE("channel '%s' publisher ~ Error %d in sem_init.",
- mChannel->getName().string(), errno);
- return UNKNOWN_ERROR;
- }
-
- mSemaphoreInitialized = true;
-
- mSharedMessage->consumed = false;
- mSharedMessage->type = type;
- mSharedMessage->deviceId = deviceId;
- mSharedMessage->source = source;
- return OK;
}
status_t InputPublisher::publishKeyEvent(
+ uint32_t seq,
int32_t deviceId,
int32_t source,
int32_t action,
@@ -337,31 +215,37 @@ status_t InputPublisher::publishKeyEvent(
nsecs_t downTime,
nsecs_t eventTime) {
#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' publisher ~ publishKeyEvent: deviceId=%d, source=0x%x, "
+ ALOGD("channel '%s' publisher ~ publishKeyEvent: seq=%u, deviceId=%d, source=0x%x, "
"action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d,"
"downTime=%lld, eventTime=%lld",
- mChannel->getName().string(),
+ mChannel->getName().string(), seq,
deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount,
downTime, eventTime);
#endif
- status_t result = publishInputEvent(AINPUT_EVENT_TYPE_KEY, deviceId, source);
- if (result < 0) {
- return result;
+ if (!seq) {
+ ALOGE("Attempted to publish a key event with sequence number 0.");
+ return BAD_VALUE;
}
- mSharedMessage->key.action = action;
- mSharedMessage->key.flags = flags;
- mSharedMessage->key.keyCode = keyCode;
- mSharedMessage->key.scanCode = scanCode;
- mSharedMessage->key.metaState = metaState;
- mSharedMessage->key.repeatCount = repeatCount;
- mSharedMessage->key.downTime = downTime;
- mSharedMessage->key.eventTime = eventTime;
- return OK;
+ InputMessage msg;
+ msg.header.type = InputMessage::TYPE_KEY;
+ msg.body.key.seq = seq;
+ msg.body.key.deviceId = deviceId;
+ msg.body.key.source = source;
+ msg.body.key.action = action;
+ msg.body.key.flags = flags;
+ msg.body.key.keyCode = keyCode;
+ msg.body.key.scanCode = scanCode;
+ msg.body.key.metaState = metaState;
+ msg.body.key.repeatCount = repeatCount;
+ msg.body.key.downTime = downTime;
+ msg.body.key.eventTime = eventTime;
+ return mChannel->sendMessage(&msg);
}
status_t InputPublisher::publishMotionEvent(
+ uint32_t seq,
int32_t deviceId,
int32_t source,
int32_t action,
@@ -379,349 +263,349 @@ status_t InputPublisher::publishMotionEvent(
const PointerProperties* pointerProperties,
const PointerCoords* pointerCoords) {
#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' publisher ~ publishMotionEvent: deviceId=%d, source=0x%x, "
+ ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, "
"action=0x%x, flags=0x%x, edgeFlags=0x%x, metaState=0x%x, buttonState=0x%x, "
"xOffset=%f, yOffset=%f, "
"xPrecision=%f, yPrecision=%f, downTime=%lld, eventTime=%lld, "
"pointerCount=%d",
- mChannel->getName().string(),
+ mChannel->getName().string(), seq,
deviceId, source, action, flags, edgeFlags, metaState, buttonState,
xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount);
#endif
+ if (!seq) {
+ ALOGE("Attempted to publish a motion event with sequence number 0.");
+ return BAD_VALUE;
+ }
+
if (pointerCount > MAX_POINTERS || pointerCount < 1) {
ALOGE("channel '%s' publisher ~ Invalid number of pointers provided: %d.",
mChannel->getName().string(), pointerCount);
return BAD_VALUE;
}
- status_t result = publishInputEvent(AINPUT_EVENT_TYPE_MOTION, deviceId, source);
- if (result < 0) {
- return result;
- }
-
- mSharedMessage->motion.action = action;
- mSharedMessage->motion.flags = flags;
- mSharedMessage->motion.edgeFlags = edgeFlags;
- mSharedMessage->motion.metaState = metaState;
- mSharedMessage->motion.buttonState = buttonState;
- mSharedMessage->motion.xOffset = xOffset;
- mSharedMessage->motion.yOffset = yOffset;
- mSharedMessage->motion.xPrecision = xPrecision;
- mSharedMessage->motion.yPrecision = yPrecision;
- mSharedMessage->motion.downTime = downTime;
- mSharedMessage->motion.pointerCount = pointerCount;
-
- mSharedMessage->motion.sampleCount = 1;
- mSharedMessage->motion.sampleData[0].eventTime = eventTime;
-
+ InputMessage msg;
+ msg.header.type = InputMessage::TYPE_MOTION;
+ msg.body.motion.seq = seq;
+ msg.body.motion.deviceId = deviceId;
+ msg.body.motion.source = source;
+ msg.body.motion.action = action;
+ msg.body.motion.flags = flags;
+ msg.body.motion.edgeFlags = edgeFlags;
+ msg.body.motion.metaState = metaState;
+ msg.body.motion.buttonState = buttonState;
+ msg.body.motion.xOffset = xOffset;
+ msg.body.motion.yOffset = yOffset;
+ msg.body.motion.xPrecision = xPrecision;
+ msg.body.motion.yPrecision = yPrecision;
+ msg.body.motion.downTime = downTime;
+ msg.body.motion.eventTime = eventTime;
+ msg.body.motion.pointerCount = pointerCount;
for (size_t i = 0; i < pointerCount; i++) {
- mSharedMessage->motion.pointerProperties[i].copyFrom(pointerProperties[i]);
- mSharedMessage->motion.sampleData[0].coords[i].copyFrom(pointerCoords[i]);
- }
-
- // Cache essential information about the motion event to ensure that a malicious consumer
- // cannot confuse the publisher by modifying the contents of the shared memory buffer while
- // it is being updated.
- if (action == AMOTION_EVENT_ACTION_MOVE
- || action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
- mMotionEventPointerCount = pointerCount;
- mMotionEventSampleDataStride = InputMessage::sampleDataStride(pointerCount);
- mMotionEventSampleDataTail = InputMessage::sampleDataPtrIncrement(
- mSharedMessage->motion.sampleData, mMotionEventSampleDataStride);
- } else {
- mMotionEventSampleDataTail = NULL;
- }
- return OK;
-}
-
-status_t InputPublisher::appendMotionSample(
- nsecs_t eventTime,
- const PointerCoords* pointerCoords) {
-#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' publisher ~ appendMotionSample: eventTime=%lld",
- mChannel->getName().string(), eventTime);
-#endif
-
- if (! mPinned || ! mMotionEventSampleDataTail) {
- ALOGE("channel '%s' publisher ~ Cannot append motion sample because there is no current "
- "AMOTION_EVENT_ACTION_MOVE or AMOTION_EVENT_ACTION_HOVER_MOVE event.",
- mChannel->getName().string());
- return INVALID_OPERATION;
- }
-
- InputMessage::SampleData* newTail = InputMessage::sampleDataPtrIncrement(
- mMotionEventSampleDataTail, mMotionEventSampleDataStride);
- size_t newBytesUsed = reinterpret_cast<char*>(newTail) -
- reinterpret_cast<char*>(mSharedMessage);
-
- if (newBytesUsed > mAshmemSize) {
-#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' publisher ~ Cannot append motion sample because the shared memory "
- "buffer is full. Buffer size: %d bytes, pointers: %d, samples: %d",
- mChannel->getName().string(),
- mAshmemSize, mMotionEventPointerCount, mSharedMessage->motion.sampleCount);
-#endif
- return NO_MEMORY;
+ msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]);
+ msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]);
}
-
- int result;
- if (mWasDispatched) {
- result = sem_trywait(& mSharedMessage->semaphore);
- if (result < 0) {
- if (errno == EAGAIN) {
- // Only possible source of contention is the consumer having consumed (or being in the
- // process of consuming) the message and left the semaphore count at 0.
-#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' publisher ~ Cannot append motion sample because the message has "
- "already been consumed.", mChannel->getName().string());
-#endif
- return FAILED_TRANSACTION;
- } else {
- ALOGE("channel '%s' publisher ~ Error %d in sem_trywait.",
- mChannel->getName().string(), errno);
- return UNKNOWN_ERROR;
- }
- }
- }
-
- mMotionEventSampleDataTail->eventTime = eventTime;
- for (size_t i = 0; i < mMotionEventPointerCount; i++) {
- mMotionEventSampleDataTail->coords[i].copyFrom(pointerCoords[i]);
- }
- mMotionEventSampleDataTail = newTail;
-
- mSharedMessage->motion.sampleCount += 1;
-
- if (mWasDispatched) {
- result = sem_post(& mSharedMessage->semaphore);
- if (result < 0) {
- ALOGE("channel '%s' publisher ~ Error %d in sem_post.",
- mChannel->getName().string(), errno);
- return UNKNOWN_ERROR;
- }
- }
- return OK;
-}
-
-status_t InputPublisher::sendDispatchSignal() {
-#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' publisher ~ sendDispatchSignal",
- mChannel->getName().string());
-#endif
-
- mWasDispatched = true;
- return mChannel->sendSignal(INPUT_SIGNAL_DISPATCH);
+ return mChannel->sendMessage(&msg);
}
-status_t InputPublisher::receiveFinishedSignal(bool* outHandled) {
+status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) {
#if DEBUG_TRANSPORT_ACTIONS
ALOGD("channel '%s' publisher ~ receiveFinishedSignal",
mChannel->getName().string());
#endif
- char signal;
- status_t result = mChannel->receiveSignal(& signal);
+ InputMessage msg;
+ status_t result = mChannel->receiveMessage(&msg);
if (result) {
+ *outSeq = 0;
*outHandled = false;
return result;
}
- if (signal == INPUT_SIGNAL_FINISHED_HANDLED) {
- *outHandled = true;
- } else if (signal == INPUT_SIGNAL_FINISHED_UNHANDLED) {
- *outHandled = false;
- } else {
- ALOGE("channel '%s' publisher ~ Received unexpected signal '%c' from consumer",
- mChannel->getName().string(), signal);
+ if (msg.header.type != InputMessage::TYPE_FINISHED) {
+ ALOGE("channel '%s' publisher ~ Received unexpected message of type %d from consumer",
+ mChannel->getName().string(), msg.header.type);
return UNKNOWN_ERROR;
}
+ *outSeq = msg.body.finished.seq;
+ *outHandled = msg.body.finished.handled;
return OK;
}
// --- InputConsumer ---
InputConsumer::InputConsumer(const sp<InputChannel>& channel) :
- mChannel(channel), mSharedMessage(NULL) {
+ mChannel(channel), mMsgDeferred(false) {
}
InputConsumer::~InputConsumer() {
- if (mSharedMessage) {
- munmap(mSharedMessage, mAshmemSize);
- }
}
-status_t InputConsumer::initialize() {
+status_t InputConsumer::consume(InputEventFactoryInterface* factory,
+ bool consumeBatches, uint32_t* outSeq, InputEvent** outEvent) {
#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' consumer ~ initialize",
- mChannel->getName().string());
+ ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s",
+ mChannel->getName().string(), consumeBatches ? "true" : "false");
#endif
- int ashmemFd = mChannel->getAshmemFd();
- int result = ashmem_get_size_region(ashmemFd);
- if (result < 0) {
- ALOGE("channel '%s' consumer ~ Error %d getting size of ashmem fd %d.",
- mChannel->getName().string(), result, ashmemFd);
- return UNKNOWN_ERROR;
- }
+ *outSeq = 0;
+ *outEvent = NULL;
- mAshmemSize = (size_t) result;
+ // Fetch the next input message.
+ // Loop until an event can be returned or no additional events are received.
+ while (!*outEvent) {
+ if (mMsgDeferred) {
+ // mMsg contains a valid input message from the previous call to consume
+ // that has not yet been processed.
+ mMsgDeferred = false;
+ } else {
+ // Receive a fresh message.
+ status_t result = mChannel->receiveMessage(&mMsg);
+ if (result) {
+ // Consume the next batched event unless batches are being held for later.
+ if (!mBatches.isEmpty() && (consumeBatches || result != WOULD_BLOCK)) {
+ MotionEvent* motionEvent = factory->createMotionEvent();
+ if (! motionEvent) return NO_MEMORY;
+
+ const Batch& batch = mBatches.top();
+ motionEvent->copyFrom(&batch.event, true /*keepHistory*/);
+ *outSeq = batch.seq;
+ *outEvent = motionEvent;
+ mBatches.pop();
+#if DEBUG_TRANSPORT_ACTIONS
+ ALOGD("channel '%s' consumer ~ consumed batch event, seq=%u",
+ mChannel->getName().string(), *outSeq);
+#endif
+ break;
+ }
+ return result;
+ }
+ }
- mSharedMessage = static_cast<InputMessage*>(mmap(NULL, mAshmemSize,
- PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0));
- if (! mSharedMessage) {
- ALOGE("channel '%s' consumer ~ mmap failed on ashmem fd %d.",
- mChannel->getName().string(), ashmemFd);
- return NO_MEMORY;
- }
+ switch (mMsg.header.type) {
+ case InputMessage::TYPE_KEY: {
+ KeyEvent* keyEvent = factory->createKeyEvent();
+ if (!keyEvent) return NO_MEMORY;
- return OK;
-}
+ initializeKeyEvent(keyEvent, &mMsg);
+ *outSeq = mMsg.body.key.seq;
+ *outEvent = keyEvent;
+#if DEBUG_TRANSPORT_ACTIONS
+ ALOGD("channel '%s' consumer ~ consumed key event, seq=%u",
+ mChannel->getName().string(), *outSeq);
+#endif
+ break;
+ }
-status_t InputConsumer::consume(InputEventFactoryInterface* factory, InputEvent** outEvent) {
+ case AINPUT_EVENT_TYPE_MOTION: {
+ ssize_t batchIndex = findBatch(mMsg.body.motion.deviceId, mMsg.body.motion.source);
+ if (batchIndex >= 0) {
+ Batch& batch = mBatches.editItemAt(batchIndex);
+ if (canAppendSamples(&batch.event, &mMsg)) {
+ // Append to the batch and save the new sequence number for the tail end.
+ uint32_t chain = batch.seq;
+ appendSamples(&batch.event, &mMsg);
+ batch.seq = mMsg.body.motion.seq;
+
+ // Update the sequence number chain.
+ SeqChain seqChain;
+ seqChain.seq = batch.seq;
+ seqChain.chain = chain;
+ mSeqChains.push(seqChain);
#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' consumer ~ consume",
- mChannel->getName().string());
+ ALOGD("channel '%s' consumer ~ appended to batch event",
+ mChannel->getName().string());
#endif
+ break;
+ } else {
+ MotionEvent* motionEvent = factory->createMotionEvent();
+ if (! motionEvent) return NO_MEMORY;
+
+ // We cannot append to the batch in progress, so we need to consume
+ // the previous batch right now and defer the new message until later.
+ mMsgDeferred = true;
+
+ // Return the end of the previous batch.
+ motionEvent->copyFrom(&batch.event, true /*keepHistory*/);
+ *outSeq = batch.seq;
+ *outEvent = motionEvent;
+ mBatches.removeAt(batchIndex);
+#if DEBUG_TRANSPORT_ACTIONS
+ ALOGD("channel '%s' consumer ~ consumed batch event and "
+ "deferred current event, seq=%u",
+ mChannel->getName().string(), *outSeq);
+#endif
+ break;
+ }
+ }
- *outEvent = NULL;
+ // Start a new batch if needed.
+ if (mMsg.body.motion.action == AMOTION_EVENT_ACTION_MOVE
+ || mMsg.body.motion.action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
+ mBatches.push();
+ Batch& batch = mBatches.editTop();
+ batch.seq = mMsg.body.motion.seq;
+ initializeMotionEvent(&batch.event, &mMsg);
+#if DEBUG_TRANSPORT_ACTIONS
+ ALOGD("channel '%s' consumer ~ started batch event",
+ mChannel->getName().string());
+#endif
+ break;
+ }
+
+ MotionEvent* motionEvent = factory->createMotionEvent();
+ if (! motionEvent) return NO_MEMORY;
- int ashmemFd = mChannel->getAshmemFd();
- int result = ashmem_pin_region(ashmemFd, 0, 0);
- if (result != ASHMEM_NOT_PURGED) {
- if (result == ASHMEM_WAS_PURGED) {
- ALOGE("channel '%s' consumer ~ Error %d pinning ashmem fd %d because it was purged "
- "which probably indicates that the publisher and consumer are out of sync.",
- mChannel->getName().string(), result, ashmemFd);
- return INVALID_OPERATION;
+ initializeMotionEvent(motionEvent, &mMsg);
+ *outSeq = mMsg.body.motion.seq;
+ *outEvent = motionEvent;
+#if DEBUG_TRANSPORT_ACTIONS
+ ALOGD("channel '%s' consumer ~ consumed motion event, seq=%u",
+ mChannel->getName().string(), *outSeq);
+#endif
+ break;
}
- ALOGE("channel '%s' consumer ~ Error %d pinning ashmem fd %d.",
- mChannel->getName().string(), result, ashmemFd);
- return UNKNOWN_ERROR;
+ default:
+ ALOGE("channel '%s' consumer ~ Received unexpected message of type %d",
+ mChannel->getName().string(), mMsg.header.type);
+ return UNKNOWN_ERROR;
+ }
}
+ return OK;
+}
- if (mSharedMessage->consumed) {
- ALOGE("channel '%s' consumer ~ The current message has already been consumed.",
- mChannel->getName().string());
- return INVALID_OPERATION;
- }
+status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {
+#if DEBUG_TRANSPORT_ACTIONS
+ ALOGD("channel '%s' consumer ~ sendFinishedSignal: seq=%u, handled=%s",
+ mChannel->getName().string(), seq, handled ? "true" : "false");
+#endif
- // Acquire but *never release* the semaphore. Contention on the semaphore is used to signal
- // to the publisher that the message has been consumed (or is in the process of being
- // consumed). Eventually the publisher will reinitialize the semaphore for the next message.
- result = sem_wait(& mSharedMessage->semaphore);
- if (result < 0) {
- ALOGE("channel '%s' consumer ~ Error %d in sem_wait.",
- mChannel->getName().string(), errno);
- return UNKNOWN_ERROR;
+ if (!seq) {
+ ALOGE("Attempted to send a finished signal with sequence number 0.");
+ return BAD_VALUE;
}
- mSharedMessage->consumed = true;
-
- switch (mSharedMessage->type) {
- case AINPUT_EVENT_TYPE_KEY: {
- KeyEvent* keyEvent = factory->createKeyEvent();
- if (! keyEvent) return NO_MEMORY;
-
- populateKeyEvent(keyEvent);
-
- *outEvent = keyEvent;
- break;
+ // Send finished signals for the batch sequence chain first.
+ size_t seqChainCount = mSeqChains.size();
+ if (seqChainCount) {
+ uint32_t currentSeq = seq;
+ uint32_t chainSeqs[seqChainCount];
+ size_t chainIndex = 0;
+ for (size_t i = seqChainCount; i-- > 0; ) {
+ const SeqChain& seqChain = mSeqChains.itemAt(i);
+ if (seqChain.seq == currentSeq) {
+ currentSeq = seqChain.chain;
+ chainSeqs[chainIndex++] = currentSeq;
+ mSeqChains.removeAt(i);
+ }
+ }
+ status_t status = OK;
+ while (!status && chainIndex-- > 0) {
+ status = sendUnchainedFinishedSignal(chainSeqs[chainIndex], handled);
+ }
+ if (status) {
+ // An error occurred so at least one signal was not sent, reconstruct the chain.
+ do {
+ SeqChain seqChain;
+ seqChain.seq = chainIndex != 0 ? chainSeqs[chainIndex - 1] : seq;
+ seqChain.chain = chainSeqs[chainIndex];
+ mSeqChains.push(seqChain);
+ } while (chainIndex-- > 0);
+ return status;
+ }
}
- case AINPUT_EVENT_TYPE_MOTION: {
- MotionEvent* motionEvent = factory->createMotionEvent();
- if (! motionEvent) return NO_MEMORY;
+ // Send finished signal for the last message in the batch.
+ return sendUnchainedFinishedSignal(seq, handled);
+}
- populateMotionEvent(motionEvent);
+status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) {
+ InputMessage msg;
+ msg.header.type = InputMessage::TYPE_FINISHED;
+ msg.body.finished.seq = seq;
+ msg.body.finished.handled = handled;
+ return mChannel->sendMessage(&msg);
+}
- *outEvent = motionEvent;
- break;
- }
+bool InputConsumer::hasPendingBatch() const {
+ return !mBatches.isEmpty();
+}
- default:
- ALOGE("channel '%s' consumer ~ Received message of unknown type %d",
- mChannel->getName().string(), mSharedMessage->type);
- return UNKNOWN_ERROR;
+ssize_t InputConsumer::findBatch(int32_t deviceId, int32_t source) const {
+ for (size_t i = 0; i < mBatches.size(); i++) {
+ const Batch& batch = mBatches.itemAt(i);
+ if (batch.event.getDeviceId() == deviceId && batch.event.getSource() == source) {
+ return i;
+ }
}
-
- return OK;
+ return -1;
}
-status_t InputConsumer::sendFinishedSignal(bool handled) {
-#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' consumer ~ sendFinishedSignal: handled=%d",
- mChannel->getName().string(), handled);
-#endif
-
- return mChannel->sendSignal(handled
- ? INPUT_SIGNAL_FINISHED_HANDLED
- : INPUT_SIGNAL_FINISHED_UNHANDLED);
+void InputConsumer::initializeKeyEvent(KeyEvent* event, const InputMessage* msg) {
+ event->initialize(
+ msg->body.key.deviceId,
+ msg->body.key.source,
+ msg->body.key.action,
+ msg->body.key.flags,
+ msg->body.key.keyCode,
+ msg->body.key.scanCode,
+ msg->body.key.metaState,
+ msg->body.key.repeatCount,
+ msg->body.key.downTime,
+ msg->body.key.eventTime);
}
-status_t InputConsumer::receiveDispatchSignal() {
-#if DEBUG_TRANSPORT_ACTIONS
- ALOGD("channel '%s' consumer ~ receiveDispatchSignal",
- mChannel->getName().string());
-#endif
+void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage* msg) {
+ size_t pointerCount = msg->body.motion.pointerCount;
+ PointerProperties pointerProperties[pointerCount];
+ PointerCoords pointerCoords[pointerCount];
+ for (size_t i = 0; i < pointerCount; i++) {
+ pointerProperties[i].copyFrom(msg->body.motion.pointers[i].properties);
+ pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords);
+ }
+
+ event->initialize(
+ msg->body.motion.deviceId,
+ msg->body.motion.source,
+ msg->body.motion.action,
+ msg->body.motion.flags,
+ msg->body.motion.edgeFlags,
+ msg->body.motion.metaState,
+ msg->body.motion.buttonState,
+ msg->body.motion.xOffset,
+ msg->body.motion.yOffset,
+ msg->body.motion.xPrecision,
+ msg->body.motion.yPrecision,
+ msg->body.motion.downTime,
+ msg->body.motion.eventTime,
+ pointerCount,
+ pointerProperties,
+ pointerCoords);
+}
- char signal;
- status_t result = mChannel->receiveSignal(& signal);
- if (result) {
- return result;
+bool InputConsumer::canAppendSamples(const MotionEvent* event, const InputMessage *msg) {
+ size_t pointerCount = msg->body.motion.pointerCount;
+ if (event->getPointerCount() != pointerCount
+ || event->getAction() != msg->body.motion.action) {
+ return false;
}
- if (signal != INPUT_SIGNAL_DISPATCH) {
- ALOGE("channel '%s' consumer ~ Received unexpected signal '%c' from publisher",
- mChannel->getName().string(), signal);
- return UNKNOWN_ERROR;
+ for (size_t i = 0; i < pointerCount; i++) {
+ if (*event->getPointerProperties(i) != msg->body.motion.pointers[i].properties) {
+ return false;
+ }
}
- return OK;
-}
-
-void InputConsumer::populateKeyEvent(KeyEvent* keyEvent) const {
- keyEvent->initialize(
- mSharedMessage->deviceId,
- mSharedMessage->source,
- mSharedMessage->key.action,
- mSharedMessage->key.flags,
- mSharedMessage->key.keyCode,
- mSharedMessage->key.scanCode,
- mSharedMessage->key.metaState,
- mSharedMessage->key.repeatCount,
- mSharedMessage->key.downTime,
- mSharedMessage->key.eventTime);
+ return true;
}
-void InputConsumer::populateMotionEvent(MotionEvent* motionEvent) const {
- motionEvent->initialize(
- mSharedMessage->deviceId,
- mSharedMessage->source,
- mSharedMessage->motion.action,
- mSharedMessage->motion.flags,
- mSharedMessage->motion.edgeFlags,
- mSharedMessage->motion.metaState,
- mSharedMessage->motion.buttonState,
- mSharedMessage->motion.xOffset,
- mSharedMessage->motion.yOffset,
- mSharedMessage->motion.xPrecision,
- mSharedMessage->motion.yPrecision,
- mSharedMessage->motion.downTime,
- mSharedMessage->motion.sampleData[0].eventTime,
- mSharedMessage->motion.pointerCount,
- mSharedMessage->motion.pointerProperties,
- mSharedMessage->motion.sampleData[0].coords);
-
- size_t sampleCount = mSharedMessage->motion.sampleCount;
- if (sampleCount > 1) {
- InputMessage::SampleData* sampleData = mSharedMessage->motion.sampleData;
- size_t sampleDataStride = InputMessage::sampleDataStride(
- mSharedMessage->motion.pointerCount);
-
- while (--sampleCount > 0) {
- sampleData = InputMessage::sampleDataPtrIncrement(sampleData, sampleDataStride);
- motionEvent->addSample(sampleData->eventTime, sampleData->coords);
- }
+void InputConsumer::appendSamples(MotionEvent* event, const InputMessage* msg) {
+ size_t pointerCount = msg->body.motion.pointerCount;
+ PointerCoords pointerCoords[pointerCount];
+ for (size_t i = 0; i < pointerCount; i++) {
+ pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords);
}
+
+ event->setMetaState(event->getMetaState() | msg->body.motion.metaState);
+ event->addSample(msg->body.motion.eventTime, pointerCoords);
}
} // namespace android
diff --git a/libs/ui/tests/InputChannel_test.cpp b/libs/ui/tests/InputChannel_test.cpp
index eff22ee5f0eb..ee422fe7d8c2 100644
--- a/libs/ui/tests/InputChannel_test.cpp
+++ b/libs/ui/tests/InputChannel_test.cpp
@@ -20,8 +20,7 @@
#include <gtest/gtest.h>
#include <unistd.h>
#include <time.h>
-#include <sys/mman.h>
-#include <cutils/ashmem.h>
+#include <errno.h>
#include "../../utils/tests/TestHelpers.h"
@@ -36,35 +35,24 @@ protected:
TEST_F(InputChannelTest, ConstructorAndDestructor_TakesOwnershipOfFileDescriptors) {
// Our purpose here is to verify that the input channel destructor closes the
- // file descriptors provided to it. One easy way is to provide it with one end
+ // file descriptor provided to it. One easy way is to provide it with one end
// of a pipe and to check for EPIPE on the other end after the channel is destroyed.
- Pipe fakeAshmem, sendPipe, receivePipe;
+ Pipe pipe;
- sp<InputChannel> inputChannel = new InputChannel(String8("channel name"),
- fakeAshmem.sendFd, receivePipe.receiveFd, sendPipe.sendFd);
+ sp<InputChannel> inputChannel = new InputChannel(String8("channel name"), pipe.sendFd);
EXPECT_STREQ("channel name", inputChannel->getName().string())
<< "channel should have provided name";
- EXPECT_EQ(fakeAshmem.sendFd, inputChannel->getAshmemFd())
- << "channel should have provided ashmem fd";
- EXPECT_EQ(receivePipe.receiveFd, inputChannel->getReceivePipeFd())
- << "channel should have provided receive pipe fd";
- EXPECT_EQ(sendPipe.sendFd, inputChannel->getSendPipeFd())
- << "channel should have provided send pipe fd";
+ EXPECT_EQ(pipe.sendFd, inputChannel->getFd())
+ << "channel should have provided fd";
inputChannel.clear(); // destroys input channel
- EXPECT_EQ(-EPIPE, fakeAshmem.readSignal())
- << "channel should have closed ashmem fd when destroyed";
- EXPECT_EQ(-EPIPE, receivePipe.writeSignal())
- << "channel should have closed receive pipe fd when destroyed";
- EXPECT_EQ(-EPIPE, sendPipe.readSignal())
- << "channel should have closed send pipe fd when destroyed";
+ EXPECT_EQ(-EPIPE, pipe.readSignal())
+ << "channel should have closed fd when destroyed";
// clean up fds of Pipe endpoints that were closed so we don't try to close them again
- fakeAshmem.sendFd = -1;
- receivePipe.receiveFd = -1;
- sendPipe.sendFd = -1;
+ pipe.sendFd = -1;
}
TEST_F(InputChannelTest, OpenInputChannelPair_ReturnsAPairOfConnectedChannels) {
@@ -82,43 +70,40 @@ TEST_F(InputChannelTest, OpenInputChannelPair_ReturnsAPairOfConnectedChannels) {
EXPECT_STREQ("channel name (client)", clientChannel->getName().string())
<< "client channel should have suffixed name";
- // Ashmem uniqueness
- EXPECT_NE(serverChannel->getAshmemFd(), clientChannel->getAshmemFd())
- << "server and client channel should have different ashmem fds because it was dup'd";
-
- // Ashmem usability
- ssize_t serverAshmemSize = ashmem_get_size_region(serverChannel->getAshmemFd());
- ssize_t clientAshmemSize = ashmem_get_size_region(clientChannel->getAshmemFd());
- uint32_t* serverAshmem = static_cast<uint32_t*>(mmap(NULL, serverAshmemSize,
- PROT_READ | PROT_WRITE, MAP_SHARED, serverChannel->getAshmemFd(), 0));
- uint32_t* clientAshmem = static_cast<uint32_t*>(mmap(NULL, clientAshmemSize,
- PROT_READ | PROT_WRITE, MAP_SHARED, clientChannel->getAshmemFd(), 0));
- ASSERT_TRUE(serverAshmem != NULL)
- << "server channel ashmem should be mappable";
- ASSERT_TRUE(clientAshmem != NULL)
- << "client channel ashmem should be mappable";
- *serverAshmem = 0xf00dd00d;
- EXPECT_EQ(0xf00dd00d, *clientAshmem)
- << "ashmem buffer should be shared by client and server";
- munmap(serverAshmem, serverAshmemSize);
- munmap(clientAshmem, clientAshmemSize);
-
// Server->Client communication
- EXPECT_EQ(OK, serverChannel->sendSignal('S'))
- << "server channel should be able to send signal to client channel";
- char signal;
- EXPECT_EQ(OK, clientChannel->receiveSignal(& signal))
- << "client channel should be able to receive signal from server channel";
- EXPECT_EQ('S', signal)
- << "client channel should receive the correct signal from server channel";
+ InputMessage serverMsg;
+ memset(&serverMsg, 0, sizeof(InputMessage));
+ serverMsg.header.type = InputMessage::TYPE_KEY;
+ serverMsg.body.key.action = AKEY_EVENT_ACTION_DOWN;
+ EXPECT_EQ(OK, serverChannel->sendMessage(&serverMsg))
+ << "server channel should be able to send message to client channel";
+
+ InputMessage clientMsg;
+ EXPECT_EQ(OK, clientChannel->receiveMessage(&clientMsg))
+ << "client channel should be able to receive message from server channel";
+ EXPECT_EQ(serverMsg.header.type, clientMsg.header.type)
+ << "client channel should receive the correct message from server channel";
+ EXPECT_EQ(serverMsg.body.key.action, clientMsg.body.key.action)
+ << "client channel should receive the correct message from server channel";
// Client->Server communication
- EXPECT_EQ(OK, clientChannel->sendSignal('c'))
- << "client channel should be able to send signal to server channel";
- EXPECT_EQ(OK, serverChannel->receiveSignal(& signal))
- << "server channel should be able to receive signal from client channel";
- EXPECT_EQ('c', signal)
- << "server channel should receive the correct signal from client channel";
+ InputMessage clientReply;
+ memset(&clientReply, 0, sizeof(InputMessage));
+ clientReply.header.type = InputMessage::TYPE_FINISHED;
+ clientReply.body.finished.seq = 0x11223344;
+ clientReply.body.finished.handled = true;
+ EXPECT_EQ(OK, clientChannel->sendMessage(&clientReply))
+ << "client channel should be able to send message to server channel";
+
+ InputMessage serverReply;
+ EXPECT_EQ(OK, serverChannel->receiveMessage(&serverReply))
+ << "server channel should be able to receive message from client channel";
+ EXPECT_EQ(clientReply.header.type, serverReply.header.type)
+ << "server channel should receive the correct message from client channel";
+ EXPECT_EQ(clientReply.body.finished.seq, serverReply.body.finished.seq)
+ << "server channel should receive the correct message from client channel";
+ EXPECT_EQ(clientReply.body.finished.handled, serverReply.body.finished.handled)
+ << "server channel should receive the correct message from client channel";
}
TEST_F(InputChannelTest, ReceiveSignal_WhenNoSignalPresent_ReturnsAnError) {
@@ -130,9 +115,9 @@ TEST_F(InputChannelTest, ReceiveSignal_WhenNoSignalPresent_ReturnsAnError) {
ASSERT_EQ(OK, result)
<< "should have successfully opened a channel pair";
- char signal;
- EXPECT_EQ(WOULD_BLOCK, clientChannel->receiveSignal(& signal))
- << "receiveSignal should have returned WOULD_BLOCK";
+ InputMessage msg;
+ EXPECT_EQ(WOULD_BLOCK, clientChannel->receiveMessage(&msg))
+ << "receiveMessage should have returned WOULD_BLOCK";
}
TEST_F(InputChannelTest, ReceiveSignal_WhenPeerClosed_ReturnsAnError) {
@@ -146,9 +131,9 @@ TEST_F(InputChannelTest, ReceiveSignal_WhenPeerClosed_ReturnsAnError) {
serverChannel.clear(); // close server channel
- char signal;
- EXPECT_EQ(DEAD_OBJECT, clientChannel->receiveSignal(& signal))
- << "receiveSignal should have returned DEAD_OBJECT";
+ InputMessage msg;
+ EXPECT_EQ(DEAD_OBJECT, clientChannel->receiveMessage(&msg))
+ << "receiveMessage should have returned DEAD_OBJECT";
}
TEST_F(InputChannelTest, SendSignal_WhenPeerClosed_ReturnsAnError) {
@@ -162,8 +147,10 @@ TEST_F(InputChannelTest, SendSignal_WhenPeerClosed_ReturnsAnError) {
serverChannel.clear(); // close server channel
- EXPECT_EQ(DEAD_OBJECT, clientChannel->sendSignal('S'))
- << "sendSignal should have returned DEAD_OBJECT";
+ InputMessage msg;
+ msg.header.type = InputMessage::TYPE_KEY;
+ EXPECT_EQ(DEAD_OBJECT, clientChannel->sendMessage(&msg))
+ << "sendMessage should have returned DEAD_OBJECT";
}
diff --git a/libs/ui/tests/InputPublisherAndConsumer_test.cpp b/libs/ui/tests/InputPublisherAndConsumer_test.cpp
index fcc4cadb71ce..33030531322e 100644
--- a/libs/ui/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/ui/tests/InputPublisherAndConsumer_test.cpp
@@ -57,11 +57,8 @@ protected:
clientChannel.clear();
}
- void Initialize();
void PublishAndConsumeKeyEvent();
- void PublishAndConsumeMotionEvent(
- size_t samplesToAppendBeforeDispatch = 0,
- size_t samplesToAppendAfterDispatch = 0);
+ void PublishAndConsumeMotionEvent();
};
TEST_F(InputPublisherAndConsumerTest, GetChannel_ReturnsTheChannel) {
@@ -69,21 +66,10 @@ TEST_F(InputPublisherAndConsumerTest, GetChannel_ReturnsTheChannel) {
EXPECT_EQ(clientChannel.get(), mConsumer->getChannel().get());
}
-void InputPublisherAndConsumerTest::Initialize() {
- status_t status;
-
- status = mPublisher->initialize();
- ASSERT_EQ(OK, status)
- << "publisher initialize should return OK";
-
- status = mConsumer->initialize();
- ASSERT_EQ(OK, status)
- << "consumer initialize should return OK";
-}
-
void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() {
status_t status;
+ const uint32_t seq = 15;
const int32_t deviceId = 1;
const int32_t source = AINPUT_SOURCE_KEYBOARD;
const int32_t action = AKEY_EVENT_ACTION_DOWN;
@@ -95,21 +81,14 @@ void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() {
const nsecs_t downTime = 3;
const nsecs_t eventTime = 4;
- status = mPublisher->publishKeyEvent(deviceId, source, action, flags,
+ status = mPublisher->publishKeyEvent(seq, deviceId, source, action, flags,
keyCode, scanCode, metaState, repeatCount, downTime, eventTime);
ASSERT_EQ(OK, status)
<< "publisher publishKeyEvent should return OK";
- status = mPublisher->sendDispatchSignal();
- ASSERT_EQ(OK, status)
- << "publisher sendDispatchSignal should return OK";
-
- status = mConsumer->receiveDispatchSignal();
- ASSERT_EQ(OK, status)
- << "consumer receiveDispatchSignal should return OK";
-
+ uint32_t consumeSeq;
InputEvent* event;
- status = mConsumer->consume(& mEventFactory, & event);
+ status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, &consumeSeq, &event);
ASSERT_EQ(OK, status)
<< "consumer consume should return OK";
@@ -119,6 +98,7 @@ void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() {
<< "consumer should have returned a key event";
KeyEvent* keyEvent = static_cast<KeyEvent*>(event);
+ EXPECT_EQ(seq, consumeSeq);
EXPECT_EQ(deviceId, keyEvent->getDeviceId());
EXPECT_EQ(source, keyEvent->getSource());
EXPECT_EQ(action, keyEvent->getAction());
@@ -130,26 +110,25 @@ void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() {
EXPECT_EQ(downTime, keyEvent->getDownTime());
EXPECT_EQ(eventTime, keyEvent->getEventTime());
- status = mConsumer->sendFinishedSignal(true);
+ status = mConsumer->sendFinishedSignal(seq, true);
ASSERT_EQ(OK, status)
<< "consumer sendFinishedSignal should return OK";
+ uint32_t finishedSeq = 0;
bool handled = false;
- status = mPublisher->receiveFinishedSignal(&handled);
+ status = mPublisher->receiveFinishedSignal(&finishedSeq, &handled);
ASSERT_EQ(OK, status)
<< "publisher receiveFinishedSignal should return OK";
+ ASSERT_EQ(seq, finishedSeq)
+ << "publisher receiveFinishedSignal should have returned the original sequence number";
ASSERT_TRUE(handled)
<< "publisher receiveFinishedSignal should have set handled to consumer's reply";
-
- status = mPublisher->reset();
- ASSERT_EQ(OK, status)
- << "publisher reset should return OK";
}
-void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent(
- size_t samplesToAppendBeforeDispatch, size_t samplesToAppendAfterDispatch) {
+void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() {
status_t status;
+ const uint32_t seq = 15;
const int32_t deviceId = 1;
const int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
const int32_t action = AMOTION_EVENT_ACTION_MOVE;
@@ -163,67 +142,36 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent(
const float yPrecision = 0.5;
const nsecs_t downTime = 3;
const size_t pointerCount = 3;
+ const nsecs_t eventTime = 4;
PointerProperties pointerProperties[pointerCount];
+ PointerCoords pointerCoords[pointerCount];
for (size_t i = 0; i < pointerCount; i++) {
pointerProperties[i].clear();
pointerProperties[i].id = (i + 2) % pointerCount;
pointerProperties[i].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
- }
- Vector<nsecs_t> sampleEventTimes;
- Vector<PointerCoords> samplePointerCoords;
-
- for (size_t i = 0; i <= samplesToAppendAfterDispatch + samplesToAppendBeforeDispatch; i++) {
- sampleEventTimes.push(i + 10);
- for (size_t j = 0; j < pointerCount; j++) {
- samplePointerCoords.push();
- PointerCoords& pc = samplePointerCoords.editTop();
- pc.clear();
- pc.setAxisValue(AMOTION_EVENT_AXIS_X, 100 * i + j);
- pc.setAxisValue(AMOTION_EVENT_AXIS_Y, 200 * i + j);
- pc.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 0.5 * i + j);
- pc.setAxisValue(AMOTION_EVENT_AXIS_SIZE, 0.7 * i + j);
- pc.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 1.5 * i + j);
- pc.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 1.7 * i + j);
- pc.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.5 * i + j);
- pc.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.7 * i + j);
- pc.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i + j);
- }
+ pointerCoords[i].clear();
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, 100 * i);
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_Y, 200 * i);
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 0.5 * i);
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_SIZE, 0.7 * i);
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, 1.5 * i);
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, 1.7 * i);
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.5 * i);
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 2.7 * i);
+ pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i);
}
- status = mPublisher->publishMotionEvent(deviceId, source, action, flags, edgeFlags,
+ status = mPublisher->publishMotionEvent(seq, deviceId, source, action, flags, edgeFlags,
metaState, buttonState, xOffset, yOffset, xPrecision, yPrecision,
- downTime, sampleEventTimes[0], pointerCount,
- pointerProperties, samplePointerCoords.array());
+ downTime, eventTime, pointerCount,
+ pointerProperties, pointerCoords);
ASSERT_EQ(OK, status)
<< "publisher publishMotionEvent should return OK";
- for (size_t i = 0; i < samplesToAppendBeforeDispatch; i++) {
- size_t sampleIndex = i + 1;
- status = mPublisher->appendMotionSample(sampleEventTimes[sampleIndex],
- samplePointerCoords.array() + sampleIndex * pointerCount);
- ASSERT_EQ(OK, status)
- << "publisher appendMotionEvent should return OK";
- }
-
- status = mPublisher->sendDispatchSignal();
- ASSERT_EQ(OK, status)
- << "publisher sendDispatchSignal should return OK";
-
- for (size_t i = 0; i < samplesToAppendAfterDispatch; i++) {
- size_t sampleIndex = i + 1 + samplesToAppendBeforeDispatch;
- status = mPublisher->appendMotionSample(sampleEventTimes[sampleIndex],
- samplePointerCoords.array() + sampleIndex * pointerCount);
- ASSERT_EQ(OK, status)
- << "publisher appendMotionEvent should return OK";
- }
-
- status = mConsumer->receiveDispatchSignal();
- ASSERT_EQ(OK, status)
- << "consumer receiveDispatchSignal should return OK";
-
+ uint32_t consumeSeq;
InputEvent* event;
- status = mConsumer->consume(& mEventFactory, & event);
+ status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, &consumeSeq, &event);
ASSERT_EQ(OK, status)
<< "consumer consume should return OK";
@@ -232,9 +180,8 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent(
ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType())
<< "consumer should have returned a motion event";
- size_t lastSampleIndex = samplesToAppendBeforeDispatch + samplesToAppendAfterDispatch;
-
MotionEvent* motionEvent = static_cast<MotionEvent*>(event);
+ EXPECT_EQ(seq, consumeSeq);
EXPECT_EQ(deviceId, motionEvent->getDeviceId());
EXPECT_EQ(source, motionEvent->getSource());
EXPECT_EQ(action, motionEvent->getAction());
@@ -245,150 +192,69 @@ void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent(
EXPECT_EQ(xPrecision, motionEvent->getXPrecision());
EXPECT_EQ(yPrecision, motionEvent->getYPrecision());
EXPECT_EQ(downTime, motionEvent->getDownTime());
- EXPECT_EQ(sampleEventTimes[lastSampleIndex], motionEvent->getEventTime());
+ EXPECT_EQ(eventTime, motionEvent->getEventTime());
EXPECT_EQ(pointerCount, motionEvent->getPointerCount());
- EXPECT_EQ(lastSampleIndex, motionEvent->getHistorySize());
+ EXPECT_EQ(0U, motionEvent->getHistorySize());
for (size_t i = 0; i < pointerCount; i++) {
SCOPED_TRACE(i);
EXPECT_EQ(pointerProperties[i].id, motionEvent->getPointerId(i));
EXPECT_EQ(pointerProperties[i].toolType, motionEvent->getToolType(i));
- }
-
- for (size_t sampleIndex = 0; sampleIndex < lastSampleIndex; sampleIndex++) {
- SCOPED_TRACE(sampleIndex);
- EXPECT_EQ(sampleEventTimes[sampleIndex],
- motionEvent->getHistoricalEventTime(sampleIndex));
- for (size_t i = 0; i < pointerCount; i++) {
- SCOPED_TRACE(i);
- size_t offset = sampleIndex * pointerCount + i;
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_X),
- motionEvent->getHistoricalRawX(i, sampleIndex));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_Y),
- motionEvent->getHistoricalRawY(i, sampleIndex));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_X) + xOffset,
- motionEvent->getHistoricalX(i, sampleIndex));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_Y) + yOffset,
- motionEvent->getHistoricalY(i, sampleIndex));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
- motionEvent->getHistoricalPressure(i, sampleIndex));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
- motionEvent->getHistoricalSize(i, sampleIndex));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
- motionEvent->getHistoricalTouchMajor(i, sampleIndex));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
- motionEvent->getHistoricalTouchMinor(i, sampleIndex));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
- motionEvent->getHistoricalToolMajor(i, sampleIndex));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
- motionEvent->getHistoricalToolMinor(i, sampleIndex));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION),
- motionEvent->getHistoricalOrientation(i, sampleIndex));
- }
- }
- SCOPED_TRACE(lastSampleIndex);
- EXPECT_EQ(sampleEventTimes[lastSampleIndex], motionEvent->getEventTime());
- for (size_t i = 0; i < pointerCount; i++) {
- SCOPED_TRACE(i);
- size_t offset = lastSampleIndex * pointerCount + i;
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_X),
+ EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X),
motionEvent->getRawX(i));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_Y),
+ EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
motionEvent->getRawY(i));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_X) + xOffset,
+ EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X) + xOffset,
motionEvent->getX(i));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_Y) + yOffset,
+ EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y) + yOffset,
motionEvent->getY(i));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
+ EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
motionEvent->getPressure(i));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
+ EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
motionEvent->getSize(i));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
+ EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
motionEvent->getTouchMajor(i));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
+ EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
motionEvent->getTouchMinor(i));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
+ EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
motionEvent->getToolMajor(i));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
+ EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
motionEvent->getToolMinor(i));
- EXPECT_EQ(samplePointerCoords[offset].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION),
+ EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION),
motionEvent->getOrientation(i));
}
- status = mConsumer->sendFinishedSignal(false);
+ status = mConsumer->sendFinishedSignal(seq, false);
ASSERT_EQ(OK, status)
<< "consumer sendFinishedSignal should return OK";
+ uint32_t finishedSeq = 0;
bool handled = true;
- status = mPublisher->receiveFinishedSignal(&handled);
+ status = mPublisher->receiveFinishedSignal(&finishedSeq, &handled);
ASSERT_EQ(OK, status)
<< "publisher receiveFinishedSignal should return OK";
+ ASSERT_EQ(seq, finishedSeq)
+ << "publisher receiveFinishedSignal should have returned the original sequence number";
ASSERT_FALSE(handled)
<< "publisher receiveFinishedSignal should have set handled to consumer's reply";
-
- status = mPublisher->reset();
- ASSERT_EQ(OK, status)
- << "publisher reset should return OK";
}
TEST_F(InputPublisherAndConsumerTest, PublishKeyEvent_EndToEnd) {
- ASSERT_NO_FATAL_FAILURE(Initialize());
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent());
}
-TEST_F(InputPublisherAndConsumerTest, PublishKeyEvent_WhenNotReset_ReturnsError) {
- status_t status;
- ASSERT_NO_FATAL_FAILURE(Initialize());
-
- status = mPublisher->publishKeyEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
- ASSERT_EQ(OK, status)
- << "publisher publishKeyEvent should return OK first time";
-
- status = mPublisher->publishKeyEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
- ASSERT_EQ(INVALID_OPERATION, status)
- << "publisher publishKeyEvent should return INVALID_OPERATION because "
- "the publisher was not reset";
-}
-
TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_EndToEnd) {
- ASSERT_NO_FATAL_FAILURE(Initialize());
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
}
-TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenNotReset_ReturnsError) {
- status_t status;
- ASSERT_NO_FATAL_FAILURE(Initialize());
-
- const size_t pointerCount = 1;
- PointerProperties pointerProperties[pointerCount];
- PointerCoords pointerCoords[pointerCount];
- for (size_t i = 0; i < pointerCount; i++) {
- pointerProperties[i].clear();
- pointerCoords[i].clear();
- }
-
- status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- pointerCount, pointerProperties, pointerCoords);
- ASSERT_EQ(OK, status)
- << "publisher publishMotionEvent should return OK";
-
- status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- pointerCount, pointerProperties, pointerCoords);
- ASSERT_EQ(INVALID_OPERATION, status)
- << "publisher publishMotionEvent should return INVALID_OPERATION because ";
- "the publisher was not reset";
-}
-
TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessThan1_ReturnsError) {
status_t status;
- ASSERT_NO_FATAL_FAILURE(Initialize());
-
const size_t pointerCount = 0;
PointerProperties pointerProperties[pointerCount];
PointerCoords pointerCoords[pointerCount];
- status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
pointerCount, pointerProperties, pointerCoords);
ASSERT_EQ(BAD_VALUE, status)
<< "publisher publishMotionEvent should return BAD_VALUE";
@@ -396,8 +262,6 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountLessTha
TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountGreaterThanMax_ReturnsError) {
status_t status;
- ASSERT_NO_FATAL_FAILURE(Initialize());
-
const size_t pointerCount = MAX_POINTERS + 1;
PointerProperties pointerProperties[pointerCount];
PointerCoords pointerCoords[pointerCount];
@@ -406,14 +270,13 @@ TEST_F(InputPublisherAndConsumerTest, PublishMotionEvent_WhenPointerCountGreater
pointerCoords[i].clear();
}
- status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
pointerCount, pointerProperties, pointerCoords);
ASSERT_EQ(BAD_VALUE, status)
<< "publisher publishMotionEvent should return BAD_VALUE";
}
TEST_F(InputPublisherAndConsumerTest, PublishMultipleEvents_EndToEnd) {
- ASSERT_NO_FATAL_FAILURE(Initialize());
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent());
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent());
@@ -421,111 +284,4 @@ TEST_F(InputPublisherAndConsumerTest, PublishMultipleEvents_EndToEnd) {
ASSERT_NO_FATAL_FAILURE(PublishAndConsumeKeyEvent());
}
-TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenCalledBeforeDispatchSignal_AppendsSamples) {
- status_t status;
- ASSERT_NO_FATAL_FAILURE(Initialize());
- ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent(3, 0));
-}
-
-TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenCalledAfterDispatchSignalAndNotConsumed_AppendsSamples) {
- status_t status;
- ASSERT_NO_FATAL_FAILURE(Initialize());
- ASSERT_NO_FATAL_FAILURE(PublishAndConsumeMotionEvent(0, 4));
-}
-
-TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenNoMotionEventPublished_ReturnsError) {
- status_t status;
- ASSERT_NO_FATAL_FAILURE(Initialize());
-
- PointerCoords pointerCoords[1];
- status = mPublisher->appendMotionSample(0, pointerCoords);
- ASSERT_EQ(INVALID_OPERATION, status)
- << "publisher appendMotionSample should return INVALID_OPERATION";
-}
-
-TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenPublishedMotionEventIsNotAMove_ReturnsError) {
- status_t status;
- ASSERT_NO_FATAL_FAILURE(Initialize());
-
- const size_t pointerCount = MAX_POINTERS;
- PointerProperties pointerProperties[pointerCount];
- PointerCoords pointerCoords[pointerCount];
- for (size_t i = 0; i < pointerCount; i++) {
- pointerProperties[i].clear();
- pointerCoords[i].clear();
- }
-
- status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_DOWN,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords);
- ASSERT_EQ(OK, status);
-
- status = mPublisher->appendMotionSample(0, pointerCoords);
- ASSERT_EQ(INVALID_OPERATION, status)
- << "publisher appendMotionSample should return INVALID_OPERATION";
-}
-
-TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenAlreadyConsumed_ReturnsError) {
- status_t status;
- ASSERT_NO_FATAL_FAILURE(Initialize());
-
- const size_t pointerCount = MAX_POINTERS;
- PointerProperties pointerProperties[pointerCount];
- PointerCoords pointerCoords[pointerCount];
- for (size_t i = 0; i < pointerCount; i++) {
- pointerProperties[i].clear();
- pointerCoords[i].clear();
- }
-
- status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_MOVE,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords);
- ASSERT_EQ(OK, status);
-
- status = mPublisher->sendDispatchSignal();
- ASSERT_EQ(OK, status);
-
- status = mConsumer->receiveDispatchSignal();
- ASSERT_EQ(OK, status);
-
- InputEvent* event;
- status = mConsumer->consume(& mEventFactory, & event);
- ASSERT_EQ(OK, status);
-
- status = mPublisher->appendMotionSample(0, pointerCoords);
- ASSERT_EQ(status_t(FAILED_TRANSACTION), status)
- << "publisher appendMotionSample should return FAILED_TRANSACTION";
-}
-
-TEST_F(InputPublisherAndConsumerTest, AppendMotionSample_WhenBufferFull_ReturnsError) {
- status_t status;
- ASSERT_NO_FATAL_FAILURE(Initialize());
-
- const size_t pointerCount = MAX_POINTERS;
- PointerProperties pointerProperties[pointerCount];
- PointerCoords pointerCoords[pointerCount];
- for (size_t i = 0; i < pointerCount; i++) {
- pointerProperties[i].clear();
- pointerCoords[i].clear();
- }
-
- status = mPublisher->publishMotionEvent(0, 0, AMOTION_EVENT_ACTION_MOVE,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords);
- ASSERT_EQ(OK, status);
-
- for (int count = 1;; count++) {
- ASSERT_LT(count, 100000) << "should eventually reach OOM";
-
- status = mPublisher->appendMotionSample(0, pointerCoords);
- if (status != OK) {
- ASSERT_GT(count, 12) << "should be able to add at least a dozen samples";
- ASSERT_EQ(NO_MEMORY, status)
- << "publisher appendMotionSample should return NO_MEMORY when buffer is full";
- break;
- }
- }
-
- status = mPublisher->appendMotionSample(0, pointerCoords);
- ASSERT_EQ(NO_MEMORY, status)
- << "publisher appendMotionSample should return NO_MEMORY persistently until reset";
-}
-
} // namespace android
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 3f5d19240e76..9748d3b24ed5 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -91,7 +91,8 @@ public class AudioManager {
* @see #EXTRA_VIBRATE_SETTING
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String VIBRATE_SETTING_CHANGED_ACTION = "android.media.VIBRATE_SETTING_CHANGED";
+ public static final String VIBRATE_SETTING_CHANGED_ACTION =
+ "android.media.VIBRATE_SETTING_CHANGED";
/**
* @hide Broadcast intent when the volume for a particular stream type changes.
@@ -105,6 +106,27 @@ public class AudioManager {
public static final String VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION";
/**
+ * @hide Broadcast intent when the master volume changes.
+ * Includes the new volume
+ *
+ * @see #EXTRA_MASTER_VOLUME_VALUE
+ * @see #EXTRA_PREV_MASTER_VOLUME_VALUE
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String MASTER_VOLUME_CHANGED_ACTION =
+ "android.media.MASTER_VOLUME_CHANGED_ACTION";
+
+ /**
+ * @hide Broadcast intent when the master mute state changes.
+ * Includes the the new volume
+ *
+ * @see #EXTRA_MASTER_VOLUME_MUTED
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String MASTER_MUTE_CHANGED_ACTION =
+ "android.media.MASTER_MUTE_CHANGED_ACTION";
+
+ /**
* The new vibrate setting for a particular type.
*
* @see #VIBRATE_SETTING_CHANGED_ACTION
@@ -141,6 +163,27 @@ public class AudioManager {
public static final String EXTRA_PREV_VOLUME_STREAM_VALUE =
"android.media.EXTRA_PREV_VOLUME_STREAM_VALUE";
+ /**
+ * @hide The new master volume value for the master volume changed intent.
+ * Value is integer between 0 and 100 inclusive.
+ */
+ public static final String EXTRA_MASTER_VOLUME_VALUE =
+ "android.media.EXTRA_MASTER_VOLUME_VALUE";
+
+ /**
+ * @hide The previous master volume value for the master volume changed intent.
+ * Value is integer between 0 and 100 inclusive.
+ */
+ public static final String EXTRA_PREV_MASTER_VOLUME_VALUE =
+ "android.media.EXTRA_PREV_MASTER_VOLUME_VALUE";
+
+ /**
+ * @hide The new master volume mute state for the master mute changed intent.
+ * Value is boolean
+ */
+ public static final String EXTRA_MASTER_VOLUME_MUTED =
+ "android.media.EXTRA_MASTER_VOLUME_MUTED";
+
/** The audio stream for phone calls */
public static final int STREAM_VOICE_CALL = AudioSystem.STREAM_VOICE_CALL;
/** The audio stream for system sounds */
@@ -372,11 +415,12 @@ public class AudioManager {
/**
* @hide
*/
- public void preDispatchKeyEvent(int keyCode, int stream) {
+ public void preDispatchKeyEvent(KeyEvent event, int stream) {
/*
* If the user hits another key within the play sound delay, then
* cancel the sound
*/
+ int keyCode = event.getKeyCode();
if (keyCode != KeyEvent.KEYCODE_VOLUME_DOWN && keyCode != KeyEvent.KEYCODE_VOLUME_UP
&& keyCode != KeyEvent.KEYCODE_VOLUME_MUTE
&& mVolumeKeyUpTime + VolumePanel.PLAY_SOUND_DELAY
@@ -397,7 +441,8 @@ public class AudioManager {
/**
* @hide
*/
- public void handleKeyDown(int keyCode, int stream) {
+ public void handleKeyDown(KeyEvent event, int stream) {
+ int keyCode = event.getKeyCode();
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
@@ -426,7 +471,13 @@ public class AudioManager {
}
break;
case KeyEvent.KEYCODE_VOLUME_MUTE:
- // TODO: Actually handle MUTE.
+ if (event.getRepeatCount() == 0) {
+ if (mUseMasterVolume) {
+ setMasterMute(!isMasterMute());
+ } else {
+ // TODO: Actually handle MUTE.
+ }
+ }
break;
}
}
@@ -434,7 +485,8 @@ public class AudioManager {
/**
* @hide
*/
- public void handleKeyUp(int keyCode, int stream) {
+ public void handleKeyUp(KeyEvent event, int stream) {
+ int keyCode = event.getKeyCode();
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
@@ -460,9 +512,6 @@ public class AudioManager {
mVolumeKeyUpTime = SystemClock.uptimeMillis();
break;
- case KeyEvent.KEYCODE_VOLUME_MUTE:
- // TODO: Actually handle MUTE.
- break;
}
}
@@ -485,7 +534,11 @@ public class AudioManager {
public void adjustStreamVolume(int streamType, int direction, int flags) {
IAudioService service = getService();
try {
- service.adjustStreamVolume(streamType, direction, flags);
+ if (mUseMasterVolume) {
+ service.adjustMasterVolume(direction, flags);
+ } else {
+ service.adjustStreamVolume(streamType, direction, flags);
+ }
} catch (RemoteException e) {
Log.e(TAG, "Dead object in adjustStreamVolume", e);
}
@@ -511,7 +564,11 @@ public class AudioManager {
public void adjustVolume(int direction, int flags) {
IAudioService service = getService();
try {
- service.adjustVolume(direction, flags);
+ if (mUseMasterVolume) {
+ service.adjustMasterVolume(direction, flags);
+ } else {
+ service.adjustVolume(direction, flags);
+ }
} catch (RemoteException e) {
Log.e(TAG, "Dead object in adjustVolume", e);
}
@@ -537,7 +594,11 @@ public class AudioManager {
public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
IAudioService service = getService();
try {
- service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags);
+ if (mUseMasterVolume) {
+ service.adjustMasterVolume(direction, flags);
+ } else {
+ service.adjustSuggestedStreamVolume(direction, suggestedStreamType, flags);
+ }
} catch (RemoteException e) {
Log.e(TAG, "Dead object in adjustSuggestedStreamVolume", e);
}
@@ -551,8 +612,9 @@ public class AudioManager {
* {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or
* {@link #ADJUST_SAME}.
* @param flags One or more flags.
+ * @hide
*/
- private void adjustMasterVolume(int direction, int flags) {
+ public void adjustMasterVolume(int direction, int flags) {
IAudioService service = getService();
try {
service.adjustMasterVolume(direction, flags);
@@ -603,7 +665,11 @@ public class AudioManager {
public int getStreamMaxVolume(int streamType) {
IAudioService service = getService();
try {
- return service.getStreamMaxVolume(streamType);
+ if (mUseMasterVolume) {
+ return service.getMasterMaxVolume();
+ } else {
+ return service.getStreamMaxVolume(streamType);
+ }
} catch (RemoteException e) {
Log.e(TAG, "Dead object in getStreamMaxVolume", e);
return 0;
@@ -621,7 +687,11 @@ public class AudioManager {
public int getStreamVolume(int streamType) {
IAudioService service = getService();
try {
- return service.getStreamVolume(streamType);
+ if (mUseMasterVolume) {
+ return service.getMasterVolume();
+ } else {
+ return service.getStreamVolume(streamType);
+ }
} catch (RemoteException e) {
Log.e(TAG, "Dead object in getStreamVolume", e);
return 0;
@@ -636,7 +706,11 @@ public class AudioManager {
public int getLastAudibleStreamVolume(int streamType) {
IAudioService service = getService();
try {
- return service.getLastAudibleStreamVolume(streamType);
+ if (mUseMasterVolume) {
+ return service.getLastAudibleMasterVolume();
+ } else {
+ return service.getLastAudibleStreamVolume(streamType);
+ }
} catch (RemoteException e) {
Log.e(TAG, "Dead object in getLastAudibleStreamVolume", e);
return 0;
@@ -679,13 +753,82 @@ public class AudioManager {
public void setStreamVolume(int streamType, int index, int flags) {
IAudioService service = getService();
try {
- service.setStreamVolume(streamType, index, flags);
+ if (mUseMasterVolume) {
+ service.setMasterVolume(index, flags);
+ } else {
+ service.setStreamVolume(streamType, index, flags);
+ }
} catch (RemoteException e) {
Log.e(TAG, "Dead object in setStreamVolume", e);
}
}
/**
+ * Returns the maximum volume index for master volume.
+ *
+ * @hide
+ */
+ public int getMasterMaxVolume() {
+ IAudioService service = getService();
+ try {
+ return service.getMasterMaxVolume();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in getMasterMaxVolume", e);
+ return 0;
+ }
+ }
+
+ /**
+ * Returns the current volume index for master volume.
+ *
+ * @return The current volume index for master volume.
+ * @hide
+ */
+ public int getMasterVolume() {
+ IAudioService service = getService();
+ try {
+ return service.getMasterVolume();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in getMasterVolume", e);
+ return 0;
+ }
+ }
+
+ /**
+ * Get last audible volume before master volume was muted.
+ *
+ * @hide
+ */
+ public int getLastAudibleMasterVolume() {
+ IAudioService service = getService();
+ try {
+ return service.getLastAudibleMasterVolume();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in getLastAudibleMasterVolume", e);
+ return 0;
+ }
+ }
+
+ /**
+ * Sets the volume index for master volume.
+ *
+ * @param index The volume index to set. See
+ * {@link #getMasterMaxVolume(int)} for the largest valid value.
+ * @param flags One or more flags.
+ * @see #getMasterMaxVolume(int)
+ * @see #getMasterVolume(int)
+ * @hide
+ */
+ public void setMasterVolume(int index, int flags) {
+ IAudioService service = getService();
+ try {
+ service.setMasterVolume(index, flags);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in setMasterVolume", e);
+ }
+ }
+
+ /**
* Solo or unsolo a particular stream. All other streams are muted.
* <p>
* The solo command is protected against client process death: if a process
@@ -756,6 +899,35 @@ public class AudioManager {
}
/**
+ * set master mute state.
+ *
+ * @hide
+ */
+ public void setMasterMute(boolean state) {
+ IAudioService service = getService();
+ try {
+ service.setMasterMute(state, mICallBack);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in setMasterMute", e);
+ }
+ }
+
+ /**
+ * get master mute state.
+ *
+ * @hide
+ */
+ public boolean isMasterMute() {
+ IAudioService service = getService();
+ try {
+ return service.isMasterMute();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Dead object in isMasterMute", e);
+ return false;
+ }
+ }
+
+ /**
* forces the stream controlled by hard volume keys
* specifying streamType == -1 releases control to the
* logic.
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 825920247667..eae03beae6fc 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -112,6 +112,7 @@ public class AudioService extends IAudioService.Stub {
// AudioHandler message.whats
private static final int MSG_SET_DEVICE_VOLUME = 0;
private static final int MSG_PERSIST_VOLUME = 1;
+ private static final int MSG_PERSIST_MASTER_VOLUME = 2;
private static final int MSG_PERSIST_RINGER_MODE = 3;
private static final int MSG_PERSIST_VIBRATE_SETTING = 4;
private static final int MSG_MEDIA_SERVER_DIED = 5;
@@ -136,10 +137,6 @@ public class AudioService extends IAudioService.Stub {
// Timeout for connection to bluetooth headset service
private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
- // Amount to raise/lower master volume
- // FIXME - this should probably be in a resource
- private static final float MASTER_VOLUME_INCREMENT = 0.05f;
-
/** @see AudioSystemThread */
private AudioSystemThread mAudioSystemThread;
/** @see AudioHandler */
@@ -158,6 +155,10 @@ public class AudioService extends IAudioService.Stub {
private static final int NUM_SOUNDPOOL_CHANNELS = 4;
private static final int SOUND_EFFECT_VOLUME = 1000;
+ // Internally master volume is a float in the 0.0 - 1.0 range,
+ // but to support integer based AudioManager API we translate it to 0 - 100
+ private static final int MAX_MASTER_VOLUME = 100;
+
/* Sound effect file names */
private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
private static final String[] SOUND_EFFECT_FILES = new String[] {
@@ -278,6 +279,11 @@ public class AudioService extends IAudioService.Stub {
// Forced device usage for communications
private int mForcedUseForComm;
+ // True if we have master volume support
+ private final boolean mUseMasterVolume;
+
+ private final int[] mMasterVolumeRamp;
+
// List of binder death handlers for setMode() client processes.
// The last process to have called setMode() is at the top of the list.
private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
@@ -405,14 +411,12 @@ public class AudioService extends IAudioService.Stub {
context.getSystemService(Context.TELEPHONY_SERVICE);
tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
- if (context.getResources().getBoolean(
- com.android.internal.R.bool.config_useMasterVolume)) {
- float volume = Settings.System.getFloat(mContentResolver,
- Settings.System.VOLUME_MASTER, -1.0f);
- if (volume >= 0.0f) {
- AudioSystem.setMasterVolume(volume);
- }
- }
+ mUseMasterVolume = context.getResources().getBoolean(
+ com.android.internal.R.bool.config_useMasterVolume);
+ restoreMasterVolume();
+
+ mMasterVolumeRamp = context.getResources().getIntArray(
+ com.android.internal.R.array.config_masterVolumeRamp);
}
private void createAudioSystemThread() {
@@ -617,22 +621,27 @@ public class AudioService extends IAudioService.Stub {
/** @see AudioManager#adjustMasterVolume(int) */
public void adjustMasterVolume(int direction, int flags) {
ensureValidDirection(direction);
-
- float volume = AudioSystem.getMasterVolume();
- if (volume >= 0.0) {
+ int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
+ int delta = 0;
+ for (int i = 0; i < mMasterVolumeRamp.length; i += 2) {
+ int testVolume = mMasterVolumeRamp[i];
+ int testDelta = mMasterVolumeRamp[i + 1];
if (direction == AudioManager.ADJUST_RAISE) {
- volume += MASTER_VOLUME_INCREMENT;
- if (volume > 1.0f) volume = 1.0f;
+ if (volume >= testVolume) {
+ delta = testDelta;
+ } else {
+ break;
+ }
} else if (direction == AudioManager.ADJUST_LOWER) {
- volume -= MASTER_VOLUME_INCREMENT;
- if (volume < 0.0f) volume = 0.0f;
+ if (volume - testDelta >= testVolume) {
+ delta = -testDelta;
+ } else {
+ break;
+ }
}
- AudioSystem.setMasterVolume(volume);
- long origCallerIdentityToken = Binder.clearCallingIdentity();
- Settings.System.putFloat(mContentResolver, Settings.System.VOLUME_MASTER, volume);
- Binder.restoreCallingIdentity(origCallerIdentityToken);
- mVolumePanel.postMasterVolumeChanged(flags);
}
+// Log.d(TAG, "adjustMasterVolume volume: " + volume + " delta: " + delta + " direction: " + direction);
+ setMasterVolume(volume + delta, flags);
}
/** @see AudioManager#setStreamVolume(int, int, int) */
@@ -690,6 +699,27 @@ public class AudioService extends IAudioService.Stub {
mContext.sendBroadcast(intent);
}
+ // UI update and Broadcast Intent
+ private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) {
+ mVolumePanel.postMasterVolumeChanged(flags);
+
+ Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION);
+ intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume);
+ intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume);
+ mContext.sendBroadcast(intent);
+ }
+
+ // UI update and Broadcast Intent
+ private void sendMasterMuteUpdate(boolean muted, int flags) {
+ mVolumePanel.postMasterMuteChanged(flags);
+
+ Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
+ intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
+ long origCallerIdentityToken = Binder.clearCallingIdentity();
+ mContext.sendStickyBroadcast(intent);
+ Binder.restoreCallingIdentity(origCallerIdentityToken);
+ }
+
/**
* Sets the stream state's index, and posts a message to set system volume.
* This will not call out to the UI. Assumes a valid stream type.
@@ -758,6 +788,19 @@ public class AudioService extends IAudioService.Stub {
return (mStreamStates[streamType].muteCount() != 0);
}
+ /** @see AudioManager#setMasterMute(boolean, IBinder) */
+ public void setMasterMute(boolean state, IBinder cb) {
+ if (state != AudioSystem.getMasterMute()) {
+ AudioSystem.setMasterMute(state);
+ sendMasterMuteUpdate(state, AudioManager.FLAG_SHOW_UI);
+ }
+ }
+
+ /** get master mute state. */
+ public boolean isMasterMute() {
+ return AudioSystem.getMasterMute();
+ }
+
/** @see AudioManager#getStreamVolume(int) */
public int getStreamVolume(int streamType) {
ensureValidStreamType(streamType);
@@ -765,12 +808,34 @@ public class AudioService extends IAudioService.Stub {
return (mStreamStates[streamType].getIndex(device, false /* lastAudible */) + 5) / 10;
}
- public float getMasterVolume() {
- return AudioSystem.getMasterVolume();
+ public int getMasterVolume() {
+ if (isMasterMute()) return 0;
+ return getLastAudibleMasterVolume();
}
- public void setMasterVolume(float volume) {
- AudioSystem.setMasterVolume(volume);
+ public void setMasterVolume(int volume, int flags) {
+ if (volume < 0) {
+ volume = 0;
+ } else if (volume > MAX_MASTER_VOLUME) {
+ volume = MAX_MASTER_VOLUME;
+ }
+ doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags);
+ }
+
+ private void doSetMasterVolume(float volume, int flags) {
+ // don't allow changing master volume when muted
+ if (!AudioSystem.getMasterMute()) {
+ int oldVolume = getMasterVolume();
+ AudioSystem.setMasterVolume(volume);
+
+ int newVolume = getMasterVolume();
+ if (newVolume != oldVolume) {
+ // Post a persist master volume msg
+ sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE,
+ Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY);
+ sendMasterVolumeUpdate(flags, oldVolume, newVolume);
+ }
+ }
}
/** @see AudioManager#getStreamMaxVolume(int) */
@@ -779,6 +844,9 @@ public class AudioService extends IAudioService.Stub {
return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
}
+ public int getMasterMaxVolume() {
+ return MAX_MASTER_VOLUME;
+ }
/** Get last audible volume before stream was muted. */
public int getLastAudibleStreamVolume(int streamType) {
@@ -787,6 +855,11 @@ public class AudioService extends IAudioService.Stub {
return (mStreamStates[streamType].getIndex(device, true /* lastAudible */) + 5) / 10;
}
+ /** Get last audible master volume before it was muted. */
+ public int getLastAudibleMasterVolume() {
+ return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
+ }
+
/** @see AudioManager#getRingerMode() */
public int getRingerMode() {
synchronized(mSettingsLock) {
@@ -857,6 +930,16 @@ public class AudioService extends IAudioService.Stub {
}
}
+ private void restoreMasterVolume() {
+ if (mUseMasterVolume) {
+ float volume = Settings.System.getFloat(mContentResolver,
+ Settings.System.VOLUME_MASTER, -1.0f);
+ if (volume >= 0.0f) {
+ AudioSystem.setMasterVolume(volume);
+ }
+ }
+ }
+
/** @see AudioManager#shouldVibrate(int) */
public boolean shouldVibrate(int vibrateType) {
@@ -2396,6 +2479,11 @@ public class AudioService extends IAudioService.Stub {
persistVolume((VolumeStreamState) msg.obj, msg.arg1, msg.arg2);
break;
+ case MSG_PERSIST_MASTER_VOLUME:
+ Settings.System.putFloat(mContentResolver, Settings.System.VOLUME_MASTER,
+ (float)msg.arg1 / (float)1000.0);
+ break;
+
case MSG_PERSIST_RINGER_MODE:
// note that the value persisted is the current ringer mode, not the
// value of ringer mode as of the time the request was made to persist
@@ -2456,6 +2544,9 @@ public class AudioService extends IAudioService.Stub {
// Restore ringer mode
setRingerModeInt(getRingerMode(), false);
+ // Restore master volume
+ restoreMasterVolume();
+
// indicate the end of reconfiguration phase to audio HAL
AudioSystem.setParameters("restarting=false");
break;
@@ -2880,6 +2971,11 @@ public class AudioService extends IAudioService.Stub {
adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
BluetoothProfile.A2DP);
}
+
+ if (mUseMasterVolume) {
+ // Send sticky broadcast for initial master mute state
+ sendMasterMuteUpdate(false, 0);
+ }
} else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
// a package is being removed, not replaced
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 01a2314f8e4b..17d8e4df481f 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -36,6 +36,8 @@ interface IAudioService {
void adjustMasterVolume(int direction, int flags);
void setStreamVolume(int streamType, int index, int flags);
+
+ void setMasterVolume(int index, int flags);
void setStreamSolo(int streamType, boolean state, IBinder cb);
@@ -43,14 +45,22 @@ interface IAudioService {
boolean isStreamMute(int streamType);
+ void setMasterMute(boolean state, IBinder cb);
+
+ boolean isMasterMute();
+
int getStreamVolume(int streamType);
- float getMasterVolume();
+ int getMasterVolume();
int getStreamMaxVolume(int streamType);
+
+ int getMasterMaxVolume();
int getLastAudibleStreamVolume(int streamType);
+ int getLastAudibleMasterVolume();
+
void setRingerMode(int ringerMode);
int getRingerMode();
diff --git a/media/java/android/media/MediaInserter.java b/media/java/android/media/MediaInserter.java
index e92c710a3edd..7fcbffa06eb1 100644
--- a/media/java/android/media/MediaInserter.java
+++ b/media/java/android/media/MediaInserter.java
@@ -34,6 +34,8 @@ import java.util.List;
public class MediaInserter {
private final HashMap<Uri, List<ContentValues>> mRowMap =
new HashMap<Uri, List<ContentValues>>();
+ private final HashMap<Uri, List<ContentValues>> mPriorityRowMap =
+ new HashMap<Uri, List<ContentValues>>();
private IContentProvider mProvider;
private int mBufferSizePerUri;
@@ -44,26 +46,45 @@ public class MediaInserter {
}
public void insert(Uri tableUri, ContentValues values) throws RemoteException {
- List<ContentValues> list = mRowMap.get(tableUri);
+ insert(tableUri, values, false);
+ }
+
+ public void insertwithPriority(Uri tableUri, ContentValues values) throws RemoteException {
+ insert(tableUri, values, true);
+ }
+
+ private void insert(Uri tableUri, ContentValues values, boolean priority) throws RemoteException {
+ HashMap<Uri, List<ContentValues>> rowmap = priority ? mPriorityRowMap : mRowMap;
+ List<ContentValues> list = rowmap.get(tableUri);
if (list == null) {
list = new ArrayList<ContentValues>();
- mRowMap.put(tableUri, list);
+ rowmap.put(tableUri, list);
}
list.add(new ContentValues(values));
if (list.size() >= mBufferSizePerUri) {
- flush(tableUri);
+ flushAllPriority();
+ flush(tableUri, list);
}
}
public void flushAll() throws RemoteException {
+ flushAllPriority();
for (Uri tableUri : mRowMap.keySet()){
- flush(tableUri);
+ List<ContentValues> list = mRowMap.get(tableUri);
+ flush(tableUri, list);
}
mRowMap.clear();
}
- private void flush(Uri tableUri) throws RemoteException {
- List<ContentValues> list = mRowMap.get(tableUri);
+ private void flushAllPriority() throws RemoteException {
+ for (Uri tableUri : mPriorityRowMap.keySet()){
+ List<ContentValues> list = mPriorityRowMap.get(tableUri);
+ flush(tableUri, list);
+ }
+ mPriorityRowMap.clear();
+ }
+
+ private void flush(Uri tableUri, List<ContentValues> list) throws RemoteException {
if (!list.isEmpty()) {
ContentValues[] valuesArray = new ContentValues[list.size()];
valuesArray = list.toArray(valuesArray);
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 69ca58bfe3c5..52d31c749e07 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -59,6 +59,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.Locale;
/**
@@ -374,7 +375,7 @@ public class MediaScanner
// hashes file path to FileCacheEntry.
// path should be lower case if mCaseInsensitivePaths is true
- private HashMap<String, FileCacheEntry> mFileCache;
+ private LinkedHashMap<String, FileCacheEntry> mFileCache;
private ArrayList<FileCacheEntry> mPlayLists;
@@ -922,16 +923,15 @@ public class MediaScanner
}
}
- // new file, insert it
- // We insert directories immediately to ensure they are in the database
- // before the files they contain.
- // Otherwise we can get duplicate directory entries in the database
- // if one of the media FileInserters is flushed before the files table FileInserter
- // Also, we immediately insert the file if the rowId of the inserted file is
- // needed.
- if (inserter == null || needToSetSettings ||
- entry.mFormat == MtpConstants.FORMAT_ASSOCIATION) {
+ // New file, insert it.
+ // Directories need to be inserted before the files they contain, so they
+ // get priority when bulk inserting.
+ // If the rowId of the inserted file is needed, it gets inserted immediately,
+ // bypassing the bulk inserter.
+ if (inserter == null || needToSetSettings) {
result = mMediaProvider.insert(tableUri, values);
+ } else if (entry.mFormat == MtpConstants.FORMAT_ASSOCIATION) {
+ inserter.insertwithPriority(tableUri, values);
} else {
inserter.insert(tableUri, values);
}
@@ -1029,7 +1029,7 @@ public class MediaScanner
String[] selectionArgs = null;
if (mFileCache == null) {
- mFileCache = new HashMap<String, FileCacheEntry>();
+ mFileCache = new LinkedHashMap<String, FileCacheEntry>();
} else {
mFileCache.clear();
}
@@ -1151,7 +1151,8 @@ public class MediaScanner
}
static class MediaBulkDeleter {
- StringBuilder idList = new StringBuilder();
+ StringBuilder whereClause = new StringBuilder();
+ ArrayList<String> whereArgs = new ArrayList<String>(100);
IContentProvider mProvider;
Uri mBaseUri;
@@ -1161,19 +1162,26 @@ public class MediaScanner
}
public void delete(long id) throws RemoteException {
- if (idList.length() != 0) {
- idList.append(",");
+ if (whereClause.length() != 0) {
+ whereClause.append(",");
}
- idList.append(id);
- if (idList.length() > 1024) {
+ whereClause.append("?");
+ whereArgs.add("" + id);
+ if (whereArgs.size() > 100) {
flush();
}
}
public void flush() throws RemoteException {
- int numrows = mProvider.delete(mBaseUri, MediaStore.MediaColumns._ID + " IN (" +
- idList.toString() + ")", null);
- //Log.i("@@@@@@@@@", "rows deleted: " + numrows);
- idList.setLength(0);
+ int size = whereArgs.size();
+ if (size > 0) {
+ String [] foo = new String [size];
+ foo = whereArgs.toArray(foo);
+ int numrows = mProvider.delete(mBaseUri, MediaStore.MediaColumns._ID + " IN (" +
+ whereClause.toString() + ")", foo);
+ //Log.i("@@@@@@@@@", "rows deleted: " + numrows);
+ whereClause.setLength(0);
+ whereArgs.clear();
+ }
}
}
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index df4fbb55bc7e..ceb87db12aee 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -623,7 +623,7 @@ void SoundChannel::play(const sp<Sample>& sample, int nextChannelID, float leftV
newTrack->setVolume(leftVolume, rightVolume);
newTrack->setLoop(0, frameCount, loop);
- // From now on, AudioTrack callbacks recevieved with previous toggle value will be ignored.
+ // From now on, AudioTrack callbacks received with previous toggle value will be ignored.
mToggle = toggle;
mAudioTrack = newTrack;
mPos = 0;
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index 4d94a75dfbb0..098a1a29242d 100755
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -1298,7 +1298,7 @@ int PreProcessingFx_Command(effect_handle_t self,
return -EINVAL;
}
- Session_GetConfig(effect->session, (effect_config_t *)pCmdData);
+ Session_GetConfig(effect->session, (effect_config_t *)pReplyData);
break;
case EFFECT_CMD_SET_CONFIG_REVERSE:
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index b74b3e35c8a7..a4068ff2abad 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -304,10 +304,25 @@ status_t AudioRecord::start()
if (mActive == 0) {
mActive = 1;
+ pid_t tid;
+ if (t != 0) {
+ mReadyToRun = WOULD_BLOCK;
+ t->run("ClientRecordThread", ANDROID_PRIORITY_AUDIO);
+ tid = t->getTid(); // pid_t is unknown until run()
+ ALOGV("getTid=%d", tid);
+ if (tid == -1) {
+ tid = 0;
+ }
+ // thread blocks in readyToRun()
+ } else {
+ tid = 0; // not gettid()
+ }
+
cblk->lock.lock();
if (!(cblk->flags & CBLK_INVALID_MSK)) {
cblk->lock.unlock();
- ret = mAudioRecord->start();
+ ALOGV("mAudioRecord->start(tid=%d)", tid);
+ ret = mAudioRecord->start(tid);
cblk->lock.lock();
if (ret == DEAD_OBJECT) {
android_atomic_or(CBLK_INVALID_ON, &cblk->flags);
@@ -322,7 +337,9 @@ status_t AudioRecord::start()
cblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS;
cblk->waitTimeMs = 0;
if (t != 0) {
- t->run("ClientRecordThread", ANDROID_PRIORITY_AUDIO);
+ // thread unblocks in readyToRun() and returns NO_ERROR
+ mReadyToRun = NO_ERROR;
+ mCondition.signal();
} else {
mPreviousPriority = getpriority(PRIO_PROCESS, 0);
mPreviousSchedulingGroup = androidGetThreadSchedulingGroup(0);
@@ -330,6 +347,9 @@ status_t AudioRecord::start()
}
} else {
mActive = 0;
+ // thread unblocks in readyToRun() and returns NO_INIT
+ mReadyToRun = NO_INIT;
+ mCondition.signal();
}
}
@@ -522,7 +542,7 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
ALOGW( "obtainBuffer timed out (is the CPU pegged?) "
"user=%08x, server=%08x", cblk->user, cblk->server);
cblk->lock.unlock();
- result = mAudioRecord->start();
+ result = mAudioRecord->start(0); // callback thread hasn't changed
cblk->lock.lock();
if (result == DEAD_OBJECT) {
android_atomic_or(CBLK_INVALID_ON, &cblk->flags);
@@ -760,7 +780,7 @@ status_t AudioRecord::restoreRecord_l(audio_track_cblk_t*& cblk)
result = openRecord_l(cblk->sampleRate, mFormat, mChannelMask,
mFrameCount, mFlags, getInput_l());
if (result == NO_ERROR) {
- result = mAudioRecord->start();
+ result = mAudioRecord->start(0); // callback thread hasn't changed
}
if (result != NO_ERROR) {
mActive = false;
@@ -811,6 +831,15 @@ bool AudioRecord::ClientRecordThread::threadLoop()
return mReceiver.processAudioBuffer(this);
}
+status_t AudioRecord::ClientRecordThread::readyToRun()
+{
+ AutoMutex(mReceiver.mLock);
+ while (mReceiver.mReadyToRun == WOULD_BLOCK) {
+ mReceiver.mCondition.wait(mReceiver.mLock);
+ }
+ return mReceiver.mReadyToRun;
+}
+
// -------------------------------------------------------------------------
}; // namespace android
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 087d7b2096f3..aead9a1654be 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -1,4 +1,4 @@
-/* frameworks/base/media/libmedia/AudioTrack.cpp
+/*
**
** Copyright 2007, The Android Open Source Project
**
@@ -362,18 +362,26 @@ void AudioTrack::start()
cblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
cblk->waitTimeMs = 0;
android_atomic_and(~CBLK_DISABLED_ON, &cblk->flags);
+ pid_t tid;
if (t != 0) {
t->run("AudioTrackThread", ANDROID_PRIORITY_AUDIO);
+ tid = t->getTid(); // pid_t is unknown until run()
+ ALOGV("getTid=%d", tid);
+ if (tid == -1) {
+ tid = 0;
+ }
} else {
mPreviousPriority = getpriority(PRIO_PROCESS, 0);
mPreviousSchedulingGroup = androidGetThreadSchedulingGroup(0);
androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
+ tid = 0; // not gettid()
}
ALOGV("start %p before lock cblk %p", this, mCblk);
if (!(cblk->flags & CBLK_INVALID_MSK)) {
cblk->lock.unlock();
- status = mAudioTrack->start();
+ ALOGV("mAudioTrack->start(tid=%d)", tid);
+ status = mAudioTrack->start(tid);
cblk->lock.lock();
if (status == DEAD_OBJECT) {
android_atomic_or(CBLK_INVALID_ON, &cblk->flags);
@@ -591,26 +599,6 @@ status_t AudioTrack::setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCou
return NO_ERROR;
}
-status_t AudioTrack::getLoop(uint32_t *loopStart, uint32_t *loopEnd, int *loopCount) const
-{
- AutoMutex lock(mLock);
- if (loopStart != NULL) {
- *loopStart = mCblk->loopStart;
- }
- if (loopEnd != NULL) {
- *loopEnd = mCblk->loopEnd;
- }
- if (loopCount != NULL) {
- if (mCblk->loopCount < 0) {
- *loopCount = -1;
- } else {
- *loopCount = mCblk->loopCount;
- }
- }
-
- return NO_ERROR;
-}
-
status_t AudioTrack::setMarkerPosition(uint32_t marker)
{
if (mCbf == NULL) return INVALID_OPERATION;
@@ -784,7 +772,7 @@ status_t AudioTrack::createTrack_l(
}
}
} else {
- // Ensure that buffer alignment matches channelcount
+ // Ensure that buffer alignment matches channelCount
int channelCount = popcount(channelMask);
if (((uint32_t)sharedBuffer->pointer() & (channelCount | 1)) != 0) {
ALOGE("Invalid buffer alignement: address %p, channelCount %d", sharedBuffer->pointer(), channelCount);
@@ -895,7 +883,7 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount)
"user=%08x, server=%08x", this, cblk->user, cblk->server);
//unlock cblk mutex before calling mAudioTrack->start() (see issue #1617140)
cblk->lock.unlock();
- result = mAudioTrack->start();
+ result = mAudioTrack->start(0); // callback thread hasn't changed
cblk->lock.lock();
if (result == DEAD_OBJECT) {
android_atomic_or(CBLK_INVALID_ON, &cblk->flags);
@@ -927,7 +915,7 @@ create_new_track:
if (mActive && (cblk->flags & CBLK_DISABLED_MSK)) {
android_atomic_and(~CBLK_DISABLED_ON, &cblk->flags);
ALOGW("obtainBuffer() track %p disabled, restarting", this);
- mAudioTrack->start();
+ mAudioTrack->start(0); // callback thread hasn't changed
}
cblk->waitTimeMs = 0;
@@ -971,7 +959,8 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize)
if (mSharedBuffer != 0) return INVALID_OPERATION;
if (ssize_t(userSize) < 0) {
- // sanity-check. user is most-likely passing an error code.
+ // Sanity-check: user is most-likely passing an error code, and it would
+ // make the return value ambiguous (actualSize vs error).
ALOGE("AudioTrack::write(buffer=%p, size=%u (%d)",
buffer, userSize, userSize);
return BAD_VALUE;
@@ -994,8 +983,6 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize)
do {
audioBuffer.frameCount = userSize/frameSz;
- // Calling obtainBuffer() with a negative wait count causes
- // an (almost) infinite wait time.
status_t err = obtainBuffer(&audioBuffer, -1);
if (err < 0) {
// out of buffers, return #bytes written
@@ -1085,6 +1072,9 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
frames = mRemainingFrames;
}
+ // See description of waitCount parameter at declaration of obtainBuffer().
+ // The logic below prevents us from being stuck below at obtainBuffer()
+ // not being able to handle timed events (position, markers, loops).
int32_t waitCount = -1;
if (mUpdatePeriod || (!mMarkerReached && mMarkerPosition) || mLoopCount) {
waitCount = 1;
@@ -1094,9 +1084,6 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
audioBuffer.frameCount = frames;
- // Calling obtainBuffer() with a wait count of 1
- // limits wait time to WAIT_PERIOD_MS. This prevents from being
- // stuck here not being able to handle timed events (position, markers, loops).
status_t err = obtainBuffer(&audioBuffer, waitCount);
if (err < NO_ERROR) {
if (err != TIMED_OUT) {
@@ -1218,7 +1205,7 @@ status_t AudioTrack::restoreTrack_l(audio_track_cblk_t*& cblk, bool fromStart)
}
}
if (mActive) {
- result = mAudioTrack->start();
+ result = mAudioTrack->start(0); // callback thread hasn't changed
ALOGW_IF(result != NO_ERROR, "restoreTrack_l() start() failed status %d", result);
}
if (fromStart && result == NO_ERROR) {
diff --git a/media/libmedia/IAudioRecord.cpp b/media/libmedia/IAudioRecord.cpp
index 8c7a96023498..6b473c943692 100644
--- a/media/libmedia/IAudioRecord.cpp
+++ b/media/libmedia/IAudioRecord.cpp
@@ -42,10 +42,11 @@ public:
{
}
- virtual status_t start()
+ virtual status_t start(pid_t tid)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioRecord::getInterfaceDescriptor());
+ data.writeInt32(tid);
status_t status = remote()->transact(START, data, &reply);
if (status == NO_ERROR) {
status = reply.readInt32();
@@ -90,7 +91,7 @@ status_t BnAudioRecord::onTransact(
} break;
case START: {
CHECK_INTERFACE(IAudioRecord, data, reply);
- reply->writeInt32(start());
+ reply->writeInt32(start(data.readInt32()));
return NO_ERROR;
} break;
case STOP: {
diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp
index e6186193656b..a7958debe1ae 100644
--- a/media/libmedia/IAudioTrack.cpp
+++ b/media/libmedia/IAudioTrack.cpp
@@ -1,4 +1,4 @@
-/* //device/extlibs/pv/android/IAudioTrack.cpp
+/*
**
** Copyright 2007, The Android Open Source Project
**
@@ -58,10 +58,11 @@ public:
return cblk;
}
- virtual status_t start()
+ virtual status_t start(pid_t tid)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+ data.writeInt32(tid);
status_t status = remote()->transact(START, data, &reply);
if (status == NO_ERROR) {
status = reply.readInt32();
@@ -130,7 +131,7 @@ status_t BnAudioTrack::onTransact(
} break;
case START: {
CHECK_INTERFACE(IAudioTrack, data, reply);
- reply->writeInt32(start());
+ reply->writeInt32(start(data.readInt32()));
return NO_ERROR;
} break;
case STOP: {
diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp
index bff251b2fc6b..93ddca8d7053 100644
--- a/media/libmedia/MediaProfiles.cpp
+++ b/media/libmedia/MediaProfiles.cpp
@@ -25,7 +25,7 @@
#include <cutils/properties.h>
#include <expat.h>
#include <media/MediaProfiles.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/openmax/OMX_Video.h>
namespace android {
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index 6cb10aa4e3ad..54eb98a963c9 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -791,7 +791,7 @@ const unsigned char /*tone_type*/ ToneGenerator::sToneMappingTable[NUM_REGIONS-1
// generators, instantiates output audio track.
//
// Input:
-// streamType: Type of stream used for tone playback (enum AudioTrack::stream_type)
+// streamType: Type of stream used for tone playback
// volume: volume applied to tone (0.0 to 1.0)
//
// Output:
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index f1c47dd91b40..250425b5d5b0 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -1,4 +1,4 @@
-/* mediaplayer.cpp
+/*
**
** Copyright 2006, The Android Open Source Project
**
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index a0c20ae4a947..4df7f3d654c4 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1265,6 +1265,8 @@ MediaPlayerService::AudioOutput::AudioOutput(int sessionId)
mStreamType = AUDIO_STREAM_MUSIC;
mLeftVolume = 1.0;
mRightVolume = 1.0;
+ mPlaybackRatePermille = 1000;
+ mSampleRateHz = 0;
mLatency = 0;
mMsecsPerFrame = 0;
mAuxEffectId = 0;
@@ -1402,10 +1404,15 @@ status_t MediaPlayerService::AudioOutput::open(
ALOGV("setVolume");
t->setVolume(mLeftVolume, mRightVolume);
- mMsecsPerFrame = 1.e3 / (float) sampleRate;
+ mSampleRateHz = sampleRate;
+ mMsecsPerFrame = mPlaybackRatePermille / (float) sampleRate;
mLatency = t->latency();
mTrack = t;
+ status_t res = t->setSampleRate(mPlaybackRatePermille * mSampleRateHz / 1000);
+ if (res != NO_ERROR) {
+ return res;
+ }
t->setAuxEffectSendLevel(mSendLevel);
return t->attachAuxEffect(mAuxEffectId);;
}
@@ -1469,6 +1476,22 @@ void MediaPlayerService::AudioOutput::setVolume(float left, float right)
}
}
+status_t MediaPlayerService::AudioOutput::setPlaybackRatePermille(int32_t ratePermille)
+{
+ ALOGV("setPlaybackRatePermille(%d)", ratePermille);
+ status_t res = NO_ERROR;
+ if (mTrack) {
+ res = mTrack->setSampleRate(ratePermille * mSampleRateHz / 1000);
+ } else {
+ res = NO_INIT;
+ }
+ mPlaybackRatePermille = ratePermille;
+ if (mSampleRateHz != 0) {
+ mMsecsPerFrame = mPlaybackRatePermille / (float) mSampleRateHz;
+ }
+ return res;
+}
+
status_t MediaPlayerService::AudioOutput::setAuxEffectSendLevel(float level)
{
ALOGV("setAuxEffectSendLevel(%f)", level);
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index fa71d11c6f2b..52af64de8035 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -95,6 +95,7 @@ class MediaPlayerService : public BnMediaPlayerService
virtual void close();
void setAudioStreamType(audio_stream_type_t streamType) { mStreamType = streamType; }
void setVolume(float left, float right);
+ virtual status_t setPlaybackRatePermille(int32_t ratePermille);
status_t setAuxEffectSendLevel(float level);
status_t attachAuxEffect(int effectId);
virtual status_t dump(int fd, const Vector<String16>& args) const;
@@ -112,6 +113,8 @@ class MediaPlayerService : public BnMediaPlayerService
audio_stream_type_t mStreamType;
float mLeftVolume;
float mRightVolume;
+ int32_t mPlaybackRatePermille;
+ uint32_t mSampleRateHz; // sample rate of the content, as set in open()
float mMsecsPerFrame;
uint32_t mLatency;
int mSessionId;
@@ -152,6 +155,7 @@ class MediaPlayerService : public BnMediaPlayerService
virtual void close() {}
void setAudioStreamType(audio_stream_type_t streamType) {}
void setVolume(float left, float right) {}
+ virtual status_t setPlaybackRatePermille(int32_t ratePermille) { return INVALID_OPERATION; }
uint32_t sampleRate() const { return mSampleRate; }
audio_format_t format() const { return mFormat; }
size_t size() const { return mSize; }
diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp
index 6d7771a8485a..052ebf04df2c 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.cpp
+++ b/media/libmediaplayerservice/StagefrightPlayer.cpp
@@ -176,7 +176,7 @@ void StagefrightPlayer::setAudioSink(const sp<AudioSink> &audioSink) {
}
status_t StagefrightPlayer::setParameter(int key, const Parcel &request) {
- ALOGV("setParameter");
+ ALOGV("setParameter(key=%d)", key);
return mPlayer->setParameter(key, request);
}
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 4632016cf9b9..fe519b095f30 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -24,6 +24,7 @@
#include <binder/IServiceManager.h>
#include <media/IMediaPlayerService.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/AudioSource.h>
#include <media/stagefright/AMRWriter.h>
#include <media/stagefright/AACWriter.h>
@@ -31,7 +32,6 @@
#include <media/stagefright/CameraSourceTimeLapse.h>
#include <media/stagefright/MPEG2TSWriter.h>
#include <media/stagefright/MPEG4Writer.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/OMXClient.h>
@@ -241,8 +241,8 @@ status_t StagefrightRecorder::setOutputFile(const char *path) {
status_t StagefrightRecorder::setOutputFile(int fd, int64_t offset, int64_t length) {
ALOGV("setOutputFile: %d, %lld, %lld", fd, offset, length);
// These don't make any sense, do they?
- CHECK_EQ(offset, 0);
- CHECK_EQ(length, 0);
+ CHECK_EQ(offset, 0ll);
+ CHECK_EQ(length, 0ll);
if (fd < 0) {
ALOGE("Invalid file descriptor: %d", fd);
@@ -734,7 +734,7 @@ status_t StagefrightRecorder::prepare() {
}
status_t StagefrightRecorder::start() {
- CHECK(mOutputFd >= 0);
+ CHECK_GE(mOutputFd, 0);
if (mWriter != NULL) {
ALOGE("File writer is not avaialble");
@@ -837,7 +837,7 @@ sp<MediaSource> StagefrightRecorder::createAudioSource() {
}
OMXClient client;
- CHECK_EQ(client.connect(), OK);
+ CHECK_EQ(client.connect(), (status_t)OK);
sp<MediaSource> audioEncoder =
OMXCodec::Create(client.interface(), encMeta,
@@ -850,9 +850,9 @@ sp<MediaSource> StagefrightRecorder::createAudioSource() {
status_t StagefrightRecorder::startAACRecording() {
// FIXME:
// Add support for OUTPUT_FORMAT_AAC_ADIF
- CHECK(mOutputFormat == OUTPUT_FORMAT_AAC_ADTS);
+ CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_AAC_ADTS);
- CHECK(mAudioEncoder == AUDIO_ENCODER_AAC);
+ CHECK_EQ(mAudioEncoder, AUDIO_ENCODER_AAC);
CHECK(mAudioSource != AUDIO_SOURCE_CNT);
mWriter = new AACWriter(mOutputFd);
@@ -1386,7 +1386,7 @@ status_t StagefrightRecorder::setupVideoEncoder(
}
OMXClient client;
- CHECK_EQ(client.connect(), OK);
+ CHECK_EQ(client.connect(), (status_t)OK);
uint32_t encoder_flags = 0;
if (mIsMetaDataStoredInVideoBuffers) {
diff --git a/media/libstagefright/AACExtractor.cpp b/media/libstagefright/AACExtractor.cpp
index 33f22f205063..4d1072fb5d28 100644
--- a/media/libstagefright/AACExtractor.cpp
+++ b/media/libstagefright/AACExtractor.cpp
@@ -23,9 +23,9 @@
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp
index 5a2834725baf..03dcbf90ff43 100644
--- a/media/libstagefright/AMRExtractor.cpp
+++ b/media/libstagefright/AMRExtractor.cpp
@@ -20,9 +20,9 @@
#include "include/AMRExtractor.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp
index 59b4ca7b4a52..ca856409ba70 100644
--- a/media/libstagefright/AMRWriter.cpp
+++ b/media/libstagefright/AMRWriter.cpp
@@ -14,9 +14,9 @@
* limitations under the License.
*/
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/AMRWriter.h>
#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 9a9c3efa48d3..df275664533b 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -268,6 +268,16 @@ bool AudioPlayer::reachedEOS(status_t *finalStatus) {
return mReachedEOS;
}
+status_t AudioPlayer::setPlaybackRatePermille(int32_t ratePermille) {
+ if (mAudioSink.get() != NULL) {
+ return mAudioSink->setPlaybackRatePermille(ratePermille);
+ } else if (mAudioTrack != NULL){
+ return mAudioTrack->setSampleRate(ratePermille * mSampleRate / 1000);
+ } else {
+ return NO_INIT;
+ }
+}
+
// static
size_t AudioPlayer::AudioSinkCallback(
MediaPlayerBase::AudioSink *audioSink,
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index aacfbddccd5b..70945e33cdc7 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -1360,7 +1360,7 @@ void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
mAudioTrack = source;
}
-void AwesomePlayer::addTextSource(sp<MediaSource> source) {
+void AwesomePlayer::addTextSource(const sp<MediaSource>& source) {
Mutex::Autolock autoLock(mTimedTextLock);
CHECK(source != NULL);
@@ -2251,6 +2251,14 @@ status_t AwesomePlayer::setParameter(int key, const Parcel &request) {
{
return setCacheStatCollectFreq(request);
}
+ case KEY_PARAMETER_PLAYBACK_RATE_PERMILLE:
+ {
+ if (mAudioPlayer != NULL) {
+ return mAudioPlayer->setPlaybackRatePermille(request.readInt32());
+ } else {
+ return NO_INIT;
+ }
+ }
default:
{
return ERROR_UNSUPPORTED;
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 228659c7c1ee..ed1d5f46ba94 100755
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -20,8 +20,8 @@
#include <OMX_Component.h>
#include <binder/IPCThreadState.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/CameraSource.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
@@ -114,7 +114,7 @@ static int32_t getColorFormat(const char* colorFormat) {
ALOGE("Uknown color format (%s), please add it to "
"CameraSource::getColorFormat", colorFormat);
- CHECK_EQ(0, "Unknown color format");
+ CHECK(!"Unknown color format");
}
CameraSource *CameraSource::Create() {
@@ -517,7 +517,7 @@ status_t CameraSource::initWithCameraAccess(
// This CHECK is good, since we just passed the lock/unlock
// check earlier by calling mCamera->setParameters().
- CHECK_EQ(OK, mCamera->setPreviewDisplay(mSurface));
+ CHECK_EQ((status_t)OK, mCamera->setPreviewDisplay(mSurface));
// By default, do not store metadata in video buffers
mIsMetaDataStoredInVideoBuffers = false;
@@ -566,7 +566,8 @@ void CameraSource::startCameraRecording() {
if (mCameraFlags & FLAGS_HOT_CAMERA) {
mCamera->unlock();
mCamera.clear();
- CHECK_EQ(OK, mCameraRecordingProxy->startRecording(new ProxyListener(this)));
+ CHECK_EQ((status_t)OK,
+ mCameraRecordingProxy->startRecording(new ProxyListener(this)));
} else {
mCamera->setListener(new CameraSourceListener(this));
mCamera->startRecording();
@@ -718,7 +719,7 @@ void CameraSource::signalBufferReturned(MediaBuffer *buffer) {
return;
}
}
- CHECK_EQ(0, "signalBufferReturned: bogus buffer");
+ CHECK(!"signalBufferReturned: bogus buffer");
}
status_t CameraSource::read(
diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp
index 83d67b93748b..26ce7ae9a88f 100644
--- a/media/libstagefright/CameraSourceTimeLapse.cpp
+++ b/media/libstagefright/CameraSourceTimeLapse.cpp
@@ -20,9 +20,9 @@
#include <binder/IPCThreadState.h>
#include <binder/MemoryBase.h>
#include <binder/MemoryHeapBase.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/CameraSource.h>
#include <media/stagefright/CameraSourceTimeLapse.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MetaData.h>
#include <camera/Camera.h>
#include <camera/CameraParameters.h>
diff --git a/media/libstagefright/DRMExtractor.cpp b/media/libstagefright/DRMExtractor.cpp
index afc4a803518d..524c3aad099e 100644
--- a/media/libstagefright/DRMExtractor.cpp
+++ b/media/libstagefright/DRMExtractor.cpp
@@ -23,6 +23,7 @@
#include <arpa/inet.h>
#include <utils/String8.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/Utils.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaSource.h>
@@ -30,7 +31,6 @@
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDebug.h>
#include <drm/drm_framework_common.h>
#include <utils/Errors.h>
diff --git a/media/libstagefright/FileSource.cpp b/media/libstagefright/FileSource.cpp
index 01f53e4b6eb6..73c8d033d150 100644
--- a/media/libstagefright/FileSource.cpp
+++ b/media/libstagefright/FileSource.cpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaDebug.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
diff --git a/media/libstagefright/JPEGSource.cpp b/media/libstagefright/JPEGSource.cpp
index e818115b31f1..bafa4b219e47 100644
--- a/media/libstagefright/JPEGSource.cpp
+++ b/media/libstagefright/JPEGSource.cpp
@@ -18,10 +18,10 @@
#define LOG_TAG "JPEGSource"
#include <utils/Log.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/JPEGSource.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
@@ -59,7 +59,7 @@ JPEGSource::JPEGSource(const sp<DataSource> &source)
mWidth(0),
mHeight(0),
mOffset(0) {
- CHECK_EQ(parseJPEG(), OK);
+ CHECK_EQ(parseJPEG(), (status_t)OK);
CHECK(mSource->getSize(&mSize) == OK);
}
diff --git a/media/libstagefright/MediaBuffer.cpp b/media/libstagefright/MediaBuffer.cpp
index 96271e41788e..11b80bf42429 100644
--- a/media/libstagefright/MediaBuffer.cpp
+++ b/media/libstagefright/MediaBuffer.cpp
@@ -22,8 +22,8 @@
#include <stdlib.h>
#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MetaData.h>
#include <ui/GraphicBuffer.h>
@@ -157,7 +157,7 @@ void MediaBuffer::reset() {
}
MediaBuffer::~MediaBuffer() {
- CHECK_EQ(mObserver, NULL);
+ CHECK(mObserver == NULL);
if (mOwnsData && mData != NULL) {
free(mData);
@@ -188,7 +188,7 @@ int MediaBuffer::refcount() const {
}
MediaBuffer *MediaBuffer::clone() {
- CHECK_EQ(mGraphicBuffer, NULL);
+ CHECK(mGraphicBuffer == NULL);
MediaBuffer *buffer = new MediaBuffer(mData, mSize);
buffer->set_range(mRangeOffset, mRangeLength);
diff --git a/media/libstagefright/MediaBufferGroup.cpp b/media/libstagefright/MediaBufferGroup.cpp
index c8d05f4d8e89..80aae51c86b2 100644
--- a/media/libstagefright/MediaBufferGroup.cpp
+++ b/media/libstagefright/MediaBufferGroup.cpp
@@ -17,9 +17,9 @@
#define LOG_TAG "MediaBufferGroup"
#include <utils/Log.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
namespace android {
diff --git a/media/libstagefright/MediaSourceSplitter.cpp b/media/libstagefright/MediaSourceSplitter.cpp
index 8af06947225f..3b64ded7338b 100644
--- a/media/libstagefright/MediaSourceSplitter.cpp
+++ b/media/libstagefright/MediaSourceSplitter.cpp
@@ -18,8 +18,8 @@
#define LOG_TAG "MediaSourceSplitter"
#include <utils/Log.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaSourceSplitter.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MetaData.h>
diff --git a/media/libstagefright/MetaData.cpp b/media/libstagefright/MetaData.cpp
index 884f3b423012..66dec905c35c 100644
--- a/media/libstagefright/MetaData.cpp
+++ b/media/libstagefright/MetaData.cpp
@@ -17,7 +17,7 @@
#include <stdlib.h>
#include <string.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MetaData.h>
namespace android {
diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index 73efc278224f..5e79e788816d 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -21,10 +21,10 @@
#include "include/OggExtractor.h"
#include <cutils/properties.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
diff --git a/media/libstagefright/SampleIterator.cpp b/media/libstagefright/SampleIterator.cpp
index 81ec5c109f92..eae721b5fb78 100644
--- a/media/libstagefright/SampleIterator.cpp
+++ b/media/libstagefright/SampleIterator.cpp
@@ -22,8 +22,8 @@
#include <arpa/inet.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/Utils.h>
#include "include/SampleTable.h"
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 43bfd9e30c52..35f9c1f7aae8 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -20,10 +20,10 @@
#include "include/StagefrightMetadataRetriever.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/ColorConverter.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/OMXCodec.h>
@@ -37,7 +37,7 @@ StagefrightMetadataRetriever::StagefrightMetadataRetriever()
ALOGV("StagefrightMetadataRetriever()");
DataSource::RegisterDefaultSniffers();
- CHECK_EQ(mClient.connect(), OK);
+ CHECK_EQ(mClient.connect(), (status_t)OK);
}
StagefrightMetadataRetriever::~StagefrightMetadataRetriever() {
@@ -169,7 +169,7 @@ static VideoFrame *extractVideoFrameWithCodecFlags(
|| (buffer != NULL && buffer->range_length() == 0));
if (err != OK) {
- CHECK_EQ(buffer, NULL);
+ CHECK(buffer == NULL);
ALOGV("decoding frame failed.");
decoder->stop();
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
index d0683814a724..aa047d61fbdc 100644
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -16,14 +16,14 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "SurfaceMediaSource"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/SurfaceMediaSource.h>
-#include <ui/GraphicBuffer.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/openmax/OMX_IVCommon.h>
#include <media/stagefright/MetadataBufferType.h>
+#include <ui/GraphicBuffer.h>
#include <surfaceflinger/ISurfaceComposer.h>
#include <surfaceflinger/SurfaceComposerClient.h>
#include <surfaceflinger/IGraphicBufferAlloc.h>
@@ -855,7 +855,7 @@ void SurfaceMediaSource::signalBufferReturned(MediaBuffer *buffer) {
}
if (!foundBuffer) {
- CHECK_EQ(0, "signalBufferReturned: bogus buffer");
+ CHECK(!"signalBufferReturned: bogus buffer");
}
}
diff --git a/media/libstagefright/ThrottledSource.cpp b/media/libstagefright/ThrottledSource.cpp
index 88e07b06915a..b1fcafdafc50 100644
--- a/media/libstagefright/ThrottledSource.cpp
+++ b/media/libstagefright/ThrottledSource.cpp
@@ -16,7 +16,7 @@
#include "include/ThrottledSource.h"
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
namespace android {
diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp
index 12c9c36606cd..f4b5d4f9876e 100644
--- a/media/libstagefright/TimedEventQueue.cpp
+++ b/media/libstagefright/TimedEventQueue.cpp
@@ -31,7 +31,7 @@
#include <sys/prctl.h>
#include <sys/time.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#ifdef ANDROID_SIMULATOR
#include <jni.h>
diff --git a/media/libstagefright/VideoSourceDownSampler.cpp b/media/libstagefright/VideoSourceDownSampler.cpp
index 1b669904f5f5..90a42c9ae5ef 100644
--- a/media/libstagefright/VideoSourceDownSampler.cpp
+++ b/media/libstagefright/VideoSourceDownSampler.cpp
@@ -17,9 +17,9 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "VideoSourceDownSampler"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/VideoSourceDownSampler.h>
#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/YUVImage.h>
#include <media/stagefright/YUVCanvas.h>
diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp
index 0bcaf0800800..501f4806b820 100644
--- a/media/libstagefright/WAVExtractor.cpp
+++ b/media/libstagefright/WAVExtractor.cpp
@@ -20,9 +20,9 @@
#include "include/WAVExtractor.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
@@ -217,7 +217,7 @@ status_t WAVExtractor::init() {
kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_G711_ALAW);
break;
default:
- CHECK_EQ(mWaveFormat, WAVE_FORMAT_MULAW);
+ CHECK_EQ(mWaveFormat, (uint16_t)WAVE_FORMAT_MULAW);
mTrackMeta->setCString(
kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_G711_MLAW);
break;
@@ -362,7 +362,7 @@ status_t WAVSource::read(
// Convert 8-bit unsigned samples to 16-bit signed.
MediaBuffer *tmp;
- CHECK_EQ(mGroup->acquire_buffer(&tmp), OK);
+ CHECK_EQ(mGroup->acquire_buffer(&tmp), (status_t)OK);
// The new buffer holds the sample number of samples, but each
// one is 2 bytes wide.
diff --git a/media/libstagefright/WVMExtractor.cpp b/media/libstagefright/WVMExtractor.cpp
index 1e4e049edb7f..c7ad513baf10 100644
--- a/media/libstagefright/WVMExtractor.cpp
+++ b/media/libstagefright/WVMExtractor.cpp
@@ -21,6 +21,7 @@
#include <arpa/inet.h>
#include <utils/String8.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/Utils.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaSource.h>
@@ -28,7 +29,6 @@
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDebug.h>
#include <dlfcn.h>
#include <utils/Errors.h>
diff --git a/media/libstagefright/codecs/aacenc/AACEncoder.cpp b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
index 2b8633d746ac..8b5007eb141f 100644
--- a/media/libstagefright/codecs/aacenc/AACEncoder.cpp
+++ b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
@@ -22,8 +22,8 @@
#include "voAAC.h"
#include "cmnMemory.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
@@ -114,8 +114,8 @@ status_t AACEncoder::setAudioSpecificConfigData() {
ALOGV("setAudioSpecificConfigData: %d hz, %d bps, and %d channels",
mSampleRate, mBitRate, mChannels);
- int32_t index;
- CHECK_EQ(OK, getSampleRateTableIndex(mSampleRate, index));
+ int32_t index = 0;
+ CHECK_EQ((status_t)OK, getSampleRateTableIndex(mSampleRate, index));
if (mChannels > 2 || mChannels <= 0) {
ALOGE("Unsupported number of channels(%d)", mChannels);
return UNKNOWN_ERROR;
@@ -142,7 +142,7 @@ status_t AACEncoder::start(MetaData *params) {
mBufferGroup = new MediaBufferGroup;
mBufferGroup->add_buffer(new MediaBuffer(2048));
- CHECK_EQ(OK, initCheck());
+ CHECK_EQ((status_t)OK, initCheck());
mNumInputSamples = 0;
mAnchorTimeUs = 0;
@@ -183,7 +183,7 @@ status_t AACEncoder::stop() {
mSource->stop();
if (mEncoderHandle) {
- CHECK_EQ(VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
+ CHECK_EQ((VO_U32)VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
mEncoderHandle = NULL;
}
delete mApiHandle;
@@ -223,7 +223,7 @@ status_t AACEncoder::read(
CHECK(options == NULL || !options->getSeekTo(&seekTimeUs, &mode));
MediaBuffer *buffer;
- CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK);
+ CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), (status_t)OK);
uint8_t *outPtr = (uint8_t *)buffer->data();
bool readFromSource = false;
int64_t wallClockTimeUs = -1;
@@ -255,7 +255,7 @@ status_t AACEncoder::read(
}
size_t align = mInputBuffer->range_length() % sizeof(int16_t);
- CHECK_EQ(align, 0);
+ CHECK_EQ(align, (size_t)0);
int64_t timeUs;
if (mInputBuffer->meta_data()->findInt64(kKeyDriftTime, &timeUs)) {
diff --git a/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp b/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp
index 3afbc4f51985..27d7e4d74a06 100644
--- a/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp
+++ b/media/libstagefright/codecs/amrnb/enc/AMRNBEncoder.cpp
@@ -18,8 +18,8 @@
#include "gsmamr_enc.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
@@ -210,7 +210,7 @@ status_t AMRNBEncoder::read(
}
MediaBuffer *buffer;
- CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK);
+ CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), (status_t)OK);
uint8_t *outPtr = (uint8_t *)buffer->data();
diff --git a/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp b/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp
index 60b1163eef31..7fd3a9505e10 100644
--- a/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp
+++ b/media/libstagefright/codecs/amrwbenc/AMRWBEncoder.cpp
@@ -22,8 +22,8 @@
#include "voAMRWB.h"
#include "cmnMemory.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
@@ -134,7 +134,7 @@ status_t AMRWBEncoder::start(MetaData *params) {
// The largest buffer size is header + 477 bits
mBufferGroup->add_buffer(new MediaBuffer(1024));
- CHECK_EQ(OK, initCheck());
+ CHECK_EQ((status_t)OK, initCheck());
mNumFramesOutput = 0;
@@ -163,7 +163,7 @@ status_t AMRWBEncoder::stop() {
mBufferGroup = NULL;
- CHECK_EQ(VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
+ CHECK_EQ((VO_U32)VO_ERR_NONE, mApiHandle->Uninit(mEncoderHandle));
mEncoderHandle = NULL;
delete mApiHandle;
@@ -222,7 +222,7 @@ status_t AMRWBEncoder::read(
}
size_t align = mInputBuffer->range_length() % sizeof(int16_t);
- CHECK_EQ(align, 0);
+ CHECK_EQ(align, (size_t)0);
int64_t timeUs;
if (mInputBuffer->meta_data()->findInt64(kKeyDriftTime, &timeUs)) {
@@ -271,7 +271,7 @@ status_t AMRWBEncoder::read(
CHECK(VO_ERR_NONE == mApiHandle->SetInputData(mEncoderHandle,&inputData));
MediaBuffer *buffer;
- CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), OK);
+ CHECK_EQ(mBufferGroup->acquire_buffer(&buffer), (status_t)OK);
uint8_t *outPtr = (uint8_t *)buffer->data();
VO_CODECBUFFER outputData;
diff --git a/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp b/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
index e202a2b64992..7533f07736c9 100644
--- a/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
+++ b/media/libstagefright/codecs/avc/enc/AVCEncoder.cpp
@@ -24,8 +24,8 @@
#include "avcenc_int.h"
#include "OMX_Video.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
@@ -417,7 +417,7 @@ status_t AVCEncoder::read(
*out = NULL;
MediaBuffer *outputBuffer;
- CHECK_EQ(OK, mGroup->acquire_buffer(&outputBuffer));
+ CHECK_EQ((status_t)OK, mGroup->acquire_buffer(&outputBuffer));
uint8_t *outPtr = (uint8_t *) outputBuffer->data();
uint32_t dataLength = outputBuffer->size();
@@ -557,9 +557,9 @@ status_t AVCEncoder::read(
encoderStatus = PVAVCEncodeNAL(mHandle, outPtr, &dataLength, &type);
if (encoderStatus == AVCENC_SUCCESS) {
outputBuffer->meta_data()->setInt32(kKeyIsSyncFrame, mIsIDRFrame);
- CHECK_EQ(NULL, PVAVCEncGetOverrunBuffer(mHandle));
+ CHECK(NULL == PVAVCEncGetOverrunBuffer(mHandle));
} else if (encoderStatus == AVCENC_PICTURE_READY) {
- CHECK_EQ(NULL, PVAVCEncGetOverrunBuffer(mHandle));
+ CHECK(NULL == PVAVCEncGetOverrunBuffer(mHandle));
if (mIsIDRFrame) {
outputBuffer->meta_data()->setInt32(kKeyIsSyncFrame, mIsIDRFrame);
mIsIDRFrame = 0;
diff --git a/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp
index d53860336285..20b0f8da2d90 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp
+++ b/media/libstagefright/codecs/m4v_h263/enc/M4vH263Encoder.cpp
@@ -23,8 +23,8 @@
#include "mp4enc_api.h"
#include "OMX_Video.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
@@ -379,7 +379,7 @@ status_t M4vH263Encoder::read(
*out = NULL;
MediaBuffer *outputBuffer;
- CHECK_EQ(OK, mGroup->acquire_buffer(&outputBuffer));
+ CHECK_EQ((status_t)OK, mGroup->acquire_buffer(&outputBuffer));
uint8_t *outPtr = (uint8_t *) outputBuffer->data();
int32_t dataLength = outputBuffer->size();
@@ -467,7 +467,7 @@ status_t M4vH263Encoder::read(
mInputBuffer = NULL;
return UNKNOWN_ERROR;
}
- CHECK_EQ(NULL, PVGetOverrunBuffer(mHandle));
+ CHECK(NULL == PVGetOverrunBuffer(mHandle));
if (hintTrack.CodeType == 0) { // I-frame serves as sync frame
outputBuffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
}
diff --git a/media/libstagefright/colorconversion/ColorConverter.cpp b/media/libstagefright/colorconversion/ColorConverter.cpp
index f3ef3de9724d..597167f91e2c 100644
--- a/media/libstagefright/colorconversion/ColorConverter.cpp
+++ b/media/libstagefright/colorconversion/ColorConverter.cpp
@@ -18,8 +18,8 @@
#define LOG_TAG "ColorConverter"
#include <utils/Log.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/ColorConverter.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaErrors.h>
namespace android {
diff --git a/media/libstagefright/id3/Android.mk b/media/libstagefright/id3/Android.mk
index 23c8e448aa95..ff35d4a77521 100644
--- a/media/libstagefright/id3/Android.mk
+++ b/media/libstagefright/id3/Android.mk
@@ -16,7 +16,7 @@ LOCAL_SRC_FILES := \
testid3.cpp
LOCAL_SHARED_LIBRARIES := \
- libstagefright libutils libbinder
+ libstagefright libutils libbinder libstagefright_foundation
LOCAL_STATIC_LIBRARIES := \
libstagefright_id3
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index 6dde9d8201a6..2e929265f438 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -20,8 +20,8 @@
#include "../include/ID3.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/Utils.h>
#include <utils/String8.h>
#include <byteswap.h>
diff --git a/media/libstagefright/id3/testid3.cpp b/media/libstagefright/id3/testid3.cpp
index 07410457e55e..bc4572cc214d 100644
--- a/media/libstagefright/id3/testid3.cpp
+++ b/media/libstagefright/id3/testid3.cpp
@@ -23,7 +23,7 @@
#include <binder/ProcessState.h>
#include <media/stagefright/FileSource.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#define MAXPATHLEN 256
@@ -70,7 +70,7 @@ static void hexdump(const void *_data, size_t size) {
void scanFile(const char *path) {
sp<FileSource> file = new FileSource(path);
- CHECK_EQ(file->initCheck(), OK);
+ CHECK_EQ(file->initCheck(), (status_t)OK);
ID3 tag(file);
if (!tag.isValid()) {
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index a7a3d4781633..4c7bfa684a13 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -258,7 +258,7 @@ private:
void setVideoSource(sp<MediaSource> source);
status_t initVideoDecoder(uint32_t flags = 0);
- void addTextSource(sp<MediaSource> source);
+ void addTextSource(const sp<MediaSource>& source);
void onStreamDone();
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index 03033f51e4d9..e1589b44c887 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -22,8 +22,8 @@
#include "include/LiveSession.h"
#include "include/NuCachedSource2.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index ace883c7f6b5..f11fcd20b9f7 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -25,7 +25,7 @@
#include "../include/OMXNodeInstance.h"
#include <binder/IMemory.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <utils/threads.h>
#include "OMXMaster.h"
@@ -102,7 +102,7 @@ OMX::CallbackDispatcher::~CallbackDispatcher() {
if (status != WOULD_BLOCK) {
// Other than join to self, the only other error return codes are
// whatever readyToRun() returns, and we don't override that
- CHECK_EQ(status, NO_ERROR);
+ CHECK_EQ(status, (status_t)NO_ERROR);
}
}
diff --git a/media/libstagefright/omx/OMXComponentBase.cpp b/media/libstagefright/omx/OMXComponentBase.cpp
index 35227a0e262f..7d11dcee5b91 100644
--- a/media/libstagefright/omx/OMXComponentBase.cpp
+++ b/media/libstagefright/omx/OMXComponentBase.cpp
@@ -18,7 +18,7 @@
#include <stdlib.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
namespace android {
@@ -33,7 +33,7 @@ OMXComponentBase::OMXComponentBase(
OMXComponentBase::~OMXComponentBase() {}
void OMXComponentBase::setComponentHandle(OMX_COMPONENTTYPE *handle) {
- CHECK_EQ(mComponentHandle, NULL);
+ CHECK(mComponentHandle == NULL);
mComponentHandle = handle;
}
diff --git a/media/libstagefright/omx/OMXMaster.cpp b/media/libstagefright/omx/OMXMaster.cpp
index d69893935fa0..6b6d0ab9eef9 100644
--- a/media/libstagefright/omx/OMXMaster.cpp
+++ b/media/libstagefright/omx/OMXMaster.cpp
@@ -24,7 +24,7 @@
#include <dlfcn.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
namespace android {
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 8938e3311beb..099c4f50aa74 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -24,8 +24,8 @@
#include <OMX_Component.h>
#include <binder/IMemory.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/HardwareAPI.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaErrors.h>
namespace android {
@@ -91,11 +91,11 @@ OMXNodeInstance::OMXNodeInstance(
}
OMXNodeInstance::~OMXNodeInstance() {
- CHECK_EQ(mHandle, NULL);
+ CHECK(mHandle == NULL);
}
void OMXNodeInstance::setHandle(OMX::node_id node_id, OMX_HANDLETYPE handle) {
- CHECK_EQ(mHandle, NULL);
+ CHECK(mHandle == NULL);
mNodeID = node_id;
mHandle = handle;
}
diff --git a/media/libstagefright/omx/tests/Android.mk b/media/libstagefright/omx/tests/Android.mk
index 41c08be74275..0c0a70c22bc8 100644
--- a/media/libstagefright/omx/tests/Android.mk
+++ b/media/libstagefright/omx/tests/Android.mk
@@ -5,7 +5,7 @@ LOCAL_SRC_FILES = \
OMXHarness.cpp \
LOCAL_SHARED_LIBRARIES := \
- libstagefright libbinder libmedia libutils
+ libstagefright libbinder libmedia libutils libstagefright_foundation
LOCAL_C_INCLUDES := \
$(JNI_H_INCLUDE) \
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index 8faf54494aa8..fab1771004be 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -26,9 +26,9 @@
#include <binder/IServiceManager.h>
#include <binder/MemoryDealer.h>
#include <media/IMediaPlayerService.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaExtractor.h>
@@ -155,7 +155,7 @@ status_t Harness::dequeueMessageForNodeIgnoringBuffers(
if (err == TIMED_OUT) {
return err;
}
- CHECK_EQ(err, OK);
+ CHECK_EQ(err, (status_t)OK);
}
}
@@ -317,7 +317,7 @@ status_t Harness::testStateTransitions(
EXPECT_SUCCESS(err, "allocatePortBuffers(input)");
err = dequeueMessageForNode(node, &msg, DEFAULT_TIMEOUT);
- CHECK_EQ(err, TIMED_OUT);
+ CHECK_EQ(err, (status_t)TIMED_OUT);
Vector<Buffer> outputBuffers;
err = allocatePortBuffers(dealer, node, 1, &outputBuffers);
@@ -412,7 +412,7 @@ status_t Harness::testStateTransitions(
// Make sure node doesn't just transition to loaded before we are done
// freeing all input and output buffers.
err = dequeueMessageForNode(node, &msg, DEFAULT_TIMEOUT);
- CHECK_EQ(err, TIMED_OUT);
+ CHECK_EQ(err, (status_t)TIMED_OUT);
for (size_t i = 0; i < inputBuffers.size(); ++i) {
err = mOMX->freeBuffer(node, 0, inputBuffers[i].mID);
@@ -420,7 +420,7 @@ status_t Harness::testStateTransitions(
}
err = dequeueMessageForNode(node, &msg, DEFAULT_TIMEOUT);
- CHECK_EQ(err, TIMED_OUT);
+ CHECK_EQ(err, (status_t)TIMED_OUT);
for (size_t i = 0; i < outputBuffers.size(); ++i) {
err = mOMX->freeBuffer(node, 1, outputBuffers[i].mID);
@@ -584,7 +584,7 @@ status_t Harness::testSeek(
return UNKNOWN_ERROR;
}
- CHECK_EQ(seekSource->start(), OK);
+ CHECK_EQ(seekSource->start(), (status_t)OK);
sp<MediaSource> codec = OMXCodec::Create(
mOMX, source->getFormat(), false /* createEncoder */,
@@ -592,7 +592,7 @@ status_t Harness::testSeek(
CHECK(codec != NULL);
- CHECK_EQ(codec->start(), OK);
+ CHECK_EQ(codec->start(), (status_t)OK);
int64_t durationUs;
CHECK(source->getFormat()->findInt64(kKeyDuration, &durationUs));
@@ -638,7 +638,7 @@ status_t Harness::testSeek(
requestedSeekTimeUs, MediaSource::ReadOptions::SEEK_NEXT_SYNC);
if (seekSource->read(&buffer, &options) != OK) {
- CHECK_EQ(buffer, NULL);
+ CHECK(buffer == NULL);
actualSeekTimeUs = -1;
} else {
CHECK(buffer != NULL);
@@ -659,7 +659,7 @@ status_t Harness::testSeek(
err = codec->read(&buffer, &options);
options.clearSeekTo();
if (err == INFO_FORMAT_CHANGED) {
- CHECK_EQ(buffer, NULL);
+ CHECK(buffer == NULL);
continue;
}
if (err == OK) {
@@ -670,7 +670,7 @@ status_t Harness::testSeek(
continue;
}
} else {
- CHECK_EQ(buffer, NULL);
+ CHECK(buffer == NULL);
}
break;
@@ -679,7 +679,7 @@ status_t Harness::testSeek(
if (requestedSeekTimeUs < 0) {
// Linear read.
if (err != OK) {
- CHECK_EQ(buffer, NULL);
+ CHECK(buffer == NULL);
} else {
CHECK(buffer != NULL);
buffer->release();
@@ -694,8 +694,8 @@ status_t Harness::testSeek(
"We attempted to seek beyond EOS and expected "
"ERROR_END_OF_STREAM to be returned, but instead "
"we found some other error.");
- CHECK_EQ(err, ERROR_END_OF_STREAM);
- CHECK_EQ(buffer, NULL);
+ CHECK_EQ(err, (status_t)ERROR_END_OF_STREAM);
+ CHECK(buffer == NULL);
} else {
EXPECT(err == OK,
"Expected a valid buffer to be returned from "
@@ -715,7 +715,7 @@ status_t Harness::testSeek(
buffer->release();
buffer = NULL;
- CHECK_EQ(codec->stop(), OK);
+ CHECK_EQ(codec->stop(), (status_t)OK);
return UNKNOWN_ERROR;
}
@@ -725,7 +725,7 @@ status_t Harness::testSeek(
}
}
- CHECK_EQ(codec->stop(), OK);
+ CHECK_EQ(codec->stop(), (status_t)OK);
return OK;
}
@@ -841,7 +841,7 @@ int main(int argc, char **argv) {
srand(seed);
sp<Harness> h = new Harness;
- CHECK_EQ(h->initCheck(), OK);
+ CHECK_EQ(h->initCheck(), (status_t)OK);
if (argc == 0) {
h->testAll();
diff --git a/media/libstagefright/tests/SurfaceMediaSource_test.cpp b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
index 76b507f99123..d7cec04e0c93 100644
--- a/media/libstagefright/tests/SurfaceMediaSource_test.cpp
+++ b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
@@ -35,7 +35,7 @@
#include <binder/ProcessState.h>
#include <ui/FramebufferNativeWindow.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaData.h>
@@ -475,7 +475,7 @@ sp<MediaRecorder> SurfaceMediaSourceGLTest::setUpMediaRecorder(int fd, int video
mr->setVideoFrameRate(fps);
mr->prepare();
ALOGV("Starting MediaRecorder...");
- CHECK_EQ(OK, mr->start());
+ CHECK_EQ((status_t)OK, mr->start());
return mr;
}
@@ -757,7 +757,7 @@ TEST_F(SurfaceMediaSourceTest, DISABLED_EncodingFromCpuYV12BufferNpotWriteMediaS
ASSERT_EQ(NO_ERROR, native_window_api_disconnect(mANW.get(), NATIVE_WINDOW_API_CPU));
ALOGV("Stopping MediaRecorder...");
- CHECK_EQ(OK, mr->stop());
+ CHECK_EQ((status_t)OK, mr->stop());
mr.clear();
close(fd);
}
@@ -886,7 +886,7 @@ TEST_F(SurfaceMediaSourceGLTest, EncodingFromGLRgbaSameImageEachBufNpotWrite) {
mEglSurface = EGL_NO_SURFACE;
ALOGV("Stopping MediaRecorder...");
- CHECK_EQ(OK, mr->stop());
+ CHECK_EQ((status_t)OK, mr->stop());
mr.clear();
close(fd);
}
@@ -929,7 +929,7 @@ TEST_F(SurfaceMediaSourceGLTest, EncodingFromGLRgbaDiffImageEachBufNpotWrite) {
mEglSurface = EGL_NO_SURFACE;
ALOGV("Stopping MediaRecorder...");
- CHECK_EQ(OK, mr->stop());
+ CHECK_EQ((status_t)OK, mr->stop());
mr.clear();
close(fd);
}
diff --git a/media/libstagefright/timedtext/TimedTextInBandSource.cpp b/media/libstagefright/timedtext/TimedTextInBandSource.cpp
index f2c4d54c4773..afb73fb50313 100644
--- a/media/libstagefright/timedtext/TimedTextInBandSource.cpp
+++ b/media/libstagefright/timedtext/TimedTextInBandSource.cpp
@@ -19,8 +19,8 @@
#include <utils/Log.h>
#include <binder/Parcel.h>
+#include <media/stagefright/foundation/ADebug.h> // CHECK_XX macro
#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDebug.h> // CHECK_XX macro
#include <media/stagefright/MediaDefs.h> // for MEDIA_MIMETYPE_xxx
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
diff --git a/media/libstagefright/timedtext/TimedTextPlayer.cpp b/media/libstagefright/timedtext/TimedTextPlayer.cpp
index 8c2df88f4253..bf7cbf6fa1ee 100644
--- a/media/libstagefright/timedtext/TimedTextPlayer.cpp
+++ b/media/libstagefright/timedtext/TimedTextPlayer.cpp
@@ -18,8 +18,8 @@
#define LOG_TAG "TimedTextPlayer"
#include <utils/Log.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaErrors.h>
#include <media/MediaPlayerInterface.h>
diff --git a/media/libstagefright/yuv/YUVCanvas.cpp b/media/libstagefright/yuv/YUVCanvas.cpp
index 38aa779c94c8..4c9fee818c2c 100644
--- a/media/libstagefright/yuv/YUVCanvas.cpp
+++ b/media/libstagefright/yuv/YUVCanvas.cpp
@@ -17,7 +17,7 @@
#define LOG_NDEBUG 0
#define LOG_TAG "YUVCanvas"
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/YUVCanvas.h>
#include <media/stagefright/YUVImage.h>
#include <ui/Rect.h>
diff --git a/media/libstagefright/yuv/YUVImage.cpp b/media/libstagefright/yuv/YUVImage.cpp
index 0d67c96b5dff..7b9000b38803 100644
--- a/media/libstagefright/yuv/YUVImage.cpp
+++ b/media/libstagefright/yuv/YUVImage.cpp
@@ -17,9 +17,9 @@
#define LOG_NDEBUG 0
#define LOG_TAG "YUVImage"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/YUVImage.h>
#include <ui/Rect.h>
-#include <media/stagefright/MediaDebug.h>
namespace android {
diff --git a/media/tests/omxjpegdecoder/Android.mk b/media/tests/omxjpegdecoder/Android.mk
index 81c616770c2c..025a131245bd 100644
--- a/media/tests/omxjpegdecoder/Android.mk
+++ b/media/tests/omxjpegdecoder/Android.mk
@@ -26,6 +26,7 @@ LOCAL_SHARED_LIBRARIES := \
libcutils \
libskia \
libstagefright \
+ libstagefright_foundation \
libbinder \
libutils \
libjpeg
diff --git a/media/tests/omxjpegdecoder/SkOmxPixelRef.cpp b/media/tests/omxjpegdecoder/SkOmxPixelRef.cpp
index dfdf676a2a06..a25e854fa991 100644
--- a/media/tests/omxjpegdecoder/SkOmxPixelRef.cpp
+++ b/media/tests/omxjpegdecoder/SkOmxPixelRef.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <SkBitmap.h>
#include "SkOmxPixelRef.h"
@@ -32,7 +32,7 @@ SkOmxPixelRef::SkOmxPixelRef(SkColorTable* ctable, MediaBuffer* buffer,
SkOmxPixelRef::~SkOmxPixelRef() {
mBuffer->release();
- CHECK_EQ(mDecoder->stop(), OK);
+ CHECK_EQ(mDecoder->stop(), (status_t)OK);
SkSafeUnref(mCTable);
}
diff --git a/media/tests/omxjpegdecoder/StreamSource.cpp b/media/tests/omxjpegdecoder/StreamSource.cpp
index 5f442032976a..f764121a0dff 100644
--- a/media/tests/omxjpegdecoder/StreamSource.cpp
+++ b/media/tests/omxjpegdecoder/StreamSource.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#include "StreamSource.h"
diff --git a/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp b/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
index 42df66cf0c69..6424744a4331 100644
--- a/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
+++ b/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp
@@ -25,7 +25,7 @@
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <media/IMediaPlayerService.h>
-#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/OMXClient.h>
@@ -89,7 +89,7 @@ static int64_t getNowUs() {
OmxJpegImageDecoder::OmxJpegImageDecoder() {
status_t err = mClient.connect();
- CHECK_EQ(err, OK);
+ CHECK_EQ(err, (status_t)OK);
}
OmxJpegImageDecoder::~OmxJpegImageDecoder() {
@@ -152,7 +152,7 @@ bool OmxJpegImageDecoder::decodeSource(sp<MediaSource> decoder,
int64_t duration = getNowUs() - startTime;
if (err != OK) {
- CHECK_EQ(buffer, NULL);
+ CHECK(buffer == NULL);
}
printf("Duration in decoder->read(): %.1f (msecs). \n",
duration / 1E3 );
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index f7713aae50c9..3beaac998b75 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -43,6 +43,7 @@
<bool name="assisted_gps_enabled">true</bool>
<!-- 0 == mobile, 1 == wifi. -->
<integer name="def_network_preference">1</integer>
+ <bool name="def_netstats_enabled">true</bool>
<bool name="def_usb_mass_storage_enabled">true</bool>
<bool name="def_wifi_on">false</bool>
<bool name="def_networks_available_notification_on">true</bool>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 3ebf44baa725..882aa6624a28 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -1599,6 +1599,9 @@ public class DatabaseHelper extends SQLiteOpenHelper {
loadBooleanSetting(stmt, Settings.Secure.DEVICE_PROVISIONED,
R.bool.def_device_provisioned);
+
+ loadBooleanSetting(stmt, Settings.Secure.NETSTATS_ENABLED,
+ R.bool.def_netstats_enabled);
} finally {
if (stmt != null) stmt.close();
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java b/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
index abed18fec0a7..83f77880836d 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
@@ -52,8 +52,7 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler {
}
public void preDispatchKeyEvent(KeyEvent event) {
- getAudioManager().preDispatchKeyEvent(event.getKeyCode(),
- AudioManager.USE_DEFAULT_STREAM_TYPE);
+ getAudioManager().preDispatchKeyEvent(event, AudioManager.USE_DEFAULT_STREAM_TYPE);
}
public boolean dispatchKeyEvent(KeyEvent event) {
@@ -79,7 +78,7 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler {
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_MUTE: {
- getAudioManager().handleKeyDown(keyCode, AudioManager.USE_DEFAULT_STREAM_TYPE);
+ getAudioManager().handleKeyDown(event, AudioManager.USE_DEFAULT_STREAM_TYPE);
return true;
}
@@ -197,8 +196,7 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler {
AudioManager audioManager = (AudioManager)mContext.getSystemService(
Context.AUDIO_SERVICE);
if (audioManager != null) {
- getAudioManager().handleKeyUp(keyCode,
- AudioManager.USE_DEFAULT_STREAM_TYPE);
+ getAudioManager().handleKeyUp(event, AudioManager.USE_DEFAULT_STREAM_TYPE);
}
}
return true;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index f1fe43b70e16..b87b8c3dd7f6 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -1416,7 +1416,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
// doesn't have one of these. In this case, we execute it here and
// eat the event instead, because we have mVolumeControlStreamType
// and they don't.
- getAudioManager().handleKeyDown(keyCode, mVolumeControlStreamType);
+ getAudioManager().handleKeyDown(event, mVolumeControlStreamType);
return true;
}
@@ -1478,7 +1478,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
// doesn't have one of these. In this case, we execute it here and
// eat the event instead, because we have mVolumeControlStreamType
// and they don't.
- getAudioManager().handleKeyUp(keyCode, mVolumeControlStreamType);
+ getAudioManager().handleKeyUp(event, mVolumeControlStreamType);
return true;
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 1efb475c2f08..c12a4b7e5917 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -1516,12 +1516,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
}
static ITelephony getTelephonyService() {
- ITelephony telephonyService = ITelephony.Stub.asInterface(
+ return ITelephony.Stub.asInterface(
ServiceManager.checkService(Context.TELEPHONY_SERVICE));
- if (telephonyService == null) {
- Log.w(TAG, "Unable to find ITelephony interface.");
- }
- return telephonyService;
}
static IAudioService getAudioService() {
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 52834db26dc6..157405a2168c 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -6,9 +6,10 @@ LOCAL_SRC_FILES:= \
AudioFlinger.cpp \
AudioMixer.cpp.arm \
AudioResampler.cpp.arm \
- AudioResamplerSinc.cpp.arm \
- AudioResamplerCubic.cpp.arm \
- AudioPolicyService.cpp
+ AudioPolicyService.cpp \
+ ServiceUtilities.cpp
+# AudioResamplerSinc.cpp.arm
+# AudioResamplerCubic.cpp.arm
LOCAL_C_INCLUDES := \
system/media/audio_effects/include \
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index d4f8d5c1803c..024868729adb 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1,4 +1,4 @@
-/* //device/include/server/AudioFlinger/AudioFlinger.cpp
+/*
**
** Copyright 2007, The Android Open Source Project
**
@@ -48,6 +48,7 @@
#include "AudioMixer.h"
#include "AudioFlinger.h"
+#include "ServiceUtilities.h"
#include <media/EffectsFactoryApi.h>
#include <audio_effects/effect_visualizer.h>
@@ -101,20 +102,6 @@ static const uint32_t kMaxThreadSleepTimeShift = 2;
// ----------------------------------------------------------------------------
-static bool recordingAllowed() {
- if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
- bool ok = checkCallingPermission(String16("android.permission.RECORD_AUDIO"));
- if (!ok) ALOGE("Request requires android.permission.RECORD_AUDIO");
- return ok;
-}
-
-static bool settingsAllowed() {
- if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
- bool ok = checkCallingPermission(String16("android.permission.MODIFY_AUDIO_SETTINGS"));
- if (!ok) ALOGE("Request requires android.permission.MODIFY_AUDIO_SETTINGS");
- return ok;
-}
-
// To collect the amplifier usage
static void addBatteryData(uint32_t params) {
sp<IMediaPlayerService> service = IMediaDeathNotifier::getMediaPlayerService();
@@ -188,29 +175,32 @@ void AudioFlinger::onFirstRef()
mod->name, mod->id);
mAudioHwDevs.push(dev);
- if (!mPrimaryHardwareDev) {
+ if (mPrimaryHardwareDev == NULL) {
mPrimaryHardwareDev = dev;
ALOGI("Using '%s' (%s.%s) as the primary audio interface",
mod->name, mod->id, audio_interfaces[i]);
}
}
- mHardwareStatus = AUDIO_HW_INIT;
-
- if (!mPrimaryHardwareDev || mAudioHwDevs.size() == 0) {
+ if (mPrimaryHardwareDev == NULL) {
ALOGE("Primary audio interface not found");
- return;
+ // proceed, all later accesses to mPrimaryHardwareDev verify it's safe with initCheck()
}
+ // Currently (mPrimaryHardwareDev == NULL) == (mAudioHwDevs.size() == 0), but the way the
+ // primary HW dev is selected can change so these conditions might not always be equivalent.
+ // When that happens, re-visit all the code that assumes this.
+
+ AutoMutex lock(mHardwareLock);
+
for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
audio_hw_device_t *dev = mAudioHwDevs[i];
mHardwareStatus = AUDIO_HW_INIT;
rc = dev->init_check(dev);
+ mHardwareStatus = AUDIO_HW_IDLE;
if (rc == 0) {
- AutoMutex lock(mHardwareLock);
-
- mMode = AUDIO_MODE_NORMAL;
+ mMode = AUDIO_MODE_NORMAL; // assigned multiple times with same value
mHardwareStatus = AUDIO_HW_SET_MODE;
dev->set_mode(dev, mMode);
mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
@@ -220,17 +210,8 @@ void AudioFlinger::onFirstRef()
}
}
-status_t AudioFlinger::initCheck() const
-{
- Mutex::Autolock _l(mLock);
- if (mPrimaryHardwareDev == NULL || mAudioHwDevs.size() == 0)
- return NO_INIT;
- return NO_ERROR;
-}
-
AudioFlinger::~AudioFlinger()
{
- int num_devs = mAudioHwDevs.size();
while (!mRecordThreads.isEmpty()) {
// closeInput() will remove first entry from mRecordThreads
@@ -241,9 +222,9 @@ AudioFlinger::~AudioFlinger()
closeOutput(mPlaybackThreads.keyAt(0));
}
- for (int i = 0; i < num_devs; i++) {
- audio_hw_device_t *dev = mAudioHwDevs[i];
- audio_hw_device_close(dev);
+ for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+ // no mHardwareLock needed, as there are no other references to this
+ audio_hw_device_close(mAudioHwDevs[i]);
}
}
@@ -327,7 +308,7 @@ static bool tryLock(Mutex& mutex)
status_t AudioFlinger::dump(int fd, const Vector<String16>& args)
{
- if (!checkCallingPermission(String16("android.permission.DUMP"))) {
+ if (!dumpAllowed()) {
dumpPermissionDenial(fd, args);
} else {
// get state of hardware lock
@@ -559,7 +540,7 @@ status_t AudioFlinger::setMasterVolume(float value)
Mutex::Autolock _l(mLock);
mMasterVolume = value;
- for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++)
mPlaybackThreads.valueAt(i)->setMasterVolume(value);
return NO_ERROR;
@@ -591,7 +572,7 @@ status_t AudioFlinger::setMode(audio_mode_t mode)
if (NO_ERROR == ret) {
Mutex::Autolock _l(mLock);
mMode = mode;
- for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++)
mPlaybackThreads.valueAt(i)->setMode(mode);
}
@@ -625,6 +606,7 @@ bool AudioFlinger::getMicMute() const
}
bool state = AUDIO_MODE_INVALID;
+ AutoMutex lock(mHardwareLock);
mHardwareStatus = AUDIO_HW_GET_MIC_MUTE;
mPrimaryHardwareDev->get_mic_mute(mPrimaryHardwareDev, &state);
mHardwareStatus = AUDIO_HW_IDLE;
@@ -639,8 +621,9 @@ status_t AudioFlinger::setMasterMute(bool muted)
}
Mutex::Autolock _l(mLock);
+ // This is an optimization, so PlaybackThread doesn't have to look at the one from AudioFlinger
mMasterMute = muted;
- for (uint32_t i = 0; i < mPlaybackThreads.size(); i++)
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++)
mPlaybackThreads.valueAt(i)->setMasterMute(muted);
return NO_ERROR;
@@ -683,7 +666,7 @@ status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value,
mStreamTypes[stream].volume = value;
if (thread == NULL) {
- for (uint32_t i = 0; i < mPlaybackThreads.size(); i++) {
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
mPlaybackThreads.valueAt(i)->setStreamVolume(stream, value);
}
} else {
@@ -729,7 +712,7 @@ float AudioFlinger::streamVolume(audio_stream_type_t stream, audio_io_handle_t o
}
volume = thread->streamVolume(stream);
} else {
- volume = mStreamTypes[stream].volume;
+ volume = streamVolume_l(stream);
}
return volume;
@@ -741,7 +724,8 @@ bool AudioFlinger::streamMute(audio_stream_type_t stream) const
return true;
}
- return mStreamTypes[stream].mute;
+ AutoMutex lock(mLock);
+ return streamMute_l(stream);
}
status_t AudioFlinger::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs)
@@ -856,7 +840,11 @@ size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, audio_format_t form
return 0;
}
- return mPrimaryHardwareDev->get_input_buffer_size(mPrimaryHardwareDev, sampleRate, format, channelCount);
+ AutoMutex lock(mHardwareLock);
+ mHardwareStatus = AUDIO_HW_GET_INPUT_BUFFER_SIZE;
+ size_t size = mPrimaryHardwareDev->get_input_buffer_size(mPrimaryHardwareDev, sampleRate, format, channelCount);
+ mHardwareStatus = AUDIO_HW_IDLE;
+ return size;
}
unsigned int AudioFlinger::getInputFramesLost(audio_io_handle_t ioHandle) const
@@ -942,7 +930,7 @@ void AudioFlinger::removeNotificationClient(pid_t pid)
{
Mutex::Autolock _l(mLock);
- int index = mNotificationClients.indexOfKey(pid);
+ ssize_t index = mNotificationClients.indexOfKey(pid);
if (index >= 0) {
sp <NotificationClient> client = mNotificationClients.valueFor(pid);
ALOGV("removeNotificationClient() %p, pid %d", client.get(), pid);
@@ -950,9 +938,9 @@ void AudioFlinger::removeNotificationClient(pid_t pid)
}
ALOGV("%d died, releasing its sessions", pid);
- int num = mAudioSessionRefs.size();
+ size_t num = mAudioSessionRefs.size();
bool removed = false;
- for (int i = 0; i< num; i++) {
+ for (size_t i = 0; i< num; ) {
AudioSessionRef *ref = mAudioSessionRefs.itemAt(i);
ALOGV(" pid %d @ %d", ref->pid, i);
if (ref->pid == pid) {
@@ -960,8 +948,9 @@ void AudioFlinger::removeNotificationClient(pid_t pid)
mAudioSessionRefs.removeAt(i);
delete ref;
removed = true;
- i--;
num--;
+ } else {
+ i++;
}
}
if (removed) {
@@ -998,7 +987,7 @@ AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio
mChannelCount(0),
mFrameSize(1), mFormat(AUDIO_FORMAT_INVALID),
mParamStatus(NO_ERROR),
- mStandby(false), mId(id), mExiting(false),
+ mStandby(false), mId(id),
mDevice(device),
mDeathRecipient(new PMDeathRecipient(this))
{
@@ -1017,17 +1006,23 @@ AudioFlinger::ThreadBase::~ThreadBase()
void AudioFlinger::ThreadBase::exit()
{
- // keep a strong ref on ourself so that we won't get
- // destroyed in the middle of requestExitAndWait()
- sp <ThreadBase> strongMe = this;
-
ALOGV("ThreadBase::exit");
{
+ // This lock prevents the following race in thread (uniprocessor for illustration):
+ // if (!exitPending()) {
+ // // context switch from here to exit()
+ // // exit() calls requestExit(), what exitPending() observes
+ // // exit() calls signal(), which is dropped since no waiters
+ // // context switch back from exit() to here
+ // mWaitWorkCV.wait(...);
+ // // now thread is hung
+ // }
AutoMutex lock(mLock);
- mExiting = true;
requestExit();
mWaitWorkCV.signal();
}
+ // When Thread::requestExitAndWait is made virtual and this method is renamed to
+ // "virtual status_t requestExitAndWait()", replace by "return Thread::requestExitAndWait();"
requestExitAndWait();
}
@@ -1246,7 +1241,7 @@ void AudioFlinger::ThreadBase::setEffectSuspended_l(
void AudioFlinger::ThreadBase::checkSuspendOnAddEffectChain_l(const sp<EffectChain>& chain)
{
- int index = mSuspendedSessions.indexOfKey(chain->sessionId());
+ ssize_t index = mSuspendedSessions.indexOfKey(chain->sessionId());
if (index < 0) {
return;
}
@@ -1272,7 +1267,7 @@ void AudioFlinger::ThreadBase::updateSuspendedSessions_l(const effect_uuid_t *ty
bool suspend,
int sessionId)
{
- int index = mSuspendedSessions.indexOfKey(sessionId);
+ ssize_t index = mSuspendedSessions.indexOfKey(sessionId);
KeyedVector <int, sp<SuspendedSessionDesc> > sessionEffects;
@@ -1383,11 +1378,13 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinge
// There is no AUDIO_STREAM_MIN, and ++ operator does not compile
for (audio_stream_type_t stream = (audio_stream_type_t) 0; stream < AUDIO_STREAM_CNT;
stream = (audio_stream_type_t) (stream + 1)) {
- mStreamTypes[stream].volume = mAudioFlinger->streamVolumeInternal(stream);
- mStreamTypes[stream].mute = mAudioFlinger->streamMute(stream);
+ mStreamTypes[stream].volume = mAudioFlinger->streamVolume_l(stream);
+ mStreamTypes[stream].mute = mAudioFlinger->streamMute_l(stream);
// initialized by stream_type_t default constructor
// mStreamTypes[stream].valid = true;
}
+ // mStreamTypes[AUDIO_STREAM_CNT] exists but isn't explicitly initialized here,
+ // because mAudioFlinger doesn't have one to copy from
}
AudioFlinger::PlaybackThread::~PlaybackThread()
@@ -1581,40 +1578,36 @@ uint32_t AudioFlinger::PlaybackThread::latency() const
}
}
-status_t AudioFlinger::PlaybackThread::setMasterVolume(float value)
+void AudioFlinger::PlaybackThread::setMasterVolume(float value)
{
+ Mutex::Autolock _l(mLock);
mMasterVolume = value;
- return NO_ERROR;
}
-status_t AudioFlinger::PlaybackThread::setMasterMute(bool muted)
+void AudioFlinger::PlaybackThread::setMasterMute(bool muted)
{
- mMasterMute = muted;
- return NO_ERROR;
+ Mutex::Autolock _l(mLock);
+ setMasterMute_l(muted);
}
-status_t AudioFlinger::PlaybackThread::setStreamVolume(audio_stream_type_t stream, float value)
+void AudioFlinger::PlaybackThread::setStreamVolume(audio_stream_type_t stream, float value)
{
+ Mutex::Autolock _l(mLock);
mStreamTypes[stream].volume = value;
- return NO_ERROR;
}
-status_t AudioFlinger::PlaybackThread::setStreamMute(audio_stream_type_t stream, bool muted)
+void AudioFlinger::PlaybackThread::setStreamMute(audio_stream_type_t stream, bool muted)
{
+ Mutex::Autolock _l(mLock);
mStreamTypes[stream].mute = muted;
- return NO_ERROR;
}
float AudioFlinger::PlaybackThread::streamVolume(audio_stream_type_t stream) const
{
+ Mutex::Autolock _l(mLock);
return mStreamTypes[stream].volume;
}
-bool AudioFlinger::PlaybackThread::streamMute(audio_stream_type_t stream) const
-{
- return mStreamTypes[stream].mute;
-}
-
// addTrack_l() must be called with ThreadBase::mLock held
status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track)
{
@@ -1944,7 +1937,7 @@ bool AudioFlinger::MixerThread::threadLoop()
property_get("ro.audio.silent", value, "0");
if (atoi(value)) {
ALOGD("Silence is golden");
- setMasterMute(true);
+ setMasterMute_l(true);
}
}
@@ -2504,21 +2497,6 @@ AudioFlinger::DirectOutputThread::~DirectOutputThread()
{
}
-static inline
-int32_t mul(int16_t in, int16_t v)
-{
-#if defined(__arm__) && !defined(__thumb__)
- int32_t out;
- asm( "smulbb %[out], %[in], %[v] \n"
- : [out]"=r"(out)
- : [in]"%r"(in), [v]"r"(v)
- : );
- return out;
-#else
- return in * int32_t(v);
-#endif
-}
-
void AudioFlinger::DirectOutputThread::applyVolume(uint16_t leftVol, uint16_t rightVol, bool ramp)
{
// Do not apply volume on compressed audio
@@ -2660,7 +2638,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop()
property_get("ro.audio.silent", value, "0");
if (atoi(value)) {
ALOGD("Silence is golden");
- setMasterMute(true);
+ setMasterMute_l(true);
}
}
@@ -3056,7 +3034,7 @@ bool AudioFlinger::DuplicatingThread::threadLoop()
property_get("ro.audio.silent", value, "0");
if (atoi(value)) {
ALOGD("Silence is golden");
- setMasterMute(true);
+ setMasterMute_l(true);
}
}
@@ -3144,6 +3122,7 @@ bool AudioFlinger::DuplicatingThread::threadLoop()
void AudioFlinger::DuplicatingThread::addOutputTrack(MixerThread *thread)
{
+ // FIXME explain this formula
int frameCount = (3 * mFrameCount * mSampleRate) / thread->sampleRate();
OutputTrack *outputTrack = new OutputTrack((ThreadBase *)thread,
this,
@@ -3415,7 +3394,7 @@ void AudioFlinger::PlaybackThread::Track::destroy()
{
// NOTE: destroyTrack_l() can remove a strong reference to this Track
// by removing it from mTracks vector, so there is a risk that this Tracks's
- // desctructor is called. As the destructor needs to lock mLock,
+ // destructor is called. As the destructor needs to lock mLock,
// we must acquire a strong reference on this Track before locking mLock
// here so that the destructor is called only when exiting this function.
// On the other hand, as long as Track::destroy() is only called by
@@ -3446,7 +3425,7 @@ void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size)
uint32_t vlr = mCblk->getVolumeLR();
snprintf(buffer, size, " %05d %05d %03u %03u 0x%08x %05u %04u %1d %1d %1d %05u %05u %05u 0x%08x 0x%08x 0x%08x 0x%08x\n",
mName - AudioMixer::TRACK0,
- (mClient == 0) ? getpid() : mClient->pid(),
+ (mClient == 0) ? getpid_cached : mClient->pid(),
mStreamType,
mFormat,
mChannelMask,
@@ -3517,11 +3496,11 @@ bool AudioFlinger::PlaybackThread::Track::isReady() const {
return false;
}
-status_t AudioFlinger::PlaybackThread::Track::start()
+status_t AudioFlinger::PlaybackThread::Track::start(pid_t tid)
{
status_t status = NO_ERROR;
- ALOGV("start(%d), calling pid %d session %d",
- mName, IPCThreadState::self()->getCallingPid(), mSessionId);
+ ALOGV("start(%d), calling pid %d session %d tid %d",
+ mName, IPCThreadState::self()->getCallingPid(), mSessionId, tid);
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
Mutex::Autolock _l(thread->mLock);
@@ -3740,12 +3719,12 @@ getNextBuffer_exit:
return NOT_ENOUGH_DATA;
}
-status_t AudioFlinger::RecordThread::RecordTrack::start()
+status_t AudioFlinger::RecordThread::RecordTrack::start(pid_t tid)
{
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
RecordThread *recordThread = (RecordThread *)thread.get();
- return recordThread->start(this);
+ return recordThread->start(this, tid);
} else {
return BAD_VALUE;
}
@@ -3767,7 +3746,7 @@ void AudioFlinger::RecordThread::RecordTrack::stop()
void AudioFlinger::RecordThread::RecordTrack::dump(char* buffer, size_t size)
{
snprintf(buffer, size, " %05d %03u 0x%08x %05d %04u %01d %05u %08x %08x\n",
- (mClient == 0) ? getpid() : mClient->pid(),
+ (mClient == 0) ? getpid_cached : mClient->pid(),
mFormat,
mChannelMask,
mSessionId,
@@ -3812,9 +3791,9 @@ AudioFlinger::PlaybackThread::OutputTrack::~OutputTrack()
clearBufferQueue();
}
-status_t AudioFlinger::PlaybackThread::OutputTrack::start()
+status_t AudioFlinger::PlaybackThread::OutputTrack::start(pid_t tid)
{
- status_t status = Track::start();
+ status_t status = Track::start(tid);
if (status != NO_ERROR) {
return status;
}
@@ -3844,7 +3823,7 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr
uint32_t waitTimeLeftMs = mSourceThread->waitTimeMs();
if (!mActive && frames != 0) {
- start();
+ start(0);
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
MixerThread *mixerThread = (MixerThread *)thread.get();
@@ -4021,6 +4000,7 @@ void AudioFlinger::PlaybackThread::OutputTrack::clearBufferQueue()
AudioFlinger::Client::Client(const sp<AudioFlinger>& audioFlinger, pid_t pid)
: RefBase(),
mAudioFlinger(audioFlinger),
+ // FIXME should be a "k" constant not hard-coded, in .h or ro. property, see 4 lines below
mMemoryDealer(new MemoryDealer(1024*1024, "AudioFlinger::Client")),
mPid(pid)
{
@@ -4079,8 +4059,8 @@ sp<IMemory> AudioFlinger::TrackHandle::getCblk() const {
return mTrack->getCblk();
}
-status_t AudioFlinger::TrackHandle::start() {
- return mTrack->start();
+status_t AudioFlinger::TrackHandle::start(pid_t tid) {
+ return mTrack->start(tid);
}
void AudioFlinger::TrackHandle::stop() {
@@ -4202,9 +4182,9 @@ sp<IMemory> AudioFlinger::RecordHandle::getCblk() const {
return mRecordTrack->getCblk();
}
-status_t AudioFlinger::RecordHandle::start() {
+status_t AudioFlinger::RecordHandle::start(pid_t tid) {
ALOGV("RecordHandle::start()");
- return mRecordTrack->start();
+ return mRecordTrack->start(tid);
}
void AudioFlinger::RecordHandle::stop() {
@@ -4496,9 +4476,9 @@ Exit:
return track;
}
-status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrack)
+status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrack, pid_t tid)
{
- ALOGV("RecordThread::start");
+ ALOGV("RecordThread::start tid=%d", tid);
sp <ThreadBase> strongMe = this;
status_t status = NO_ERROR;
{
@@ -4531,7 +4511,7 @@ status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrac
ALOGV("Signal record thread");
mWaitWorkCV.signal();
// do not wait for mStartStopCond if exiting
- if (mExiting) {
+ if (exitPending()) {
mActiveTrack.clear();
status = INVALID_OPERATION;
goto startError;
@@ -4558,7 +4538,7 @@ void AudioFlinger::RecordThread::stop(RecordThread::RecordTrack* recordTrack) {
if (mActiveTrack != 0 && recordTrack == mActiveTrack.get()) {
mActiveTrack->mState = TrackBase::PAUSING;
// do not wait for mStartStopCond if exiting
- if (mExiting) {
+ if (exitPending()) {
return;
}
mStartStopCond.wait(mLock);
@@ -4682,7 +4662,7 @@ bool AudioFlinger::RecordThread::checkForNewParameters_l()
}
if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
// do not accept frame count changes if tracks are open as the track buffer
- // size depends on frame count and correct behavior would not be garantied
+ // size depends on frame count and correct behavior would not be guaranteed
// if frame count is changed after track creation
if (mActiveTrack != 0) {
status = INVALID_OPERATION;
@@ -5004,6 +4984,8 @@ status_t AudioFlinger::closeOutput(audio_io_handle_t output)
mPlaybackThreads.removeItem(output);
}
thread->exit();
+ // The thread entity (active unit of execution) is no longer running here,
+ // but the ThreadBase container still exists.
if (thread->type() != ThreadBase::DUPLICATING) {
AudioStreamOut *out = thread->clearOutput();
@@ -5147,6 +5129,8 @@ status_t AudioFlinger::closeInput(audio_io_handle_t input)
mRecordThreads.removeItem(input);
}
thread->exit();
+ // The thread entity (active unit of execution) is no longer running here,
+ // but the ThreadBase container still exists.
AudioStreamIn *in = thread->clearInput();
assert(in != NULL);
@@ -5195,8 +5179,8 @@ void AudioFlinger::acquireAudioSessionId(int audioSession)
Mutex::Autolock _l(mLock);
pid_t caller = IPCThreadState::self()->getCallingPid();
ALOGV("acquiring %d from %d", audioSession, caller);
- int num = mAudioSessionRefs.size();
- for (int i = 0; i< num; i++) {
+ size_t num = mAudioSessionRefs.size();
+ for (size_t i = 0; i< num; i++) {
AudioSessionRef *ref = mAudioSessionRefs.editItemAt(i);
if (ref->sessionid == audioSession && ref->pid == caller) {
ref->cnt++;
@@ -5213,8 +5197,8 @@ void AudioFlinger::releaseAudioSessionId(int audioSession)
Mutex::Autolock _l(mLock);
pid_t caller = IPCThreadState::self()->getCallingPid();
ALOGV("releasing %d from %d", audioSession, caller);
- int num = mAudioSessionRefs.size();
- for (int i = 0; i< num; i++) {
+ size_t num = mAudioSessionRefs.size();
+ for (size_t i = 0; i< num; i++) {
AudioSessionRef *ref = mAudioSessionRefs.itemAt(i);
if (ref->sessionid == audioSession && ref->pid == caller) {
ref->cnt--;
@@ -5410,7 +5394,7 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid,
// Session AUDIO_SESSION_OUTPUT_STAGE is reserved for output stage effects
// that can only be created by audio policy manager (running in same process)
- if (sessionId == AUDIO_SESSION_OUTPUT_STAGE && getpid() != pid) {
+ if (sessionId == AUDIO_SESSION_OUTPUT_STAGE && getpid_cached != pid) {
lStatus = PERMISSION_DENIED;
goto Exit;
}
@@ -5876,13 +5860,13 @@ void AudioFlinger::ThreadBase::setMode(audio_mode_t mode)
void AudioFlinger::ThreadBase::disconnectEffect(const sp<EffectModule>& effect,
const wp<EffectHandle>& handle,
- bool unpiniflast) {
+ bool unpinIfLast) {
Mutex::Autolock _l(mLock);
ALOGV("disconnectEffect() %p effect %p", this, effect.get());
// delete the effect module if removing last handle on it
if (effect->removeHandle(handle) == 0) {
- if (!effect->isPinned() || unpiniflast) {
+ if (!effect->isPinned() || unpinIfLast) {
removeEffect_l(effect);
AudioSystem::unregisterEffect(effect->id());
}
@@ -6126,7 +6110,6 @@ status_t AudioFlinger::EffectModule::addHandle(const sp<EffectHandle>& handle)
status_t status;
Mutex::Autolock _l(mLock);
- // First handle in mHandles has highest priority and controls the effect module
int priority = handle->priority();
size_t size = mHandles.size();
sp<EffectHandle> h;
@@ -6198,7 +6181,7 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::EffectModule::controlHandle()
return mHandles.size() != 0 ? mHandles[0].promote() : 0;
}
-void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle, bool unpiniflast)
+void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle, bool unpinIfLast)
{
ALOGV("disconnect() %p handle %p", this, handle.unsafe_get());
// keep a strong reference on this EffectModule to avoid calling the
@@ -6207,7 +6190,7 @@ void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle, bool
{
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
- thread->disconnectEffect(keep, handle, unpiniflast);
+ thread->disconnectEffect(keep, handle, unpinIfLast);
}
}
}
@@ -6879,13 +6862,13 @@ void AudioFlinger::EffectHandle::disconnect()
disconnect(true);
}
-void AudioFlinger::EffectHandle::disconnect(bool unpiniflast)
+void AudioFlinger::EffectHandle::disconnect(bool unpinIfLast)
{
- ALOGV("disconnect(%s)", unpiniflast ? "true" : "false");
+ ALOGV("disconnect(%s)", unpinIfLast ? "true" : "false");
if (mEffect == 0) {
return;
}
- mEffect->disconnect(this, unpiniflast);
+ mEffect->disconnect(this, unpinIfLast);
if (mHasControl && mEnabled) {
sp<ThreadBase> thread = mEffect->thread().promote();
@@ -7028,7 +7011,7 @@ void AudioFlinger::EffectHandle::dump(char* buffer, size_t size)
bool locked = mCblk != NULL && tryLock(mCblk->lock);
snprintf(buffer, size, "\t\t\t%05d %05d %01u %01u %05u %05u\n",
- (mClient == 0) ? getpid() : mClient->pid(),
+ (mClient == 0) ? getpid_cached : mClient->pid(),
mPriority,
mHasControl,
!locked,
@@ -7196,12 +7179,12 @@ status_t AudioFlinger::EffectChain::addEffect_l(const sp<EffectModule>& effect)
// Reject insertion if an effect with EFFECT_FLAG_INSERT_EXCLUSIVE is
// already present
- int size = (int)mEffects.size();
- int idx_insert = size;
- int idx_insert_first = -1;
- int idx_insert_last = -1;
+ size_t size = mEffects.size();
+ size_t idx_insert = size;
+ ssize_t idx_insert_first = -1;
+ ssize_t idx_insert_last = -1;
- for (int i = 0; i < size; i++) {
+ for (size_t i = 0; i < size; i++) {
effect_descriptor_t d = mEffects[i]->desc();
uint32_t iMode = d.flags & EFFECT_FLAG_TYPE_MASK;
uint32_t iPref = d.flags & EFFECT_FLAG_INSERT_MASK;
@@ -7270,11 +7253,10 @@ status_t AudioFlinger::EffectChain::addEffect_l(const sp<EffectModule>& effect)
size_t AudioFlinger::EffectChain::removeEffect_l(const sp<EffectModule>& effect)
{
Mutex::Autolock _l(mLock);
- int size = (int)mEffects.size();
- int i;
+ size_t size = mEffects.size();
uint32_t type = effect->desc().flags & EFFECT_FLAG_TYPE_MASK;
- for (i = 0; i < size; i++) {
+ for (size_t i = 0; i < size; i++) {
if (effect == mEffects[i]) {
// calling stop here will remove pre-processing effect from the audio HAL.
// This is safe as we hold the EffectChain mutex which guarantees that we are not in
@@ -7421,7 +7403,7 @@ void AudioFlinger::EffectChain::setEffectSuspended_l(
sp<SuspendedEffectDesc> desc;
// use effect type UUID timelow as key as there is no real risk of identical
// timeLow fields among effect type UUIDs.
- int index = mSuspendedEffects.indexOfKey(type->timeLow);
+ ssize_t index = mSuspendedEffects.indexOfKey(type->timeLow);
if (suspend) {
if (index >= 0) {
desc = mSuspendedEffects.valueAt(index);
@@ -7471,7 +7453,7 @@ void AudioFlinger::EffectChain::setEffectSuspendedAll_l(bool suspend)
{
sp<SuspendedEffectDesc> desc;
- int index = mSuspendedEffects.indexOfKey((int)kKeyForSuspendAll);
+ ssize_t index = mSuspendedEffects.indexOfKey((int)kKeyForSuspendAll);
if (suspend) {
if (index >= 0) {
desc = mSuspendedEffects.valueAt(index);
@@ -7553,7 +7535,7 @@ sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectIfEnabled(
void AudioFlinger::EffectChain::checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,
bool enabled)
{
- int index = mSuspendedEffects.indexOfKey(effect->desc().type.timeLow);
+ ssize_t index = mSuspendedEffects.indexOfKey(effect->desc().type.timeLow);
if (enabled) {
if (index < 0) {
// if the effect is not suspend check if all effects are suspended
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 955648f7633f..aa0b8f8575ac 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -1,4 +1,4 @@
-/* //device/include/server/AudioFlinger/AudioFlinger.h
+/*
**
** Copyright 2007, The Android Open Source Project
**
@@ -67,7 +67,7 @@ public:
virtual status_t dump(int fd, const Vector<String16>& args);
- // IAudioFlinger interface
+ // IAudioFlinger interface, in binder opcode order
virtual sp<IAudioTrack> createTrack(
pid_t pid,
audio_stream_type_t streamType,
@@ -81,6 +81,17 @@ public:
int *sessionId,
status_t *status);
+ virtual sp<IAudioRecord> openRecord(
+ pid_t pid,
+ audio_io_handle_t input,
+ uint32_t sampleRate,
+ audio_format_t format,
+ uint32_t channelMask,
+ int frameCount,
+ uint32_t flags,
+ int *sessionId,
+ status_t *status);
+
virtual uint32_t sampleRate(audio_io_handle_t output) const;
virtual int channelCount(audio_io_handle_t output) const;
virtual audio_format_t format(audio_io_handle_t output) const;
@@ -112,7 +123,6 @@ public:
virtual void registerClient(const sp<IAudioFlingerClient>& client);
virtual size_t getInputBufferSize(uint32_t sampleRate, audio_format_t format, int channelCount) const;
- virtual unsigned int getInputFramesLost(audio_io_handle_t ioHandle) const;
virtual audio_io_handle_t openOutput(uint32_t *pDevices,
uint32_t *pSamplingRate,
@@ -145,6 +155,8 @@ public:
virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames,
audio_io_handle_t output) const;
+ virtual unsigned int getInputFramesLost(audio_io_handle_t ioHandle) const;
+
virtual int newAudioSessionId();
virtual void acquireAudioSessionId(int audioSession);
@@ -171,53 +183,25 @@ public:
virtual status_t moveEffects(int sessionId, audio_io_handle_t srcOutput,
audio_io_handle_t dstOutput);
- enum hardware_call_state {
- AUDIO_HW_IDLE = 0,
- AUDIO_HW_INIT,
- AUDIO_HW_OUTPUT_OPEN,
- AUDIO_HW_OUTPUT_CLOSE,
- AUDIO_HW_INPUT_OPEN,
- AUDIO_HW_INPUT_CLOSE,
- AUDIO_HW_STANDBY,
- AUDIO_HW_SET_MASTER_VOLUME,
- AUDIO_HW_GET_ROUTING,
- AUDIO_HW_SET_ROUTING,
- AUDIO_HW_GET_MODE,
- AUDIO_HW_SET_MODE,
- AUDIO_HW_GET_MIC_MUTE,
- AUDIO_HW_SET_MIC_MUTE,
- AUDIO_SET_VOICE_VOLUME,
- AUDIO_SET_PARAMETER,
- };
-
- // record interface
- virtual sp<IAudioRecord> openRecord(
- pid_t pid,
- audio_io_handle_t input,
- uint32_t sampleRate,
- audio_format_t format,
- uint32_t channelMask,
- int frameCount,
- uint32_t flags,
- int *sessionId,
- status_t *status);
-
virtual status_t onTransact(
uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags);
+ // end of IAudioFlinger interface
+
+private:
audio_mode_t getMode() const { return mMode; }
bool btNrecIsOff() const { return mBtNrecIsOff; }
-private:
-
AudioFlinger();
virtual ~AudioFlinger();
- status_t initCheck() const;
+ // call in any IAudioFlinger method that accesses mPrimaryHardwareDev
+ status_t initCheck() const { return mPrimaryHardwareDev == NULL ? NO_INIT : NO_ERROR; }
+
virtual void onFirstRef();
audio_hw_device_t* findSuitableHwDev_l(uint32_t devices);
void purgeStaleEffects_l();
@@ -306,6 +290,8 @@ private:
enum track_state {
IDLE,
TERMINATED,
+ // These are order-sensitive; do not change order without reviewing the impact.
+ // In particular there are assumptions about > STOPPED.
STOPPED,
RESUMING,
ACTIVE,
@@ -330,7 +316,7 @@ private:
int sessionId);
virtual ~TrackBase();
- virtual status_t start() = 0;
+ virtual status_t start(pid_t tid) = 0;
virtual void stop() = 0;
sp<IMemory> getCblk() const { return mCblkMemory; }
audio_track_cblk_t* cblk() const { return mCblk; }
@@ -419,6 +405,8 @@ private:
audio_format_t format() const { return mFormat; }
size_t frameCount() const { return mFrameCount; }
void wakeUp() { mWaitWorkCV.broadcast(); }
+ // Should be "virtual status_t requestExitAndWait()" and override same
+ // method in Thread, but Thread::requestExitAndWait() is not yet virtual.
void exit();
virtual bool checkForNewParameters_l() = 0;
virtual status_t setParameters(const String8& keyValuePairs);
@@ -442,7 +430,7 @@ private:
status_t *status);
void disconnectEffect(const sp< EffectModule>& effect,
const wp<EffectHandle>& handle,
- bool unpiniflast);
+ bool unpinIfLast);
// return values for hasAudioSession (bit field)
enum effect_state {
@@ -550,7 +538,6 @@ private:
Vector<ConfigEvent> mConfigEvents;
bool mStandby;
const audio_io_handle_t mId;
- bool mExiting;
Vector< sp<EffectChain> > mEffectChains;
uint32_t mDevice; // output device for PlaybackThread
// input + output devices for RecordThread
@@ -601,7 +588,7 @@ private:
virtual ~Track();
void dump(char* buffer, size_t size);
- virtual status_t start();
+ virtual status_t start(pid_t tid);
virtual void stop();
void pause();
@@ -683,7 +670,7 @@ private:
int frameCount);
virtual ~OutputTrack();
- virtual status_t start();
+ virtual status_t start(pid_t tid);
virtual void stop();
bool write(int16_t* data, uint32_t frames);
bool bufferQueueEmpty() const { return (mBufferQueue.size() == 0) ? true : false; }
@@ -722,17 +709,13 @@ private:
virtual uint32_t latency() const;
- virtual status_t setMasterVolume(float value);
- virtual status_t setMasterMute(bool muted);
+ void setMasterVolume(float value);
+ void setMasterMute(bool muted);
- virtual float masterVolume() const { return mMasterVolume; }
- virtual bool masterMute() const { return mMasterMute; }
+ void setStreamVolume(audio_stream_type_t stream, float value);
+ void setStreamMute(audio_stream_type_t stream, bool muted);
- virtual status_t setStreamVolume(audio_stream_type_t stream, float value);
- virtual status_t setStreamMute(audio_stream_type_t stream, bool muted);
-
- virtual float streamVolume(audio_stream_type_t stream) const;
- virtual bool streamMute(audio_stream_type_t stream) const;
+ float streamVolume(audio_stream_type_t stream) const;
sp<Track> createTrack_l(
const sp<AudioFlinger::Client>& client,
@@ -775,7 +758,11 @@ private:
int mSuspended;
int mBytesWritten;
private:
+ // mMasterMute is in both PlaybackThread and in AudioFlinger. When a
+ // PlaybackThread needs to find out if master-muted, it checks it's local
+ // copy rather than the one in AudioFlinger. This optimization saves a lock.
bool mMasterMute;
+ void setMasterMute_l(bool muted) { mMasterMute = muted; }
protected:
SortedVector< wp<Track> > mActiveTracks;
@@ -868,6 +855,8 @@ private:
private:
void applyVolume(uint16_t leftVol, uint16_t rightVol, bool ramp);
+ // volumes last sent to audio HAL with stream->set_volume()
+ // FIXME use standard representation and names
float mLeftVolFloat;
float mRightVolFloat;
uint16_t mLeftVolShort;
@@ -899,7 +888,11 @@ private:
PlaybackThread *checkPlaybackThread_l(audio_io_handle_t output) const;
MixerThread *checkMixerThread_l(audio_io_handle_t output) const;
RecordThread *checkRecordThread_l(audio_io_handle_t input) const;
- float streamVolumeInternal(audio_stream_type_t stream) const
+ // no range check, AudioFlinger::mLock held
+ bool streamMute_l(audio_stream_type_t stream) const
+ { return mStreamTypes[stream].mute; }
+ // no range check, doesn't check per-thread stream volume, AudioFlinger::mLock held
+ float streamVolume_l(audio_stream_type_t stream) const
{ return mStreamTypes[stream].volume; }
void audioConfigChanged_l(int event, audio_io_handle_t ioHandle, void *param2);
@@ -915,12 +908,13 @@ private:
friend class AudioBuffer;
+ // server side of the client's IAudioTrack
class TrackHandle : public android::BnAudioTrack {
public:
TrackHandle(const sp<PlaybackThread::Track>& track);
virtual ~TrackHandle();
virtual sp<IMemory> getCblk() const;
- virtual status_t start();
+ virtual status_t start(pid_t tid);
virtual void stop();
virtual void flush();
virtual void mute(bool);
@@ -958,7 +952,7 @@ private:
int sessionId);
virtual ~RecordTrack();
- virtual status_t start();
+ virtual status_t start(pid_t tid);
virtual void stop();
bool overflow() { bool tmp = mOverflow; mOverflow = false; return tmp; }
@@ -1003,6 +997,7 @@ private:
status_t *status);
status_t start(RecordTrack* recordTrack);
+ status_t start(RecordTrack* recordTrack, pid_t tid);
void stop(RecordTrack* recordTrack);
status_t dump(int fd, const Vector<String16>& args);
AudioStreamIn* getInput() const;
@@ -1038,12 +1033,13 @@ private:
ssize_t mBytesRead;
};
+ // server side of the client's IAudioRecord
class RecordHandle : public android::BnAudioRecord {
public:
RecordHandle(const sp<RecordThread::RecordTrack>& recordTrack);
virtual ~RecordHandle();
virtual sp<IMemory> getCblk() const;
- virtual status_t start();
+ virtual status_t start(pid_t tid);
virtual void stop();
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
@@ -1120,7 +1116,7 @@ private:
const wp<ThreadBase>& thread() { return mThread; }
status_t addHandle(const sp<EffectHandle>& handle);
- void disconnect(const wp<EffectHandle>& handle, bool unpiniflast);
+ void disconnect(const wp<EffectHandle>& handle, bool unpinIfLast);
size_t removeHandle (const wp<EffectHandle>& handle);
effect_descriptor_t& desc() { return mDescriptor; }
@@ -1166,6 +1162,7 @@ mutable Mutex mLock; // mutex for process, commands and handl
status_t mStatus; // initialization status
effect_state mState; // current activation state
Vector< wp<EffectHandle> > mHandles; // list of client handles
+ // First handle in mHandles has highest priority and controls the effect module
uint32_t mMaxDisableWaitCnt; // maximum grace period before forcing an effect off after
// sending disable command.
uint32_t mDisableWaitCnt; // current process() calls count during disable period.
@@ -1196,7 +1193,9 @@ mutable Mutex mLock; // mutex for process, commands and handl
uint32_t *replySize,
void *pReplyData);
virtual void disconnect();
- virtual void disconnect(bool unpiniflast);
+ private:
+ void disconnect(bool unpinIfLast);
+ public:
virtual sp<IMemory> getCblk() const { return mCblkMemory; }
virtual status_t onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags);
@@ -1389,6 +1388,7 @@ mutable Mutex mLock; // mutex for process, commands and handl
hwDev(dev), stream(in) {}
};
+ // for mAudioSessionRefs only
struct AudioSessionRef {
// FIXME rename parameter names when fields get "m" prefix
AudioSessionRef(int sessionid_, pid_t pid_) :
@@ -1406,8 +1406,31 @@ mutable Mutex mLock; // mutex for process, commands and handl
DefaultKeyedVector< pid_t, wp<Client> > mClients; // see ~Client()
mutable Mutex mHardwareLock;
- audio_hw_device_t* mPrimaryHardwareDev;
+
+ // These two fields are immutable after onFirstRef(), so no lock needed to access
+ audio_hw_device_t* mPrimaryHardwareDev; // mAudioHwDevs[0] or NULL
Vector<audio_hw_device_t*> mAudioHwDevs;
+
+ enum hardware_call_state {
+ AUDIO_HW_IDLE = 0,
+ AUDIO_HW_INIT,
+ AUDIO_HW_OUTPUT_OPEN,
+ AUDIO_HW_OUTPUT_CLOSE,
+ AUDIO_HW_INPUT_OPEN,
+ AUDIO_HW_INPUT_CLOSE,
+ AUDIO_HW_STANDBY,
+ AUDIO_HW_SET_MASTER_VOLUME,
+ AUDIO_HW_GET_ROUTING,
+ AUDIO_HW_SET_ROUTING,
+ AUDIO_HW_GET_MODE,
+ AUDIO_HW_SET_MODE,
+ AUDIO_HW_GET_MIC_MUTE,
+ AUDIO_HW_SET_MIC_MUTE,
+ AUDIO_SET_VOICE_VOLUME,
+ AUDIO_SET_PARAMETER,
+ AUDIO_HW_GET_INPUT_BUFFER_SIZE,
+ };
+
mutable hardware_call_state mHardwareStatus; // for dump only
@@ -1421,10 +1444,11 @@ mutable Mutex mLock; // mutex for process, commands and handl
DefaultKeyedVector< audio_io_handle_t, sp<RecordThread> > mRecordThreads;
DefaultKeyedVector< pid_t, sp<NotificationClient> > mNotificationClients;
- volatile int32_t mNextUniqueId;
+ volatile int32_t mNextUniqueId; // updated by android_atomic_inc
audio_mode_t mMode;
bool mBtNrecIsOff;
+ // protected by mLock
Vector<AudioSessionRef*> mAudioSessionRefs;
float masterVolume_l() const { return mMasterVolume; }
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 191520a33a54..cb7678b23e71 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -1,4 +1,4 @@
-/* //device/include/server/AudioFlinger/AudioMixer.cpp
+/*
**
** Copyright 2007, The Android Open Source Project
**
@@ -961,7 +961,12 @@ void AudioMixer::process__genericResampling(state_t* state)
// one track, 16 bits stereo without resampling is the most common case
void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state)
{
+ // This method is only called when state->enabledTracks has exactly
+ // one bit set. The asserts below would verify this, but are commented out
+ // since the whole point of this method is to optimize performance.
+ //assert(0 != state->enabledTracks);
const int i = 31 - __builtin_clz(state->enabledTracks);
+ //assert((1 << i) == state->enabledTracks);
const track_t& t = state->tracks[i];
AudioBufferProvider::Buffer& b(t.buffer);
diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h
index c709686f6825..c95691865c8c 100644
--- a/services/audioflinger/AudioMixer.h
+++ b/services/audioflinger/AudioMixer.h
@@ -1,4 +1,4 @@
-/* //device/include/server/AudioFlinger/AudioMixer.h
+/*
**
** Copyright 2007, The Android Open Source Project
**
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index f8b430ea8f52..041b5a869b0a 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -30,6 +30,7 @@
#include <utils/String16.h>
#include <utils/threads.h>
#include "AudioPolicyService.h"
+#include "ServiceUtilities.h"
#include <cutils/properties.h>
#include <hardware_legacy/power.h>
#include <media/AudioEffect.h>
@@ -49,13 +50,6 @@ static const char kCmdDeadlockedString[] = "AudioPolicyService command thread ma
static const int kDumpLockRetries = 50;
static const int kDumpLockSleepUs = 20000;
-static bool checkPermission() {
- if (getpid() == IPCThreadState::self()->getCallingPid()) return true;
- bool ok = checkCallingPermission(String16("android.permission.MODIFY_AUDIO_SETTINGS"));
- if (!ok) ALOGE("Request requires android.permission.MODIFY_AUDIO_SETTINGS");
- return ok;
-}
-
namespace {
extern struct audio_policy_service_ops aps_ops;
};
@@ -157,7 +151,7 @@ status_t AudioPolicyService::setDeviceConnectionState(audio_devices_t device,
if (mpAudioPolicy == NULL) {
return NO_INIT;
}
- if (!checkPermission()) {
+ if (!settingsAllowed()) {
return PERMISSION_DENIED;
}
if (!audio_is_output_device(device) && !audio_is_input_device(device)) {
@@ -190,7 +184,7 @@ status_t AudioPolicyService::setPhoneState(audio_mode_t state)
if (mpAudioPolicy == NULL) {
return NO_INIT;
}
- if (!checkPermission()) {
+ if (!settingsAllowed()) {
return PERMISSION_DENIED;
}
if (uint32_t(state) >= AUDIO_MODE_CNT) {
@@ -213,7 +207,7 @@ status_t AudioPolicyService::setForceUse(audio_policy_force_use_t usage,
if (mpAudioPolicy == NULL) {
return NO_INIT;
}
- if (!checkPermission()) {
+ if (!settingsAllowed()) {
return PERMISSION_DENIED;
}
if (usage < 0 || usage >= AUDIO_POLICY_FORCE_USE_CNT) {
@@ -388,7 +382,7 @@ status_t AudioPolicyService::initStreamVolume(audio_stream_type_t stream,
if (mpAudioPolicy == NULL) {
return NO_INIT;
}
- if (!checkPermission()) {
+ if (!settingsAllowed()) {
return PERMISSION_DENIED;
}
if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
@@ -405,7 +399,7 @@ status_t AudioPolicyService::setStreamVolumeIndex(audio_stream_type_t stream,
if (mpAudioPolicy == NULL) {
return NO_INIT;
}
- if (!checkPermission()) {
+ if (!settingsAllowed()) {
return PERMISSION_DENIED;
}
if (uint32_t(stream) >= AUDIO_STREAM_CNT) {
@@ -578,7 +572,7 @@ status_t AudioPolicyService::dumpInternals(int fd)
status_t AudioPolicyService::dump(int fd, const Vector<String16>& args)
{
- if (!checkCallingPermission(String16("android.permission.DUMP"))) {
+ if (!dumpAllowed()) {
dumpPermissionDenial(fd);
} else {
bool locked = tryLock(mLock);
@@ -774,7 +768,7 @@ status_t AudioPolicyService::AudioCommandThread::dump(int fd)
snprintf(buffer, SIZE, "- Commands:\n");
result = String8(buffer);
result.append(" Command Time Wait pParam\n");
- for (int i = 0; i < (int)mAudioCommands.size(); i++) {
+ for (size_t i = 0; i < mAudioCommands.size(); i++) {
mAudioCommands[i]->dump(buffer, SIZE);
result.append(buffer);
}
@@ -908,7 +902,7 @@ status_t AudioPolicyService::AudioCommandThread::voiceVolumeCommand(float volume
// insertCommand_l() must be called with mLock held
void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *command, int delayMs)
{
- ssize_t i;
+ ssize_t i; // not size_t because i will count down to -1
Vector <AudioCommand *> removedCommands;
command->mTime = systemTime() + milliseconds(delayMs);
diff --git a/services/audioflinger/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp
index 4eac0328ffe8..9486b9c9efe0 100644
--- a/services/audioflinger/AudioResampler.cpp
+++ b/services/audioflinger/AudioResampler.cpp
@@ -23,8 +23,10 @@
#include <cutils/log.h>
#include <cutils/properties.h>
#include "AudioResampler.h"
+#if 0
#include "AudioResamplerSinc.h"
#include "AudioResamplerCubic.h"
+#endif
#ifdef __arm__
#include <machine/cpu-features.h>
@@ -99,6 +101,7 @@ AudioResampler* AudioResampler::create(int bitDepth, int inChannelCount,
ALOGV("Create linear Resampler");
resampler = new AudioResamplerOrder1(bitDepth, inChannelCount, sampleRate);
break;
+#if 0
case MED_QUALITY:
ALOGV("Create cubic Resampler");
resampler = new AudioResamplerCubic(bitDepth, inChannelCount, sampleRate);
@@ -107,6 +110,7 @@ AudioResampler* AudioResampler::create(int bitDepth, int inChannelCount,
ALOGV("Create sinc Resampler");
resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate);
break;
+#endif
}
// initialize resampler
diff --git a/services/audioflinger/AudioResampler.h b/services/audioflinger/AudioResampler.h
index ee171ff3ec3d..c23016e02ca5 100644
--- a/services/audioflinger/AudioResampler.h
+++ b/services/audioflinger/AudioResampler.h
@@ -72,9 +72,9 @@ protected:
AudioResampler(const AudioResampler&);
AudioResampler& operator=(const AudioResampler&);
- int32_t mBitDepth;
- int32_t mChannelCount;
- int32_t mSampleRate;
+ const int32_t mBitDepth;
+ const int32_t mChannelCount;
+ const int32_t mSampleRate;
int32_t mInSampleRate;
AudioBufferProvider::Buffer mBuffer;
union {
diff --git a/services/audioflinger/AudioResamplerSinc.cpp b/services/audioflinger/AudioResamplerSinc.cpp
index d012433c72ee..7a27b810afd0 100644
--- a/services/audioflinger/AudioResamplerSinc.cpp
+++ b/services/audioflinger/AudioResamplerSinc.cpp
@@ -199,33 +199,32 @@ void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount,
size_t outputSampleCount = outFrameCount * 2;
size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
- AudioBufferProvider::Buffer& buffer(mBuffer);
while (outputIndex < outputSampleCount) {
// buffer is empty, fetch a new one
- while (buffer.frameCount == 0) {
- buffer.frameCount = inFrameCount;
- provider->getNextBuffer(&buffer);
- if (buffer.raw == NULL) {
+ while (mBuffer.frameCount == 0) {
+ mBuffer.frameCount = inFrameCount;
+ provider->getNextBuffer(&mBuffer);
+ if (mBuffer.raw == NULL) {
goto resample_exit;
}
const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
if (phaseIndex == 1) {
// read one frame
- read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex);
+ read<CHANNELS>(impulse, phaseFraction, mBuffer.i16, inputIndex);
} else if (phaseIndex == 2) {
// read 2 frames
- read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex);
+ read<CHANNELS>(impulse, phaseFraction, mBuffer.i16, inputIndex);
inputIndex++;
if (inputIndex >= mBuffer.frameCount) {
inputIndex -= mBuffer.frameCount;
- provider->releaseBuffer(&buffer);
+ provider->releaseBuffer(&mBuffer);
} else {
- read<CHANNELS>(impulse, phaseFraction, buffer.i16, inputIndex);
+ read<CHANNELS>(impulse, phaseFraction, mBuffer.i16, inputIndex);
}
}
}
- int16_t *in = buffer.i16;
- const size_t frameCount = buffer.frameCount;
+ int16_t *in = mBuffer.i16;
+ const size_t frameCount = mBuffer.frameCount;
// Always read-in the first samples from the input buffer
int16_t* head = impulse + halfNumCoefs*CHANNELS;
@@ -264,7 +263,7 @@ void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount,
// if done with buffer, save samples
if (inputIndex >= frameCount) {
inputIndex -= frameCount;
- provider->releaseBuffer(&buffer);
+ provider->releaseBuffer(&mBuffer);
}
}
diff --git a/services/audioflinger/ServiceUtilities.cpp b/services/audioflinger/ServiceUtilities.cpp
new file mode 100644
index 000000000000..6a58852f4210
--- /dev/null
+++ b/services/audioflinger/ServiceUtilities.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/PermissionCache.h>
+#include "ServiceUtilities.h"
+
+namespace android {
+
+// This optimization assumes mediaserver process doesn't fork, which it doesn't
+const pid_t getpid_cached = getpid();
+
+bool recordingAllowed() {
+ if (getpid_cached == IPCThreadState::self()->getCallingPid()) return true;
+ static const String16 sRecordAudio("android.permission.RECORD_AUDIO");
+ // don't use PermissionCache; this is not a system permission
+ bool ok = checkCallingPermission(sRecordAudio);
+ if (!ok) ALOGE("Request requires android.permission.RECORD_AUDIO");
+ return ok;
+}
+
+bool settingsAllowed() {
+ if (getpid_cached == IPCThreadState::self()->getCallingPid()) return true;
+ static const String16 sAudioSettings("android.permission.MODIFY_AUDIO_SETTINGS");
+ // don't use PermissionCache; this is not a system permission
+ bool ok = checkCallingPermission(sAudioSettings);
+ if (!ok) ALOGE("Request requires android.permission.MODIFY_AUDIO_SETTINGS");
+ return ok;
+}
+
+bool dumpAllowed() {
+ // don't optimize for same pid, since mediaserver never dumps itself
+ static const String16 sDump("android.permission.DUMP");
+ // OK to use PermissionCache; this is a system permission
+ bool ok = PermissionCache::checkCallingPermission(sDump);
+ // convention is for caller to dump an error message to fd instead of logging here
+ //if (!ok) ALOGE("Request requires android.permission.DUMP");
+ return ok;
+}
+
+} // namespace android
diff --git a/services/audioflinger/ServiceUtilities.h b/services/audioflinger/ServiceUtilities.h
new file mode 100644
index 000000000000..f77ec5bcee5c
--- /dev/null
+++ b/services/audioflinger/ServiceUtilities.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#include <unistd.h>
+
+namespace android {
+
+extern const pid_t getpid_cached;
+
+bool recordingAllowed();
+bool settingsAllowed();
+bool dumpAllowed();
+
+}
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index ad64ccd55f4f..d4e59d1b46c8 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -24,24 +24,15 @@
// Log detailed debug messages about each outbound event processed by the dispatcher.
#define DEBUG_OUTBOUND_EVENT_DETAILS 0
-// Log debug messages about batching.
-#define DEBUG_BATCHING 0
-
// Log debug messages about the dispatch cycle.
#define DEBUG_DISPATCH_CYCLE 0
// Log debug messages about registrations.
#define DEBUG_REGISTRATION 0
-// Log debug messages about performance statistics.
-#define DEBUG_PERFORMANCE_STATISTICS 0
-
// Log debug messages about input event injection.
#define DEBUG_INJECTION 0
-// Log debug messages about input event throttling.
-#define DEBUG_THROTTLING 0
-
// Log debug messages about input focus tracking.
#define DEBUG_FOCUS 0
@@ -79,21 +70,11 @@ const nsecs_t APP_SWITCH_TIMEOUT = 500 * 1000000LL; // 0.5sec
// before considering it stale and dropping it.
const nsecs_t STALE_EVENT_TIMEOUT = 10000 * 1000000LL; // 10sec
-// Motion samples that are received within this amount of time are simply coalesced
-// when batched instead of being appended. This is done because some drivers update
-// the location of pointers one at a time instead of all at once.
-// For example, when there are 10 fingers down, the input dispatcher may receive 10
-// samples in quick succession with only one finger's location changed in each sample.
-//
-// This value effectively imposes an upper bound on the touch sampling rate.
-// Touch sensors typically have a 50Hz - 200Hz sampling rate, so we expect distinct
-// samples to become available 5-20ms apart but individual finger reports can trickle
-// in over a period of 2-4ms or so.
-//
-// Empirical testing shows that a 2ms coalescing interval (500Hz) is not enough,
-// a 3ms coalescing interval (333Hz) works well most of the time and doesn't introduce
-// significant quantization noise on current hardware.
-const nsecs_t MOTION_SAMPLE_COALESCE_INTERVAL = 3 * 1000000LL; // 3ms, 333Hz
+// Amount of time to allow touch events to be streamed out to a connection before requiring
+// that the first event be finished. This value extends the ANR timeout by the specified
+// amount. For example, if streaming is allowed to get ahead by one second relative to the
+// queue of waiting unfinished events, then ANRs will similarly be delayed by one second.
+const nsecs_t STREAM_AHEAD_EVENT_TIMEOUT = 500 * 1000000LL; // 0.5sec
static inline nsecs_t now() {
@@ -203,21 +184,12 @@ InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& polic
mPendingEvent(NULL), mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
mNextUnblockedEvent(NULL),
mDispatchEnabled(true), mDispatchFrozen(false), mInputFilterEnabled(false),
- mCurrentInputTargetsValid(false),
mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
mLooper = new Looper(false);
mKeyRepeatState.lastKeyEntry = NULL;
policy->getDispatcherConfiguration(&mConfig);
-
- mThrottleState.minTimeBetweenEvents = 1000000000LL / mConfig.maxEventsPerSecond;
- mThrottleState.lastDeviceId = -1;
-
-#if DEBUG_THROTTLING
- mThrottleState.originalSampleCount = 0;
- ALOGD("Throttling - Max events per second = %d", mConfig.maxEventsPerSecond);
-#endif
}
InputDispatcher::~InputDispatcher() {
@@ -229,8 +201,8 @@ InputDispatcher::~InputDispatcher() {
drainInboundQueueLocked();
}
- while (mConnectionsByReceiveFd.size() != 0) {
- unregisterInputChannel(mConnectionsByReceiveFd.valueAt(0)->inputChannel);
+ while (mConnectionsByFd.size() != 0) {
+ unregisterInputChannel(mConnectionsByFd.valueAt(0)->inputChannel);
}
}
@@ -302,78 +274,21 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
}
// Nothing to do if there is no pending event.
- if (! mPendingEvent) {
- if (mActiveConnections.isEmpty()) {
- dispatchIdleLocked();
- }
+ if (!mPendingEvent) {
return;
}
} else {
// Inbound queue has at least one entry.
- EventEntry* entry = mInboundQueue.head;
-
- // Throttle the entry if it is a move event and there are no
- // other events behind it in the queue. Due to movement batching, additional
- // samples may be appended to this event by the time the throttling timeout
- // expires.
- // TODO Make this smarter and consider throttling per device independently.
- if (entry->type == EventEntry::TYPE_MOTION
- && !isAppSwitchDue
- && mDispatchEnabled
- && (entry->policyFlags & POLICY_FLAG_PASS_TO_USER)
- && !entry->isInjected()) {
- MotionEntry* motionEntry = static_cast<MotionEntry*>(entry);
- int32_t deviceId = motionEntry->deviceId;
- uint32_t source = motionEntry->source;
- if (! isAppSwitchDue
- && !motionEntry->next // exactly one event, no successors
- && (motionEntry->action == AMOTION_EVENT_ACTION_MOVE
- || motionEntry->action == AMOTION_EVENT_ACTION_HOVER_MOVE)
- && deviceId == mThrottleState.lastDeviceId
- && source == mThrottleState.lastSource) {
- nsecs_t nextTime = mThrottleState.lastEventTime
- + mThrottleState.minTimeBetweenEvents;
- if (currentTime < nextTime) {
- // Throttle it!
-#if DEBUG_THROTTLING
- ALOGD("Throttling - Delaying motion event for "
- "device %d, source 0x%08x by up to %0.3fms.",
- deviceId, source, (nextTime - currentTime) * 0.000001);
-#endif
- if (nextTime < *nextWakeupTime) {
- *nextWakeupTime = nextTime;
- }
- if (mThrottleState.originalSampleCount == 0) {
- mThrottleState.originalSampleCount =
- motionEntry->countSamples();
- }
- return;
- }
- }
-
-#if DEBUG_THROTTLING
- if (mThrottleState.originalSampleCount != 0) {
- uint32_t count = motionEntry->countSamples();
- ALOGD("Throttling - Motion event sample count grew by %d from %d to %d.",
- count - mThrottleState.originalSampleCount,
- mThrottleState.originalSampleCount, count);
- mThrottleState.originalSampleCount = 0;
- }
-#endif
-
- mThrottleState.lastEventTime = currentTime;
- mThrottleState.lastDeviceId = deviceId;
- mThrottleState.lastSource = source;
- }
-
- mInboundQueue.dequeue(entry);
- mPendingEvent = entry;
+ mPendingEvent = mInboundQueue.dequeueAtHead();
}
// Poke user activity for this event.
if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {
pokeUserActivityLocked(mPendingEvent);
}
+
+ // Get ready to dispatch the event.
+ resetANRTimeoutsLocked();
}
// Now we have an event to dispatch.
@@ -461,16 +376,6 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
}
}
-void InputDispatcher::dispatchIdleLocked() {
-#if DEBUG_FOCUS
- ALOGD("Dispatcher idle. There are no pending events or active connections.");
-#endif
-
- // Reset targets when idle, to release input channels and other resources
- // they are holding onto.
- resetTargetsLocked();
-}
-
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
bool needWake = mInboundQueue.isEmpty();
mInboundQueue.enqueueAtTail(entry);
@@ -508,9 +413,9 @@ bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
&& (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
&& mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY
&& mInputTargetWaitApplicationHandle != NULL) {
- int32_t x = int32_t(motionEntry->firstSample.pointerCoords[0].
+ int32_t x = int32_t(motionEntry->pointerCoords[0].
getAxisValue(AMOTION_EVENT_AXIS_X));
- int32_t y = int32_t(motionEntry->firstSample.pointerCoords[0].
+ int32_t y = int32_t(motionEntry->pointerCoords[0].
getAxisValue(AMOTION_EVENT_AXIS_Y));
sp<InputWindowHandle> touchedWindowHandle = findTouchedWindowAtLocked(x, y);
if (touchedWindowHandle != NULL
@@ -671,6 +576,7 @@ void InputDispatcher::drainInboundQueueLocked() {
void InputDispatcher::releasePendingEventLocked() {
if (mPendingEvent) {
+ resetANRTimeoutsLocked();
releaseInboundEventLocked(mPendingEvent);
mPendingEvent = NULL;
}
@@ -793,7 +699,6 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
}
entry->dispatchInProgress = true;
- resetTargetsLocked();
logOutboundKeyDetailsLocked("dispatchKey - ", entry);
}
@@ -832,31 +737,28 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
// Clean up if dropping the event.
if (*dropReason != DROP_REASON_NOT_DROPPED) {
- resetTargetsLocked();
setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
return true;
}
// Identify targets.
- if (! mCurrentInputTargetsValid) {
- int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
- entry, nextWakeupTime);
- if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
- return false;
- }
-
- setInjectionResultLocked(entry, injectionResult);
- if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
- return true;
- }
+ Vector<InputTarget> inputTargets;
+ int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
+ entry, inputTargets, nextWakeupTime);
+ if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
+ return false;
+ }
- addMonitoringTargetsLocked();
- commitTargetsLocked();
+ setInjectionResultLocked(entry, injectionResult);
+ if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
+ return true;
}
+ addMonitoringTargetsLocked(inputTargets);
+
// Dispatch the key.
- dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
+ dispatchEventLocked(currentTime, entry, inputTargets);
return true;
}
@@ -877,14 +779,12 @@ bool InputDispatcher::dispatchMotionLocked(
// Preprocessing.
if (! entry->dispatchInProgress) {
entry->dispatchInProgress = true;
- resetTargetsLocked();
logOutboundMotionDetailsLocked("dispatchMotion - ", entry);
}
// Clean up if dropping the event.
if (*dropReason != DROP_REASON_NOT_DROPPED) {
- resetTargetsLocked();
setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
return true;
@@ -893,75 +793,37 @@ bool InputDispatcher::dispatchMotionLocked(
bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;
// Identify targets.
- bool conflictingPointerActions = false;
- if (! mCurrentInputTargetsValid) {
- int32_t injectionResult;
- const MotionSample* splitBatchAfterSample = NULL;
- if (isPointerEvent) {
- // Pointer event. (eg. touchscreen)
- injectionResult = findTouchedWindowTargetsLocked(currentTime,
- entry, nextWakeupTime, &conflictingPointerActions, &splitBatchAfterSample);
- } else {
- // Non touch event. (eg. trackball)
- injectionResult = findFocusedWindowTargetsLocked(currentTime,
- entry, nextWakeupTime);
- }
- if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
- return false;
- }
-
- setInjectionResultLocked(entry, injectionResult);
- if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
- return true;
- }
-
- addMonitoringTargetsLocked();
- commitTargetsLocked();
-
- // Unbatch the event if necessary by splitting it into two parts after the
- // motion sample indicated by splitBatchAfterSample.
- if (splitBatchAfterSample && splitBatchAfterSample->next) {
-#if DEBUG_BATCHING
- uint32_t originalSampleCount = entry->countSamples();
-#endif
- MotionSample* nextSample = splitBatchAfterSample->next;
- MotionEntry* nextEntry = new MotionEntry(nextSample->eventTime,
- entry->deviceId, entry->source, entry->policyFlags,
- entry->action, entry->flags,
- entry->metaState, entry->buttonState, entry->edgeFlags,
- entry->xPrecision, entry->yPrecision, entry->downTime,
- entry->pointerCount, entry->pointerProperties, nextSample->pointerCoords);
- if (nextSample != entry->lastSample) {
- nextEntry->firstSample.next = nextSample->next;
- nextEntry->lastSample = entry->lastSample;
- }
- delete nextSample;
-
- entry->lastSample = const_cast<MotionSample*>(splitBatchAfterSample);
- entry->lastSample->next = NULL;
+ Vector<InputTarget> inputTargets;
- if (entry->injectionState) {
- nextEntry->injectionState = entry->injectionState;
- entry->injectionState->refCount += 1;
- }
-
-#if DEBUG_BATCHING
- ALOGD("Split batch of %d samples into two parts, first part has %d samples, "
- "second part has %d samples.", originalSampleCount,
- entry->countSamples(), nextEntry->countSamples());
-#endif
+ bool conflictingPointerActions = false;
+ int32_t injectionResult;
+ if (isPointerEvent) {
+ // Pointer event. (eg. touchscreen)
+ injectionResult = findTouchedWindowTargetsLocked(currentTime,
+ entry, inputTargets, nextWakeupTime, &conflictingPointerActions);
+ } else {
+ // Non touch event. (eg. trackball)
+ injectionResult = findFocusedWindowTargetsLocked(currentTime,
+ entry, inputTargets, nextWakeupTime);
+ }
+ if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
+ return false;
+ }
- mInboundQueue.enqueueAtHead(nextEntry);
- }
+ setInjectionResultLocked(entry, injectionResult);
+ if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
+ return true;
}
+ addMonitoringTargetsLocked(inputTargets);
+
// Dispatch the motion.
if (conflictingPointerActions) {
CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
"conflicting pointer actions");
synthesizeCancelationEventsForAllConnectionsLocked(options);
}
- dispatchEventToCurrentInputTargetsLocked(currentTime, entry, false);
+ dispatchEventLocked(currentTime, entry, inputTargets);
return true;
}
@@ -979,12 +841,6 @@ void InputDispatcher::logOutboundMotionDetailsLocked(const char* prefix, const M
entry->edgeFlags, entry->xPrecision, entry->yPrecision,
entry->downTime);
- // Print the most recent sample that we have available, this may change due to batching.
- size_t sampleCount = 1;
- const MotionSample* sample = & entry->firstSample;
- for (; sample->next != NULL; sample = sample->next) {
- sampleCount += 1;
- }
for (uint32_t i = 0; i < entry->pointerCount; i++) {
ALOGD(" Pointer %d: id=%d, toolType=%d, "
"x=%f, y=%f, pressure=%f, size=%f, "
@@ -992,45 +848,36 @@ void InputDispatcher::logOutboundMotionDetailsLocked(const char* prefix, const M
"orientation=%f",
i, entry->pointerProperties[i].id,
entry->pointerProperties[i].toolType,
- sample->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X),
- sample->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
- sample->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
- sample->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
- sample->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
- sample->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
- sample->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
- sample->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
- sample->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
- }
-
- // Keep in mind that due to batching, it is possible for the number of samples actually
- // dispatched to change before the application finally consumed them.
- if (entry->action == AMOTION_EVENT_ACTION_MOVE) {
- ALOGD(" ... Total movement samples currently batched %d ...", sampleCount);
+ entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X),
+ entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
+ entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
+ entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
+ entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
+ entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
+ entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
+ entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
+ entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION));
}
#endif
}
-void InputDispatcher::dispatchEventToCurrentInputTargetsLocked(nsecs_t currentTime,
- EventEntry* eventEntry, bool resumeWithAppendedMotionSample) {
+void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
+ EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
#if DEBUG_DISPATCH_CYCLE
- ALOGD("dispatchEventToCurrentInputTargets - "
- "resumeWithAppendedMotionSample=%s",
- toString(resumeWithAppendedMotionSample));
+ ALOGD("dispatchEventToCurrentInputTargets");
#endif
ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true
pokeUserActivityLocked(eventEntry);
- for (size_t i = 0; i < mCurrentInputTargets.size(); i++) {
- const InputTarget& inputTarget = mCurrentInputTargets.itemAt(i);
+ for (size_t i = 0; i < inputTargets.size(); i++) {
+ const InputTarget& inputTarget = inputTargets.itemAt(i);
ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
if (connectionIndex >= 0) {
- sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
- prepareDispatchCycleLocked(currentTime, connection, eventEntry, & inputTarget,
- resumeWithAppendedMotionSample);
+ sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
+ prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
} else {
#if DEBUG_FOCUS
ALOGD("Dropping event delivery to target with channel '%s' because it "
@@ -1041,16 +888,6 @@ void InputDispatcher::dispatchEventToCurrentInputTargetsLocked(nsecs_t currentTi
}
}
-void InputDispatcher::resetTargetsLocked() {
- mCurrentInputTargetsValid = false;
- mCurrentInputTargets.clear();
- resetANRTimeoutsLocked();
-}
-
-void InputDispatcher::commitTargetsLocked() {
- mCurrentInputTargetsValid = true;
-}
-
int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime,
const EventEntry* entry,
const sp<InputApplicationHandle>& applicationHandle,
@@ -1135,7 +972,7 @@ void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout
if (inputChannel.get()) {
ssize_t connectionIndex = getConnectionIndexLocked(inputChannel);
if (connectionIndex >= 0) {
- sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
+ sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
if (connection->status == Connection::STATUS_NORMAL) {
CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS,
"application not responding");
@@ -1165,9 +1002,7 @@ void InputDispatcher::resetANRTimeoutsLocked() {
}
int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
- const EventEntry* entry, nsecs_t* nextWakeupTime) {
- mCurrentInputTargets.clear();
-
+ const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) {
int32_t injectionResult;
// If there is no currently focused window and no focused application
@@ -1206,7 +1041,7 @@ int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
}
// If the currently focused window is still working on previous events then keep waiting.
- if (! isWindowFinishedWithPreviousInputLocked(mFocusedWindowHandle)) {
+ if (!isWindowReadyForMoreInputLocked(currentTime, mFocusedWindowHandle, entry)) {
#if DEBUG_FOCUS
ALOGD("Waiting because focused window still processing previous input.");
#endif
@@ -1218,7 +1053,8 @@ int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
// Success! Output targets.
injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
addWindowTargetLocked(mFocusedWindowHandle,
- InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0));
+ InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0),
+ inputTargets);
// Done.
Failed:
@@ -1235,16 +1071,14 @@ Unresponsive:
}
int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
- const MotionEntry* entry, nsecs_t* nextWakeupTime, bool* outConflictingPointerActions,
- const MotionSample** outSplitBatchAfterSample) {
+ const MotionEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime,
+ bool* outConflictingPointerActions) {
enum InjectionPermission {
INJECTION_PERMISSION_UNKNOWN,
INJECTION_PERMISSION_GRANTED,
INJECTION_PERMISSION_DENIED
};
- mCurrentInputTargets.clear();
-
nsecs_t startTime = now();
// For security reasons, we defer updating the touch state until we are sure that
@@ -1316,11 +1150,10 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {
/* Case 1: New splittable pointer going down, or need target for hover or scroll. */
- const MotionSample* sample = &entry->firstSample;
int32_t pointerIndex = getMotionEventActionPointerIndex(action);
- int32_t x = int32_t(sample->pointerCoords[pointerIndex].
+ int32_t x = int32_t(entry->pointerCoords[pointerIndex].
getAxisValue(AMOTION_EVENT_AXIS_X));
- int32_t y = int32_t(sample->pointerCoords[pointerIndex].
+ int32_t y = int32_t(entry->pointerCoords[pointerIndex].
getAxisValue(AMOTION_EVENT_AXIS_Y));
sp<InputWindowHandle> newTouchedWindowHandle;
sp<InputWindowHandle> topErrorWindowHandle;
@@ -1420,21 +1253,6 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
// Update hover state.
if (isHoverAction) {
newHoverWindowHandle = newTouchedWindowHandle;
-
- // Ensure all subsequent motion samples are also within the touched window.
- // Set *outSplitBatchAfterSample to the sample before the first one that is not
- // within the touched window.
- if (!isTouchModal) {
- while (sample->next) {
- if (!newHoverWindowHandle->getInfo()->touchableRegionContainsPoint(
- sample->next->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X),
- sample->next->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y))) {
- *outSplitBatchAfterSample = sample;
- break;
- }
- sample = sample->next;
- }
- }
} else if (maskedAction == AMOTION_EVENT_ACTION_SCROLL) {
newHoverWindowHandle = mLastHoverWindowHandle;
}
@@ -1463,9 +1281,8 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
if (maskedAction == AMOTION_EVENT_ACTION_MOVE
&& entry->pointerCount == 1
&& mTempTouchState.isSlippery()) {
- const MotionSample* sample = &entry->firstSample;
- int32_t x = int32_t(sample->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
- int32_t y = int32_t(sample->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
+ int32_t x = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));
+ int32_t y = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
sp<InputWindowHandle> oldTouchedWindowHandle =
mTempTouchState.getFirstForegroundWindowHandle();
@@ -1500,17 +1317,11 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
pointerIds.markBit(entry->pointerProperties[0].id);
}
mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);
-
- // Split the batch here so we send exactly one sample.
- *outSplitBatchAfterSample = &entry->firstSample;
}
}
}
if (newHoverWindowHandle != mLastHoverWindowHandle) {
- // Split the batch here so we send exactly one sample as part of ENTER or EXIT.
- *outSplitBatchAfterSample = &entry->firstSample;
-
// Let the previous window know that the hover sequence is over.
if (mLastHoverWindowHandle != NULL) {
#if DEBUG_HOVER
@@ -1593,7 +1404,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
}
// If the touched window is still working on previous events then keep waiting.
- if (! isWindowFinishedWithPreviousInputLocked(touchedWindow.windowHandle)) {
+ if (!isWindowReadyForMoreInputLocked(currentTime, touchedWindow.windowHandle, entry)) {
#if DEBUG_FOCUS
ALOGD("Waiting because touched window still processing previous input.");
#endif
@@ -1633,7 +1444,7 @@ int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
const TouchedWindow& touchedWindow = mTempTouchState.windows.itemAt(i);
addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags,
- touchedWindow.pointerIds);
+ touchedWindow.pointerIds, inputTargets);
}
// Drop the outside or hover touch windows since we will not care about them
@@ -1738,11 +1549,11 @@ Unresponsive:
}
void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
- int32_t targetFlags, BitSet32 pointerIds) {
- mCurrentInputTargets.push();
+ int32_t targetFlags, BitSet32 pointerIds, Vector<InputTarget>& inputTargets) {
+ inputTargets.push();
const InputWindowInfo* windowInfo = windowHandle->getInfo();
- InputTarget& target = mCurrentInputTargets.editTop();
+ InputTarget& target = inputTargets.editTop();
target.inputChannel = windowInfo->inputChannel;
target.flags = targetFlags;
target.xOffset = - windowInfo->frameLeft;
@@ -1751,11 +1562,11 @@ void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowH
target.pointerIds = pointerIds;
}
-void InputDispatcher::addMonitoringTargetsLocked() {
+void InputDispatcher::addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets) {
for (size_t i = 0; i < mMonitoringChannels.size(); i++) {
- mCurrentInputTargets.push();
+ inputTargets.push();
- InputTarget& target = mCurrentInputTargets.editTop();
+ InputTarget& target = inputTargets.editTop();
target.inputChannel = mMonitoringChannels[i];
target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
target.xOffset = 0;
@@ -1804,15 +1615,51 @@ bool InputDispatcher::isWindowObscuredAtPointLocked(
return false;
}
-bool InputDispatcher::isWindowFinishedWithPreviousInputLocked(
- const sp<InputWindowHandle>& windowHandle) {
+bool InputDispatcher::isWindowReadyForMoreInputLocked(nsecs_t currentTime,
+ const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry) {
ssize_t connectionIndex = getConnectionIndexLocked(windowHandle->getInputChannel());
if (connectionIndex >= 0) {
- sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
- return connection->outboundQueue.isEmpty();
- } else {
- return true;
+ sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
+ if (connection->inputPublisherBlocked) {
+ return false;
+ }
+ if (eventEntry->type == EventEntry::TYPE_KEY) {
+ // If the event is a key event, then we must wait for all previous events to
+ // complete before delivering it because previous events may have the
+ // side-effect of transferring focus to a different window and we want to
+ // ensure that the following keys are sent to the new window.
+ //
+ // Suppose the user touches a button in a window then immediately presses "A".
+ // If the button causes a pop-up window to appear then we want to ensure that
+ // the "A" key is delivered to the new pop-up window. This is because users
+ // often anticipate pending UI changes when typing on a keyboard.
+ // To obtain this behavior, we must serialize key events with respect to all
+ // prior input events.
+ return connection->outboundQueue.isEmpty()
+ && connection->waitQueue.isEmpty();
+ }
+ // Touch events can always be sent to a window immediately because the user intended
+ // to touch whatever was visible at the time. Even if focus changes or a new
+ // window appears moments later, the touch event was meant to be delivered to
+ // whatever window happened to be on screen at the time.
+ //
+ // Generic motion events, such as trackball or joystick events are a little trickier.
+ // Like key events, generic motion events are delivered to the focused window.
+ // Unlike key events, generic motion events don't tend to transfer focus to other
+ // windows and it is not important for them to be serialized. So we prefer to deliver
+ // generic motion events as soon as possible to improve efficiency and reduce lag
+ // through batching.
+ //
+ // The one case where we pause input event delivery is when the wait queue is piling
+ // up with lots of events because the application is not responding.
+ // This condition ensures that ANRs are detected reliably.
+ if (!connection->waitQueue.isEmpty()
+ && currentTime >= connection->waitQueue.head->eventEntry->eventTime
+ + STREAM_AHEAD_EVENT_TIMEOUT) {
+ return false;
+ }
}
+ return true;
}
String8 InputDispatcher::getApplicationWindowLabelLocked(
@@ -1865,23 +1712,16 @@ void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) {
}
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
- const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
- bool resumeWithAppendedMotionSample) {
+ const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
#if DEBUG_DISPATCH_CYCLE
ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, "
"xOffset=%f, yOffset=%f, scaleFactor=%f, "
- "pointerIds=0x%x, "
- "resumeWithAppendedMotionSample=%s",
+ "pointerIds=0x%x",
connection->getInputChannelName(), inputTarget->flags,
inputTarget->xOffset, inputTarget->yOffset,
- inputTarget->scaleFactor, inputTarget->pointerIds.value,
- toString(resumeWithAppendedMotionSample));
+ inputTarget->scaleFactor, inputTarget->pointerIds.value);
#endif
- // Make sure we are never called for streaming when splitting across multiple windows.
- bool isSplit = inputTarget->flags & InputTarget::FLAG_SPLIT;
- ALOG_ASSERT(! (resumeWithAppendedMotionSample && isSplit));
-
// Skip this event if the connection status is not normal.
// We don't want to enqueue additional outbound events if the connection is broken.
if (connection->status != Connection::STATUS_NORMAL) {
@@ -1893,7 +1733,7 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
}
// Split a motion event if needed.
- if (isSplit) {
+ if (inputTarget->flags & InputTarget::FLAG_SPLIT) {
ALOG_ASSERT(eventEntry->type == EventEntry::TYPE_MOTION);
MotionEntry* originalMotionEntry = static_cast<MotionEntry*>(eventEntry);
@@ -1909,145 +1749,43 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
logOutboundMotionDetailsLocked(" ", splitMotionEntry);
#endif
enqueueDispatchEntriesLocked(currentTime, connection,
- splitMotionEntry, inputTarget, resumeWithAppendedMotionSample);
+ splitMotionEntry, inputTarget);
splitMotionEntry->release();
return;
}
}
// Not splitting. Enqueue dispatch entries for the event as is.
- enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget,
- resumeWithAppendedMotionSample);
+ enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
}
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
- const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
- bool resumeWithAppendedMotionSample) {
- // Resume the dispatch cycle with a freshly appended motion sample.
- // First we check that the last dispatch entry in the outbound queue is for the same
- // motion event to which we appended the motion sample. If we find such a dispatch
- // entry, and if it is currently in progress then we try to stream the new sample.
+ const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
bool wasEmpty = connection->outboundQueue.isEmpty();
- if (! wasEmpty && resumeWithAppendedMotionSample) {
- DispatchEntry* motionEventDispatchEntry =
- connection->findQueuedDispatchEntryForEvent(eventEntry);
- if (motionEventDispatchEntry) {
- // If the dispatch entry is not in progress, then we must be busy dispatching an
- // earlier event. Not a problem, the motion event is on the outbound queue and will
- // be dispatched later.
- if (! motionEventDispatchEntry->inProgress) {
-#if DEBUG_BATCHING
- ALOGD("channel '%s' ~ Not streaming because the motion event has "
- "not yet been dispatched. "
- "(Waiting for earlier events to be consumed.)",
- connection->getInputChannelName());
-#endif
- return;
- }
-
- // If the dispatch entry is in progress but it already has a tail of pending
- // motion samples, then it must mean that the shared memory buffer filled up.
- // Not a problem, when this dispatch cycle is finished, we will eventually start
- // a new dispatch cycle to process the tail and that tail includes the newly
- // appended motion sample.
- if (motionEventDispatchEntry->tailMotionSample) {
-#if DEBUG_BATCHING
- ALOGD("channel '%s' ~ Not streaming because no new samples can "
- "be appended to the motion event in this dispatch cycle. "
- "(Waiting for next dispatch cycle to start.)",
- connection->getInputChannelName());
-#endif
- 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
- ALOGD("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).
- MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
- MotionSample* appendedMotionSample = motionEntry->lastSample;
- status_t status;
- if (motionEventDispatchEntry->scaleFactor == 1.0f) {
- status = connection->inputPublisher.appendMotionSample(
- appendedMotionSample->eventTime, appendedMotionSample->pointerCoords);
- } else {
- PointerCoords scaledCoords[MAX_POINTERS];
- for (size_t i = 0; i < motionEntry->pointerCount; i++) {
- scaledCoords[i] = appendedMotionSample->pointerCoords[i];
- scaledCoords[i].scale(motionEventDispatchEntry->scaleFactor);
- }
- status = connection->inputPublisher.appendMotionSample(
- appendedMotionSample->eventTime, scaledCoords);
- }
- if (status == OK) {
-#if DEBUG_BATCHING
- ALOGD("channel '%s' ~ Successfully streamed new motion sample.",
- connection->getInputChannelName());
-#endif
- return;
- }
-
-#if DEBUG_BATCHING
- if (status == NO_MEMORY) {
- ALOGD("channel '%s' ~ Could not append motion sample to currently "
- "dispatched move event because the shared memory buffer is full. "
- "(Waiting for next dispatch cycle to start.)",
- connection->getInputChannelName());
- } else if (status == status_t(FAILED_TRANSACTION)) {
- ALOGD("channel '%s' ~ Could not append motion sample to currently "
- "dispatched move event because the event has already been consumed. "
- "(Waiting for next dispatch cycle to start.)",
- connection->getInputChannelName());
- } else {
- ALOGD("channel '%s' ~ Could not append motion sample to currently "
- "dispatched move event due to an error, status=%d. "
- "(Waiting for next dispatch cycle to start.)",
- connection->getInputChannelName(), status);
- }
-#endif
- // Failed to stream. Start a new tail of pending motion samples to dispatch
- // in the next cycle.
- motionEventDispatchEntry->tailMotionSample = appendedMotionSample;
- return;
- }
- }
-
// Enqueue dispatch entries for the requested modes.
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
- resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
+ InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
- resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_OUTSIDE);
+ InputTarget::FLAG_DISPATCH_AS_OUTSIDE);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
- resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
+ InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
- resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_IS);
+ InputTarget::FLAG_DISPATCH_AS_IS);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
- resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
+ InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
- resumeWithAppendedMotionSample, InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);
+ InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);
// If the outbound queue was previously empty, start the dispatch cycle going.
if (wasEmpty && !connection->outboundQueue.isEmpty()) {
- activateConnectionLocked(connection.get());
startDispatchCycleLocked(currentTime, connection);
}
}
void InputDispatcher::enqueueDispatchEntryLocked(
const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
- bool resumeWithAppendedMotionSample, int32_t dispatchMode) {
+ int32_t dispatchMode) {
int32_t inputTargetFlags = inputTarget->flags;
if (!(inputTargetFlags & dispatchMode)) {
return;
@@ -2060,20 +1798,6 @@ void InputDispatcher::enqueueDispatchEntryLocked(
inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset,
inputTarget->scaleFactor);
- // Handle the case where we could not stream a new motion sample because the consumer has
- // already consumed the motion event (otherwise the corresponding dispatch entry would
- // still be in the outbound queue for this connection). We set the head motion sample
- // to the list starting with the newly appended motion sample.
- if (resumeWithAppendedMotionSample) {
-#if DEBUG_BATCHING
- ALOGD("channel '%s' ~ Preparing a new dispatch cycle for additional motion samples "
- "that cannot be streamed because the motion event has already been consumed.",
- connection->getInputChannelName());
-#endif
- MotionSample* appendedMotionSample = static_cast<MotionEntry*>(eventEntry)->lastSample;
- dispatchEntry->headMotionSample = appendedMotionSample;
- }
-
// Apply target flags and update the connection's input state.
switch (eventEntry->type) {
case EventEntry::TYPE_KEY: {
@@ -2152,227 +1876,128 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
connection->getInputChannelName());
#endif
- ALOG_ASSERT(connection->status == Connection::STATUS_NORMAL);
- ALOG_ASSERT(! connection->outboundQueue.isEmpty());
-
- DispatchEntry* dispatchEntry = connection->outboundQueue.head;
- ALOG_ASSERT(! dispatchEntry->inProgress);
-
- // Mark the dispatch entry as in progress.
- dispatchEntry->inProgress = true;
-
- // Publish the event.
- status_t status;
- EventEntry* eventEntry = dispatchEntry->eventEntry;
- switch (eventEntry->type) {
- case EventEntry::TYPE_KEY: {
- KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
-
- // Publish the key event.
- status = connection->inputPublisher.publishKeyEvent(
- keyEntry->deviceId, keyEntry->source,
- dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
- keyEntry->keyCode, keyEntry->scanCode,
- keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,
- keyEntry->eventTime);
+ while (connection->status == Connection::STATUS_NORMAL
+ && !connection->outboundQueue.isEmpty()) {
+ DispatchEntry* dispatchEntry = connection->outboundQueue.head;
- if (status) {
- ALOGE("channel '%s' ~ Could not publish key event, "
- "status=%d", connection->getInputChannelName(), status);
- abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
- return;
+ // Publish the event.
+ status_t status;
+ EventEntry* eventEntry = dispatchEntry->eventEntry;
+ switch (eventEntry->type) {
+ case EventEntry::TYPE_KEY: {
+ KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
+
+ // Publish the key event.
+ status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,
+ keyEntry->deviceId, keyEntry->source,
+ dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
+ keyEntry->keyCode, keyEntry->scanCode,
+ keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,
+ keyEntry->eventTime);
+ break;
}
- break;
- }
- case EventEntry::TYPE_MOTION: {
- MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
+ case EventEntry::TYPE_MOTION: {
+ MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
- // 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.
- // Otherwise, we just start from the first sample of the motion event.
- MotionSample* firstMotionSample = dispatchEntry->headMotionSample;
- if (! firstMotionSample) {
- firstMotionSample = & motionEntry->firstSample;
- }
-
- PointerCoords scaledCoords[MAX_POINTERS];
- const PointerCoords* usingCoords = firstMotionSample->pointerCoords;
-
- // Set the X and Y offset depending on the input source.
- float xOffset, yOffset, scaleFactor;
- if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER
- && !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
- scaleFactor = dispatchEntry->scaleFactor;
- xOffset = dispatchEntry->xOffset * scaleFactor;
- yOffset = dispatchEntry->yOffset * scaleFactor;
- if (scaleFactor != 1.0f) {
- for (size_t i = 0; i < motionEntry->pointerCount; i++) {
- scaledCoords[i] = firstMotionSample->pointerCoords[i];
- scaledCoords[i].scale(scaleFactor);
+ PointerCoords scaledCoords[MAX_POINTERS];
+ const PointerCoords* usingCoords = motionEntry->pointerCoords;
+
+ // Set the X and Y offset depending on the input source.
+ float xOffset, yOffset, scaleFactor;
+ if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
+ && !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
+ scaleFactor = dispatchEntry->scaleFactor;
+ xOffset = dispatchEntry->xOffset * scaleFactor;
+ yOffset = dispatchEntry->yOffset * scaleFactor;
+ if (scaleFactor != 1.0f) {
+ for (size_t i = 0; i < motionEntry->pointerCount; i++) {
+ scaledCoords[i] = motionEntry->pointerCoords[i];
+ scaledCoords[i].scale(scaleFactor);
+ }
+ usingCoords = scaledCoords;
}
- usingCoords = scaledCoords;
- }
- } else {
- xOffset = 0.0f;
- yOffset = 0.0f;
- scaleFactor = 1.0f;
-
- // We don't want the dispatch target to know.
- if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) {
- for (size_t i = 0; i < motionEntry->pointerCount; i++) {
- scaledCoords[i].clear();
+ } else {
+ xOffset = 0.0f;
+ yOffset = 0.0f;
+ scaleFactor = 1.0f;
+
+ // We don't want the dispatch target to know.
+ if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) {
+ for (size_t i = 0; i < motionEntry->pointerCount; i++) {
+ scaledCoords[i].clear();
+ }
+ usingCoords = scaledCoords;
}
- usingCoords = scaledCoords;
}
- }
- // Publish the motion event and the first motion sample.
- 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,
- motionEntry->pointerCount, motionEntry->pointerProperties,
- usingCoords);
+ // Publish the motion event.
+ status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
+ motionEntry->deviceId, motionEntry->source,
+ dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
+ motionEntry->edgeFlags, motionEntry->metaState, motionEntry->buttonState,
+ xOffset, yOffset,
+ motionEntry->xPrecision, motionEntry->yPrecision,
+ motionEntry->downTime, motionEntry->eventTime,
+ motionEntry->pointerCount, motionEntry->pointerProperties,
+ usingCoords);
+ break;
+ }
- if (status) {
- ALOGE("channel '%s' ~ Could not publish motion event, "
- "status=%d", connection->getInputChannelName(), status);
- abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
+ default:
+ ALOG_ASSERT(false);
return;
}
- 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) {
- if (usingCoords == scaledCoords) {
- if (!(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
- for (size_t i = 0; i < motionEntry->pointerCount; i++) {
- scaledCoords[i] = nextMotionSample->pointerCoords[i];
- scaledCoords[i].scale(scaleFactor);
- }
- }
+ // Check the result.
+ if (status) {
+ if (status == WOULD_BLOCK) {
+ if (connection->waitQueue.isEmpty()) {
+ ALOGE("channel '%s' ~ Could not publish event because the pipe is full. "
+ "This is unexpected because the wait queue is empty, so the pipe "
+ "should be empty and we shouldn't have any problems writing an "
+ "event to it, status=%d", connection->getInputChannelName(), status);
+ abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
} else {
- usingCoords = nextMotionSample->pointerCoords;
- }
- status = connection->inputPublisher.appendMotionSample(
- nextMotionSample->eventTime, usingCoords);
- if (status == NO_MEMORY) {
+ // Pipe is full and we are waiting for the app to finish process some events
+ // before sending more events to it.
#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ Shared memory buffer full. Some motion samples will "
- "be sent in the next dispatch cycle.",
+ ALOGD("channel '%s' ~ Could not publish event because the pipe is full, "
+ "waiting for the application to catch up",
connection->getInputChannelName());
#endif
- break;
- }
- if (status != OK) {
- ALOGE("channel '%s' ~ Could not append motion sample "
- "for a reason other than out of memory, status=%d",
- connection->getInputChannelName(), status);
- abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
- return;
+ connection->inputPublisherBlocked = true;
}
+ } else {
+ ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, "
+ "status=%d", connection->getInputChannelName(), status);
+ abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
}
-
- // Remember the next motion sample that we could not dispatch, in case we ran out
- // of space in the shared memory buffer.
- dispatchEntry->tailMotionSample = nextMotionSample;
+ return;
}
- break;
- }
-
- default: {
- ALOG_ASSERT(false);
- }
- }
- // Send the dispatch signal.
- status = connection->inputPublisher.sendDispatchSignal();
- if (status) {
- ALOGE("channel '%s' ~ Could not send dispatch signal, status=%d",
- connection->getInputChannelName(), status);
- abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
- return;
+ // Re-enqueue the event on the wait queue.
+ connection->outboundQueue.dequeue(dispatchEntry);
+ connection->waitQueue.enqueueAtTail(dispatchEntry);
}
-
- // Record information about the newly started dispatch cycle.
- connection->lastEventTime = eventEntry->eventTime;
- connection->lastDispatchTime = currentTime;
-
- // Notify other system components.
- onDispatchCycleStartedLocked(currentTime, connection);
}
void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
- const sp<Connection>& connection, bool handled) {
+ const sp<Connection>& connection, uint32_t seq, bool handled) {
#if DEBUG_DISPATCH_CYCLE
- ALOGD("channel '%s' ~ finishDispatchCycle - %01.1fms since event, "
- "%01.1fms since dispatch, handled=%s",
- connection->getInputChannelName(),
- connection->getEventLatencyMillis(currentTime),
- connection->getDispatchLatencyMillis(currentTime),
- toString(handled));
+ ALOGD("channel '%s' ~ finishDispatchCycle - seq=%u, handled=%s",
+ connection->getInputChannelName(), seq, toString(handled));
#endif
+ connection->inputPublisherBlocked = false;
+
if (connection->status == Connection::STATUS_BROKEN
|| connection->status == Connection::STATUS_ZOMBIE) {
return;
}
- // Reset the publisher since the event has been consumed.
- // We do this now so that the publisher can release some of its internal resources
- // while waiting for the next dispatch cycle to begin.
- status_t status = connection->inputPublisher.reset();
- if (status) {
- ALOGE("channel '%s' ~ Could not reset publisher, status=%d",
- connection->getInputChannelName(), status);
- abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
- return;
- }
-
// Notify other system components and prepare to start the next dispatch cycle.
- onDispatchCycleFinishedLocked(currentTime, connection, handled);
-}
-
-void InputDispatcher::startNextDispatchCycleLocked(nsecs_t currentTime,
- const sp<Connection>& connection) {
- // Start the next dispatch cycle for this connection.
- while (! connection->outboundQueue.isEmpty()) {
- DispatchEntry* dispatchEntry = connection->outboundQueue.head;
- if (dispatchEntry->inProgress) {
- // Finish or resume current event in progress.
- if (dispatchEntry->tailMotionSample) {
- // We have a tail of undispatched motion samples.
- // Reuse the same DispatchEntry and start a new cycle.
- dispatchEntry->inProgress = false;
- dispatchEntry->headMotionSample = dispatchEntry->tailMotionSample;
- dispatchEntry->tailMotionSample = NULL;
- startDispatchCycleLocked(currentTime, connection);
- return;
- }
- // Finished.
- connection->outboundQueue.dequeueAtHead();
- if (dispatchEntry->hasForegroundTarget()) {
- decrementPendingForegroundDispatchesLocked(dispatchEntry->eventEntry);
- }
- delete dispatchEntry;
- } else {
- // If the head is not in progress, then we must have already dequeued the in
- // progress event, which means we actually aborted it.
- // So just start the next event for this connection.
- startDispatchCycleLocked(currentTime, connection);
- return;
- }
- }
-
- // Outbound queue is empty, deactivate the connection.
- deactivateConnectionLocked(connection.get());
+ onDispatchCycleFinishedLocked(currentTime, connection, seq, handled);
}
void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime,
@@ -2382,8 +2007,9 @@ void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime,
connection->getInputChannelName(), toString(notify));
#endif
- // Clear the outbound queue.
- drainOutboundQueueLocked(connection.get());
+ // Clear the dispatch queues.
+ drainDispatchQueueLocked(&connection->outboundQueue);
+ drainDispatchQueueLocked(&connection->waitQueue);
// The connection appears to be unrecoverably broken.
// Ignore already broken or zombie connections.
@@ -2397,33 +2023,35 @@ void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime,
}
}
-void InputDispatcher::drainOutboundQueueLocked(Connection* connection) {
- while (! connection->outboundQueue.isEmpty()) {
- DispatchEntry* dispatchEntry = connection->outboundQueue.dequeueAtHead();
- if (dispatchEntry->hasForegroundTarget()) {
- decrementPendingForegroundDispatchesLocked(dispatchEntry->eventEntry);
- }
- delete dispatchEntry;
+void InputDispatcher::drainDispatchQueueLocked(Queue<DispatchEntry>* queue) {
+ while (!queue->isEmpty()) {
+ DispatchEntry* dispatchEntry = queue->dequeueAtHead();
+ releaseDispatchEntryLocked(dispatchEntry);
}
+}
- deactivateConnectionLocked(connection);
+void InputDispatcher::releaseDispatchEntryLocked(DispatchEntry* dispatchEntry) {
+ if (dispatchEntry->hasForegroundTarget()) {
+ decrementPendingForegroundDispatchesLocked(dispatchEntry->eventEntry);
+ }
+ delete dispatchEntry;
}
-int InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data) {
+int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) {
InputDispatcher* d = static_cast<InputDispatcher*>(data);
{ // acquire lock
AutoMutex _l(d->mLock);
- ssize_t connectionIndex = d->mConnectionsByReceiveFd.indexOfKey(receiveFd);
+ ssize_t connectionIndex = d->mConnectionsByFd.indexOfKey(fd);
if (connectionIndex < 0) {
ALOGE("Received spurious receive callback for unknown input channel. "
- "fd=%d, events=0x%x", receiveFd, events);
+ "fd=%d, events=0x%x", fd, events);
return 0; // remove the callback
}
bool notify;
- sp<Connection> connection = d->mConnectionsByReceiveFd.valueAt(connectionIndex);
+ sp<Connection> connection = d->mConnectionsByFd.valueAt(connectionIndex);
if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) {
if (!(events & ALOOPER_EVENT_INPUT)) {
ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. "
@@ -2431,18 +2059,31 @@ int InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data
return 1;
}
- bool handled = false;
- status_t status = connection->inputPublisher.receiveFinishedSignal(&handled);
- if (!status) {
- nsecs_t currentTime = now();
- d->finishDispatchCycleLocked(currentTime, connection, handled);
+ nsecs_t currentTime = now();
+ bool gotOne = false;
+ status_t status;
+ for (;;) {
+ uint32_t seq;
+ bool handled;
+ status = connection->inputPublisher.receiveFinishedSignal(&seq, &handled);
+ if (status) {
+ break;
+ }
+ d->finishDispatchCycleLocked(currentTime, connection, seq, handled);
+ gotOne = true;
+ }
+ if (gotOne) {
d->runCommandsLockedInterruptible();
- return 1;
+ if (status == WOULD_BLOCK) {
+ return 1;
+ }
}
- ALOGE("channel '%s' ~ Failed to receive finished signal. status=%d",
- connection->getInputChannelName(), status);
- notify = true;
+ notify = status != DEAD_OBJECT || !connection->monitor;
+ if (notify) {
+ ALOGE("channel '%s' ~ Failed to receive finished signal. status=%d",
+ connection->getInputChannelName(), status);
+ }
} else {
// Monitor channels are never explicitly unregistered.
// We do it automatically when the remote endpoint is closed so don't warn
@@ -2462,9 +2103,9 @@ int InputDispatcher::handleReceiveCallback(int receiveFd, int events, void* data
void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked(
const CancelationOptions& options) {
- for (size_t i = 0; i < mConnectionsByReceiveFd.size(); i++) {
+ for (size_t i = 0; i < mConnectionsByFd.size(); i++) {
synthesizeCancelationEventsForConnectionLocked(
- mConnectionsByReceiveFd.valueAt(i), options);
+ mConnectionsByFd.valueAt(i), options);
}
}
@@ -2473,7 +2114,7 @@ void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked(
ssize_t index = getConnectionIndexLocked(channel);
if (index >= 0) {
synthesizeCancelationEventsForConnectionLocked(
- mConnectionsByReceiveFd.valueAt(index), options);
+ mConnectionsByFd.valueAt(index), options);
}
}
@@ -2485,19 +2126,19 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(
nsecs_t currentTime = now();
- mTempCancelationEvents.clear();
+ Vector<EventEntry*> cancelationEvents;
connection->inputState.synthesizeCancelationEvents(currentTime,
- mTempCancelationEvents, options);
+ cancelationEvents, options);
- if (!mTempCancelationEvents.isEmpty()) {
+ if (!cancelationEvents.isEmpty()) {
#if DEBUG_OUTBOUND_EVENT_DETAILS
ALOGD("channel '%s' ~ Synthesized %d cancelation events to bring channel back in sync "
"with reality: %s, mode=%d.",
- connection->getInputChannelName(), mTempCancelationEvents.size(),
+ connection->getInputChannelName(), cancelationEvents.size(),
options.reason, options.mode);
#endif
- for (size_t i = 0; i < mTempCancelationEvents.size(); i++) {
- EventEntry* cancelationEventEntry = mTempCancelationEvents.itemAt(i);
+ for (size_t i = 0; i < cancelationEvents.size(); i++) {
+ EventEntry* cancelationEventEntry = cancelationEvents.itemAt(i);
switch (cancelationEventEntry->type) {
case EventEntry::TYPE_KEY:
logOutboundKeyDetailsLocked("cancel - ",
@@ -2525,14 +2166,12 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(
target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
enqueueDispatchEntryLocked(connection, cancelationEventEntry, // increments ref
- &target, false, InputTarget::FLAG_DISPATCH_AS_IS);
+ &target, InputTarget::FLAG_DISPATCH_AS_IS);
cancelationEventEntry->release();
}
- if (!connection->outboundQueue.head->inProgress) {
- startDispatchCycleLocked(currentTime, connection);
- }
+ startDispatchCycleLocked(currentTime, connection);
}
}
@@ -2556,7 +2195,7 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet
splitPointerIndexMap[splitPointerCount] = originalPointerIndex;
splitPointerProperties[splitPointerCount].copyFrom(pointerProperties);
splitPointerCoords[splitPointerCount].copyFrom(
- originalMotionEntry->firstSample.pointerCoords[originalPointerIndex]);
+ originalMotionEntry->pointerCoords[originalPointerIndex]);
splitPointerCount += 1;
}
}
@@ -2617,18 +2256,6 @@ InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet
originalMotionEntry->downTime,
splitPointerCount, splitPointerProperties, splitPointerCoords);
- for (MotionSample* originalMotionSample = originalMotionEntry->firstSample.next;
- originalMotionSample != NULL; originalMotionSample = originalMotionSample->next) {
- for (uint32_t splitPointerIndex = 0; splitPointerIndex < splitPointerCount;
- splitPointerIndex++) {
- uint32_t originalPointerIndex = splitPointerIndexMap[splitPointerIndex];
- splitPointerCoords[splitPointerIndex].copyFrom(
- originalMotionSample->pointerCoords[originalPointerIndex]);
- }
-
- splitMotionEntry->appendSample(originalMotionSample->eventTime, splitPointerCoords);
- }
-
if (originalMotionEntry->injectionState) {
splitMotionEntry->injectionState = originalMotionEntry->injectionState;
splitMotionEntry->injectionState->refCount += 1;
@@ -2789,163 +2416,6 @@ void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
mLock.lock();
}
- // Attempt batching and streaming of move events.
- if (args->action == AMOTION_EVENT_ACTION_MOVE
- || args->action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
- // BATCHING CASE
- //
- // Try to append a move sample to the tail of the inbound queue for this device.
- // Give up if we encounter a non-move motion event for this device since that
- // means we cannot append any new samples until a new motion event has started.
- for (EventEntry* entry = mInboundQueue.tail; entry; entry = entry->prev) {
- if (entry->type != EventEntry::TYPE_MOTION) {
- // Keep looking for motion events.
- continue;
- }
-
- MotionEntry* motionEntry = static_cast<MotionEntry*>(entry);
- if (motionEntry->deviceId != args->deviceId
- || motionEntry->source != args->source) {
- // Keep looking for this device and source.
- continue;
- }
-
- if (!motionEntry->canAppendSamples(args->action,
- args->pointerCount, args->pointerProperties)) {
- // Last motion event in the queue for this device and source is
- // not compatible for appending new samples. Stop here.
- goto NoBatchingOrStreaming;
- }
-
- // Do the batching magic.
- batchMotionLocked(motionEntry, args->eventTime,
- args->metaState, args->pointerCoords,
- "most recent motion event for this device and source in the inbound queue");
- mLock.unlock();
- return; // done!
- }
-
- // BATCHING ONTO PENDING EVENT CASE
- //
- // Try to append a move sample to the currently pending event, if there is one.
- // We can do this as long as we are still waiting to find the targets for the
- // event. Once the targets are locked-in we can only do streaming.
- if (mPendingEvent
- && (!mPendingEvent->dispatchInProgress || !mCurrentInputTargetsValid)
- && mPendingEvent->type == EventEntry::TYPE_MOTION) {
- MotionEntry* motionEntry = static_cast<MotionEntry*>(mPendingEvent);
- if (motionEntry->deviceId == args->deviceId
- && motionEntry->source == args->source) {
- if (!motionEntry->canAppendSamples(args->action,
- args->pointerCount, args->pointerProperties)) {
- // Pending motion event is for this device and source but it is
- // not compatible for appending new samples. Stop here.
- goto NoBatchingOrStreaming;
- }
-
- // Do the batching magic.
- batchMotionLocked(motionEntry, args->eventTime,
- args->metaState, args->pointerCoords,
- "pending motion event");
- mLock.unlock();
- return; // done!
- }
- }
-
- // STREAMING CASE
- //
- // There is no pending motion event (of any kind) for this device in the inbound queue.
- // Search the outbound queue for the current foreground targets to find a dispatched
- // motion event that is still in progress. If found, then, appen the new sample to
- // that event and push it out to all current targets. The logic in
- // prepareDispatchCycleLocked takes care of the case where some targets may
- // already have consumed the motion event by starting a new dispatch cycle if needed.
- if (mCurrentInputTargetsValid) {
- for (size_t i = 0; i < mCurrentInputTargets.size(); i++) {
- const InputTarget& inputTarget = mCurrentInputTargets[i];
- if ((inputTarget.flags & InputTarget::FLAG_FOREGROUND) == 0) {
- // Skip non-foreground targets. We only want to stream if there is at
- // least one foreground target whose dispatch is still in progress.
- continue;
- }
-
- ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
- if (connectionIndex < 0) {
- // Connection must no longer be valid.
- continue;
- }
-
- sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
- if (connection->outboundQueue.isEmpty()) {
- // This foreground target has an empty outbound queue.
- continue;
- }
-
- DispatchEntry* dispatchEntry = connection->outboundQueue.head;
- if (! dispatchEntry->inProgress
- || dispatchEntry->eventEntry->type != EventEntry::TYPE_MOTION
- || dispatchEntry->isSplit()) {
- // No motion event is being dispatched, or it is being split across
- // windows in which case we cannot stream.
- continue;
- }
-
- MotionEntry* motionEntry = static_cast<MotionEntry*>(
- dispatchEntry->eventEntry);
- if (motionEntry->action != args->action
- || motionEntry->deviceId != args->deviceId
- || motionEntry->source != args->source
- || motionEntry->pointerCount != args->pointerCount
- || motionEntry->isInjected()) {
- // The motion event is not compatible with this move.
- continue;
- }
-
- if (args->action == AMOTION_EVENT_ACTION_HOVER_MOVE) {
- if (mLastHoverWindowHandle == NULL) {
-#if DEBUG_BATCHING
- ALOGD("Not streaming hover move because there is no "
- "last hovered window.");
-#endif
- goto NoBatchingOrStreaming;
- }
-
- sp<InputWindowHandle> hoverWindowHandle = findTouchedWindowAtLocked(
- args->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X),
- args->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));
- if (mLastHoverWindowHandle != hoverWindowHandle) {
-#if DEBUG_BATCHING
- ALOGD("Not streaming hover move because the last hovered window "
- "is '%s' but the currently hovered window is '%s'.",
- mLastHoverWindowHandle->getName().string(),
- hoverWindowHandle != NULL
- ? hoverWindowHandle->getName().string() : "<null>");
-#endif
- goto NoBatchingOrStreaming;
- }
- }
-
- // Hurray! This foreground target is currently dispatching a move event
- // that we can stream onto. Append the motion sample and resume dispatch.
- motionEntry->appendSample(args->eventTime, args->pointerCoords);
-#if DEBUG_BATCHING
- ALOGD("Appended motion sample onto batch for most recently dispatched "
- "motion event for this device and source in the outbound queues. "
- "Attempting to stream the motion sample.");
-#endif
- nsecs_t currentTime = now();
- dispatchEventToCurrentInputTargetsLocked(currentTime, motionEntry,
- true /*resumeWithAppendedMotionSample*/);
-
- runCommandsLockedInterruptible();
- mLock.unlock();
- return; // done!
- }
- }
-
-NoBatchingOrStreaming:;
- }
-
// Just enqueue a new motion event.
MotionEntry* newEntry = new MotionEntry(args->eventTime,
args->deviceId, args->source, policyFlags,
@@ -2962,36 +2432,6 @@ NoBatchingOrStreaming:;
}
}
-void InputDispatcher::batchMotionLocked(MotionEntry* entry, nsecs_t eventTime,
- int32_t metaState, const PointerCoords* pointerCoords, const char* eventDescription) {
- // Combine meta states.
- entry->metaState |= metaState;
-
- // Coalesce this sample if not enough time has elapsed since the last sample was
- // initially appended to the batch.
- MotionSample* lastSample = entry->lastSample;
- long interval = eventTime - lastSample->eventTimeBeforeCoalescing;
- if (interval <= MOTION_SAMPLE_COALESCE_INTERVAL) {
- uint32_t pointerCount = entry->pointerCount;
- for (uint32_t i = 0; i < pointerCount; i++) {
- lastSample->pointerCoords[i].copyFrom(pointerCoords[i]);
- }
- lastSample->eventTime = eventTime;
-#if DEBUG_BATCHING
- ALOGD("Coalesced motion into last sample of batch for %s, events were %0.3f ms apart",
- eventDescription, interval * 0.000001f);
-#endif
- return;
- }
-
- // Append the sample.
- entry->appendSample(eventTime, pointerCoords);
-#if DEBUG_BATCHING
- ALOGD("Appended motion sample onto batch for %s, events were %0.3f ms apart",
- eventDescription, interval * 0.000001f);
-#endif
-}
-
void InputDispatcher::notifySwitch(const NotifySwitchArgs* args) {
#if DEBUG_INBOUND_EVENT_DETAILS
ALOGD("notifySwitch - eventTime=%lld, policyFlags=0x%x, switchCode=%d, switchValue=%d",
@@ -3040,7 +2480,8 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event,
policyFlags |= POLICY_FLAG_TRUSTED;
}
- EventEntry* injectedEntry;
+ EventEntry* firstInjectedEntry;
+ EventEntry* lastInjectedEntry;
switch (event->getType()) {
case AINPUT_EVENT_TYPE_KEY: {
const KeyEvent* keyEvent = static_cast<const KeyEvent*>(event);
@@ -3063,11 +2504,12 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event,
}
mLock.lock();
- injectedEntry = new KeyEntry(keyEvent->getEventTime(),
+ firstInjectedEntry = new KeyEntry(keyEvent->getEventTime(),
keyEvent->getDeviceId(), keyEvent->getSource(),
policyFlags, action, flags,
keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(),
keyEvent->getRepeatCount(), keyEvent->getDownTime());
+ lastInjectedEntry = firstInjectedEntry;
break;
}
@@ -3088,7 +2530,7 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event,
mLock.lock();
const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes();
const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords();
- MotionEntry* motionEntry = new MotionEntry(*sampleEventTimes,
+ firstInjectedEntry = new MotionEntry(*sampleEventTimes,
motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags,
action, motionEvent->getFlags(),
motionEvent->getMetaState(), motionEvent->getButtonState(),
@@ -3096,12 +2538,21 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event,
motionEvent->getXPrecision(), motionEvent->getYPrecision(),
motionEvent->getDownTime(), uint32_t(pointerCount),
pointerProperties, samplePointerCoords);
+ lastInjectedEntry = firstInjectedEntry;
for (size_t i = motionEvent->getHistorySize(); i > 0; i--) {
sampleEventTimes += 1;
samplePointerCoords += pointerCount;
- motionEntry->appendSample(*sampleEventTimes, samplePointerCoords);
+ MotionEntry* nextInjectedEntry = new MotionEntry(*sampleEventTimes,
+ motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags,
+ action, motionEvent->getFlags(),
+ motionEvent->getMetaState(), motionEvent->getButtonState(),
+ motionEvent->getEdgeFlags(),
+ motionEvent->getXPrecision(), motionEvent->getYPrecision(),
+ motionEvent->getDownTime(), uint32_t(pointerCount),
+ pointerProperties, samplePointerCoords);
+ lastInjectedEntry->next = nextInjectedEntry;
+ lastInjectedEntry = nextInjectedEntry;
}
- injectedEntry = motionEntry;
break;
}
@@ -3116,9 +2567,15 @@ int32_t InputDispatcher::injectInputEvent(const InputEvent* event,
}
injectionState->refCount += 1;
- injectedEntry->injectionState = injectionState;
+ lastInjectedEntry->injectionState = injectionState;
+
+ bool needWake = false;
+ for (EventEntry* entry = firstInjectedEntry; entry != NULL; ) {
+ EventEntry* nextEntry = entry->next;
+ needWake |= enqueueInboundEventLocked(entry);
+ entry = nextEntry;
+ }
- bool needWake = enqueueInboundEventLocked(injectedEntry);
mLock.unlock();
if (needWake) {
@@ -3366,13 +2823,13 @@ void InputDispatcher::setFocusedApplication(
if (inputApplicationHandle != NULL && inputApplicationHandle->updateInfo()) {
if (mFocusedApplicationHandle != inputApplicationHandle) {
if (mFocusedApplicationHandle != NULL) {
- resetTargetsLocked();
+ resetANRTimeoutsLocked();
mFocusedApplicationHandle->releaseInfo();
}
mFocusedApplicationHandle = inputApplicationHandle;
}
} else if (mFocusedApplicationHandle != NULL) {
- resetTargetsLocked();
+ resetANRTimeoutsLocked();
mFocusedApplicationHandle->releaseInfo();
mFocusedApplicationHandle.clear();
}
@@ -3495,8 +2952,8 @@ bool InputDispatcher::transferTouchFocus(const sp<InputChannel>& fromChannel,
ssize_t fromConnectionIndex = getConnectionIndexLocked(fromChannel);
ssize_t toConnectionIndex = getConnectionIndexLocked(toChannel);
if (fromConnectionIndex >= 0 && toConnectionIndex >= 0) {
- sp<Connection> fromConnection = mConnectionsByReceiveFd.valueAt(fromConnectionIndex);
- sp<Connection> toConnection = mConnectionsByReceiveFd.valueAt(toConnectionIndex);
+ sp<Connection> fromConnection = mConnectionsByFd.valueAt(fromConnectionIndex);
+ sp<Connection> toConnection = mConnectionsByFd.valueAt(toConnectionIndex);
fromConnection->inputState.copyPointerStateTo(toConnection->inputState);
CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
@@ -3525,7 +2982,7 @@ void InputDispatcher::resetAndDropEverythingLocked(const char* reason) {
resetKeyRepeatLocked();
releasePendingEventLocked();
drainInboundQueueLocked();
- resetTargetsLocked();
+ resetANRTimeoutsLocked();
mTouchState.reset();
mLastHoverWindowHandle.clear();
@@ -3622,20 +3079,6 @@ void InputDispatcher::dumpDispatchStateLocked(String8& dump) {
dump.appendFormat(INDENT "InboundQueue: length=%u\n", mInboundQueue.count());
- if (!mActiveConnections.isEmpty()) {
- dump.append(INDENT "ActiveConnections:\n");
- for (size_t i = 0; i < mActiveConnections.size(); i++) {
- const Connection* connection = mActiveConnections[i];
- dump.appendFormat(INDENT2 "%d: '%s', status=%s, outboundQueueLength=%u, "
- "inputState.isNeutral=%s\n",
- i, connection->getInputChannelName(), connection->getStatusLabel(),
- connection->outboundQueue.count(),
- toString(connection->inputState.isNeutral()));
- }
- } else {
- dump.append(INDENT "ActiveConnections: <none>\n");
- }
-
if (isAppSwitchPendingLocked()) {
dump.appendFormat(INDENT "AppSwitch: pending, due in %01.1fms\n",
(mAppSwitchDueTime - now()) / 1000000.0);
@@ -3661,21 +3104,15 @@ status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChan
}
sp<Connection> connection = new Connection(inputChannel, inputWindowHandle, monitor);
- status_t status = connection->initialize();
- if (status) {
- ALOGE("Failed to initialize input publisher for input channel '%s', status=%d",
- inputChannel->getName().string(), status);
- return status;
- }
- int32_t receiveFd = inputChannel->getReceivePipeFd();
- mConnectionsByReceiveFd.add(receiveFd, connection);
+ int32_t fd = inputChannel->getFd();
+ mConnectionsByFd.add(fd, connection);
if (monitor) {
mMonitoringChannels.push(inputChannel);
}
- mLooper->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
+ mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
runCommandsLockedInterruptible();
} // release lock
@@ -3711,14 +3148,14 @@ status_t InputDispatcher::unregisterInputChannelLocked(const sp<InputChannel>& i
return BAD_VALUE;
}
- sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
- mConnectionsByReceiveFd.removeItemsAt(connectionIndex);
+ sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
+ mConnectionsByFd.removeItemsAt(connectionIndex);
if (connection->monitor) {
removeMonitorChannelLocked(inputChannel);
}
- mLooper->removeFd(inputChannel->getReceivePipeFd());
+ mLooper->removeFd(inputChannel->getFd());
nsecs_t currentTime = now();
abortBrokenDispatchCycleLocked(currentTime, connection, notify);
@@ -3739,9 +3176,9 @@ void InputDispatcher::removeMonitorChannelLocked(const sp<InputChannel>& inputCh
}
ssize_t InputDispatcher::getConnectionIndexLocked(const sp<InputChannel>& inputChannel) {
- ssize_t connectionIndex = mConnectionsByReceiveFd.indexOfKey(inputChannel->getReceivePipeFd());
+ ssize_t connectionIndex = mConnectionsByFd.indexOfKey(inputChannel->getFd());
if (connectionIndex >= 0) {
- sp<Connection> connection = mConnectionsByReceiveFd.valueAt(connectionIndex);
+ sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
if (connection->inputChannel.get() == inputChannel.get()) {
return connectionIndex;
}
@@ -3750,33 +3187,12 @@ ssize_t InputDispatcher::getConnectionIndexLocked(const sp<InputChannel>& inputC
return -1;
}
-void InputDispatcher::activateConnectionLocked(Connection* connection) {
- for (size_t i = 0; i < mActiveConnections.size(); i++) {
- if (mActiveConnections.itemAt(i) == connection) {
- return;
- }
- }
- mActiveConnections.add(connection);
-}
-
-void InputDispatcher::deactivateConnectionLocked(Connection* connection) {
- for (size_t i = 0; i < mActiveConnections.size(); i++) {
- if (mActiveConnections.itemAt(i) == connection) {
- mActiveConnections.removeAt(i);
- return;
- }
- }
-}
-
-void InputDispatcher::onDispatchCycleStartedLocked(
- nsecs_t currentTime, const sp<Connection>& connection) {
-}
-
void InputDispatcher::onDispatchCycleFinishedLocked(
- nsecs_t currentTime, const sp<Connection>& connection, bool handled) {
+ nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled) {
CommandEntry* commandEntry = postCommandLocked(
& InputDispatcher::doDispatchCycleFinishedLockedInterruptible);
commandEntry->connection = connection;
+ commandEntry->seq = seq;
commandEntry->handled = handled;
}
@@ -3870,26 +3286,40 @@ void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(
CommandEntry* commandEntry) {
sp<Connection> connection = commandEntry->connection;
+ uint32_t seq = commandEntry->seq;
bool handled = commandEntry->handled;
- bool skipNext = false;
- if (!connection->outboundQueue.isEmpty()) {
- DispatchEntry* dispatchEntry = connection->outboundQueue.head;
- if (dispatchEntry->inProgress) {
- if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) {
- KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry);
- skipNext = afterKeyEventLockedInterruptible(connection,
- dispatchEntry, keyEntry, handled);
- } else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) {
- MotionEntry* motionEntry = static_cast<MotionEntry*>(dispatchEntry->eventEntry);
- skipNext = afterMotionEventLockedInterruptible(connection,
- dispatchEntry, motionEntry, handled);
+ // Handle post-event policy actions.
+ DispatchEntry* dispatchEntry = connection->findWaitQueueEntry(seq);
+ if (dispatchEntry) {
+ bool restartEvent;
+ if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) {
+ KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry);
+ restartEvent = afterKeyEventLockedInterruptible(connection,
+ dispatchEntry, keyEntry, handled);
+ } else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) {
+ MotionEntry* motionEntry = static_cast<MotionEntry*>(dispatchEntry->eventEntry);
+ restartEvent = afterMotionEventLockedInterruptible(connection,
+ dispatchEntry, motionEntry, handled);
+ } else {
+ restartEvent = false;
+ }
+
+ // Dequeue the event and start the next cycle.
+ // Note that because the lock might have been released, it is possible that the
+ // contents of the wait queue to have been drained, so we need to double-check
+ // a few things.
+ if (dispatchEntry == connection->findWaitQueueEntry(seq)) {
+ connection->waitQueue.dequeue(dispatchEntry);
+ if (restartEvent && connection->status == Connection::STATUS_NORMAL) {
+ connection->outboundQueue.enqueueAtHead(dispatchEntry);
+ } else {
+ releaseDispatchEntryLocked(dispatchEntry);
}
}
- }
- if (!skipNext) {
- startNextDispatchCycleLocked(now(), connection);
+ // Start the next dispatch cycle for this connection.
+ startDispatchCycleLocked(now(), connection);
}
}
@@ -3953,11 +3383,9 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con
if (connection->status != Connection::STATUS_NORMAL) {
connection->inputState.removeFallbackKey(originalKeyCode);
- return true; // skip next cycle
+ return false;
}
- ALOG_ASSERT(connection->outboundQueue.head == dispatchEntry);
-
// Latch the fallback keycode for this key on an initial down.
// The fallback keycode cannot change at any other point in the lifecycle.
if (initialDown) {
@@ -4035,10 +3463,7 @@ bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& con
"originalKeyCode=%d, fallbackKeyCode=%d, fallbackMetaState=%08x",
originalKeyCode, fallbackKeyCode, keyEntry->metaState);
#endif
-
- dispatchEntry->inProgress = false;
- startDispatchCycleLocked(now(), connection);
- return true; // already started next cycle
+ return true; // restart the event
} else {
#if DEBUG_OUTBOUND_EVENT_DETAILS
ALOGD("Unhandled key event: No fallback key.");
@@ -4080,7 +3505,6 @@ void InputDispatcher::dump(String8& dump) {
dumpDispatchStateLocked(dump);
dump.append(INDENT "Configuration:\n");
- dump.appendFormat(INDENT2 "MaxEventsPerSecond: %d\n", mConfig.maxEventsPerSecond);
dump.appendFormat(INDENT2 "KeyRepeatDelay: %0.1fms\n", mConfig.keyRepeatDelay * 0.000001f);
dump.appendFormat(INDENT2 "KeyRepeatTimeout: %0.1fms\n", mConfig.keyRepeatTimeout * 0.000001f);
}
@@ -4204,17 +3628,6 @@ void InputDispatcher::KeyEntry::recycle() {
}
-// --- InputDispatcher::MotionSample ---
-
-InputDispatcher::MotionSample::MotionSample(nsecs_t eventTime,
- const PointerCoords* pointerCoords, uint32_t pointerCount) :
- next(NULL), eventTime(eventTime), eventTimeBeforeCoalescing(eventTime) {
- for (uint32_t i = 0; i < pointerCount; i++) {
- this->pointerCoords[i].copyFrom(pointerCoords[i]);
- }
-}
-
-
// --- InputDispatcher::MotionEntry ---
InputDispatcher::MotionEntry::MotionEntry(nsecs_t eventTime,
@@ -4224,66 +3637,31 @@ InputDispatcher::MotionEntry::MotionEntry(nsecs_t eventTime,
nsecs_t downTime, uint32_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) :
EventEntry(TYPE_MOTION, eventTime, policyFlags),
+ eventTime(eventTime),
deviceId(deviceId), source(source), action(action), flags(flags),
metaState(metaState), buttonState(buttonState), edgeFlags(edgeFlags),
xPrecision(xPrecision), yPrecision(yPrecision),
- downTime(downTime), pointerCount(pointerCount),
- firstSample(eventTime, pointerCoords, pointerCount),
- lastSample(&firstSample) {
+ downTime(downTime), pointerCount(pointerCount) {
for (uint32_t i = 0; i < pointerCount; i++) {
this->pointerProperties[i].copyFrom(pointerProperties[i]);
+ this->pointerCoords[i].copyFrom(pointerCoords[i]);
}
}
InputDispatcher::MotionEntry::~MotionEntry() {
- for (MotionSample* sample = firstSample.next; sample != NULL; ) {
- MotionSample* next = sample->next;
- delete sample;
- sample = next;
- }
-}
-
-uint32_t InputDispatcher::MotionEntry::countSamples() const {
- uint32_t count = 1;
- for (MotionSample* sample = firstSample.next; sample != NULL; sample = sample->next) {
- count += 1;
- }
- return count;
-}
-
-bool InputDispatcher::MotionEntry::canAppendSamples(int32_t action, uint32_t pointerCount,
- const PointerProperties* pointerProperties) const {
- if (this->action != action
- || this->pointerCount != pointerCount
- || this->isInjected()) {
- return false;
- }
- for (uint32_t i = 0; i < pointerCount; i++) {
- if (this->pointerProperties[i] != pointerProperties[i]) {
- return false;
- }
- }
- return true;
-}
-
-void InputDispatcher::MotionEntry::appendSample(
- nsecs_t eventTime, const PointerCoords* pointerCoords) {
- MotionSample* sample = new MotionSample(eventTime, pointerCoords, pointerCount);
-
- lastSample->next = sample;
- lastSample = sample;
}
// --- InputDispatcher::DispatchEntry ---
+volatile int32_t InputDispatcher::DispatchEntry::sNextSeqAtomic;
+
InputDispatcher::DispatchEntry::DispatchEntry(EventEntry* eventEntry,
int32_t targetFlags, float xOffset, float yOffset, float scaleFactor) :
+ seq(nextSeq()),
eventEntry(eventEntry), targetFlags(targetFlags),
xOffset(xOffset), yOffset(yOffset), scaleFactor(scaleFactor),
- inProgress(false),
- resolvedAction(0), resolvedFlags(0),
- headMotionSample(NULL), tailMotionSample(NULL) {
+ resolvedAction(0), resolvedFlags(0) {
eventEntry->refCount += 1;
}
@@ -4291,6 +3669,15 @@ InputDispatcher::DispatchEntry::~DispatchEntry() {
eventEntry->release();
}
+uint32_t InputDispatcher::DispatchEntry::nextSeq() {
+ // Sequence number 0 is reserved and will never be returned.
+ uint32_t seq;
+ do {
+ seq = android_atomic_inc(&sNextSeqAtomic);
+ } while (!seq);
+ return seq;
+}
+
// --- InputDispatcher::InputState ---
@@ -4501,7 +3888,7 @@ void InputDispatcher::InputState::MotionMemento::setPointers(const MotionEntry*
pointerCount = entry->pointerCount;
for (uint32_t i = 0; i < entry->pointerCount; i++) {
pointerProperties[i].copyFrom(entry->pointerProperties[i]);
- pointerCoords[i].copyFrom(entry->lastSample->pointerCoords[i]);
+ pointerCoords[i].copyFrom(entry->pointerCoords[i]);
}
}
@@ -4621,17 +4008,12 @@ InputDispatcher::Connection::Connection(const sp<InputChannel>& inputChannel,
const sp<InputWindowHandle>& inputWindowHandle, bool monitor) :
status(STATUS_NORMAL), inputChannel(inputChannel), inputWindowHandle(inputWindowHandle),
monitor(monitor),
- inputPublisher(inputChannel),
- lastEventTime(LONG_LONG_MAX), lastDispatchTime(LONG_LONG_MAX) {
+ inputPublisher(inputChannel), inputPublisherBlocked(false) {
}
InputDispatcher::Connection::~Connection() {
}
-status_t InputDispatcher::Connection::initialize() {
- return inputPublisher.initialize();
-}
-
const char* InputDispatcher::Connection::getStatusLabel() const {
switch (status) {
case STATUS_NORMAL:
@@ -4648,12 +4030,10 @@ const char* InputDispatcher::Connection::getStatusLabel() const {
}
}
-InputDispatcher::DispatchEntry* InputDispatcher::Connection::findQueuedDispatchEntryForEvent(
- const EventEntry* eventEntry) const {
- for (DispatchEntry* dispatchEntry = outboundQueue.tail; dispatchEntry;
- dispatchEntry = dispatchEntry->prev) {
- if (dispatchEntry->eventEntry == eventEntry) {
- return dispatchEntry;
+InputDispatcher::DispatchEntry* InputDispatcher::Connection::findWaitQueueEntry(uint32_t seq) {
+ for (DispatchEntry* entry = waitQueue.head; entry != NULL; entry = entry->next) {
+ if (entry->seq == seq) {
+ return entry;
}
}
return NULL;
@@ -4663,7 +4043,8 @@ InputDispatcher::DispatchEntry* InputDispatcher::Connection::findQueuedDispatchE
// --- InputDispatcher::CommandEntry ---
InputDispatcher::CommandEntry::CommandEntry(Command command) :
- command(command), eventTime(0), keyEntry(NULL), userActivityEventType(0), handled(false) {
+ command(command), eventTime(0), keyEntry(NULL), userActivityEventType(0),
+ seq(0), handled(false) {
}
InputDispatcher::CommandEntry::~CommandEntry() {
diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h
index a1d42e1bfa8d..5c517f5163c2 100644
--- a/services/input/InputDispatcher.h
+++ b/services/input/InputDispatcher.h
@@ -27,6 +27,7 @@
#include <utils/String8.h>
#include <utils/Looper.h>
#include <utils/BitSet.h>
+#include <cutils/atomic.h>
#include <stddef.h>
#include <unistd.h>
@@ -172,15 +173,9 @@ struct InputDispatcherConfiguration {
// The key repeat inter-key delay.
nsecs_t keyRepeatDelay;
- // The maximum suggested event delivery rate per second.
- // This value is used to throttle motion event movement actions on a per-device
- // basis. It is not intended to be a hard limit.
- int32_t maxEventsPerSecond;
-
InputDispatcherConfiguration() :
keyRepeatTimeout(500 * 1000000LL),
- keyRepeatDelay(50 * 1000000LL),
- maxEventsPerSecond(60) { }
+ keyRepeatDelay(50 * 1000000LL) { }
};
@@ -404,6 +399,9 @@ private:
struct Link {
T* next;
T* prev;
+
+ protected:
+ inline Link() : next(NULL), prev(NULL) { }
};
struct InjectionState {
@@ -496,18 +494,8 @@ private:
virtual ~KeyEntry();
};
- struct MotionSample {
- MotionSample* next;
-
- nsecs_t eventTime; // may be updated during coalescing
- nsecs_t eventTimeBeforeCoalescing; // not updated during coalescing
- PointerCoords pointerCoords[MAX_POINTERS];
-
- MotionSample(nsecs_t eventTime, const PointerCoords* pointerCoords,
- uint32_t pointerCount);
- };
-
struct MotionEntry : EventEntry {
+ nsecs_t eventTime;
int32_t deviceId;
uint32_t source;
int32_t action;
@@ -520,10 +508,7 @@ private:
nsecs_t downTime;
uint32_t pointerCount;
PointerProperties pointerProperties[MAX_POINTERS];
-
- // Linked list of motion samples associated with this motion event.
- MotionSample firstSample;
- MotionSample* lastSample;
+ PointerCoords pointerCoords[MAX_POINTERS];
MotionEntry(nsecs_t eventTime,
int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action,
@@ -532,46 +517,24 @@ private:
nsecs_t downTime, uint32_t pointerCount,
const PointerProperties* pointerProperties, const PointerCoords* pointerCoords);
- uint32_t countSamples() const;
-
- // Checks whether we can append samples, assuming the device id and source are the same.
- bool canAppendSamples(int32_t action, uint32_t pointerCount,
- const PointerProperties* pointerProperties) const;
-
- void appendSample(nsecs_t eventTime, const PointerCoords* pointerCoords);
-
protected:
virtual ~MotionEntry();
};
// Tracks the progress of dispatching a particular event to a particular connection.
struct DispatchEntry : Link<DispatchEntry> {
+ const uint32_t seq; // unique sequence number, never 0
+
EventEntry* eventEntry; // the event to dispatch
int32_t targetFlags;
float xOffset;
float yOffset;
float scaleFactor;
- // 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
- // MotionEntry::firstSample. Otherwise, some samples were dispatched in a previous
- // cycle and this pointer indicates the location of the first remainining sample
- // to dispatch during the current cycle.
- MotionSample* headMotionSample;
- // Pointer to a motion sample to dispatch in the next cycle if the dispatcher was
- // unable to send all motion samples during this cycle. On the next cycle,
- // headMotionSample will be initialized to tailMotionSample and tailMotionSample
- // will be set to NULL.
- MotionSample* tailMotionSample;
-
DispatchEntry(EventEntry* eventEntry,
int32_t targetFlags, float xOffset, float yOffset, float scaleFactor);
~DispatchEntry();
@@ -583,6 +546,11 @@ private:
inline bool isSplit() const {
return targetFlags & InputTarget::FLAG_SPLIT;
}
+
+ private:
+ static volatile int32_t sNextSeqAtomic;
+
+ static uint32_t nextSeq();
};
// A command entry captures state and behavior for an action to be performed in the
@@ -618,6 +586,7 @@ private:
sp<InputApplicationHandle> inputApplicationHandle;
sp<InputWindowHandle> inputWindowHandle;
int32_t userActivityEventType;
+ uint32_t seq;
bool handled;
};
@@ -819,10 +788,17 @@ private:
bool monitor;
InputPublisher inputPublisher;
InputState inputState;
+
+ // True if the socket is full and no further events can be published until
+ // the application consumes some of the input.
+ bool inputPublisherBlocked;
+
+ // Queue of events that need to be published to the connection.
Queue<DispatchEntry> outboundQueue;
- nsecs_t lastEventTime; // the time when the event was originally captured
- nsecs_t lastDispatchTime; // the time when the last event was dispatched
+ // Queue of events that have been published to the connection but that have not
+ // yet received a "finished" response from the application.
+ Queue<DispatchEntry> waitQueue;
explicit Connection(const sp<InputChannel>& inputChannel,
const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
@@ -831,21 +807,7 @@ private:
const char* getStatusLabel() const;
- // Finds a DispatchEntry in the outbound queue associated with the specified event.
- // Returns NULL if not found.
- DispatchEntry* findQueuedDispatchEntryForEvent(const EventEntry* eventEntry) const;
-
- // Gets the time since the current event was originally obtained from the input driver.
- inline double getEventLatencyMillis(nsecs_t currentTime) const {
- return (currentTime - lastEventTime) / 1000000.0;
- }
-
- // Gets the time since the current event entered the outbound dispatch queue.
- inline double getDispatchLatencyMillis(nsecs_t currentTime) const {
- return (currentTime - lastDispatchTime) / 1000000.0;
- }
-
- status_t initialize();
+ DispatchEntry* findWaitQueueEntry(uint32_t seq);
};
enum DropReason {
@@ -870,15 +832,7 @@ private:
Queue<EventEntry> mInboundQueue;
Queue<CommandEntry> mCommandQueue;
- Vector<EventEntry*> mTempCancelationEvents;
-
void dispatchOnceInnerLocked(nsecs_t* nextWakeupTime);
- void dispatchIdleLocked();
-
- // Batches a new sample onto a motion entry.
- // Assumes that the we have already checked that we can append samples.
- void batchMotionLocked(MotionEntry* entry, nsecs_t eventTime, int32_t metaState,
- const PointerCoords* pointerCoords, const char* eventDescription);
// Enqueues an inbound event. Returns true if mLooper->wake() should be called.
bool enqueueInboundEventLocked(EventEntry* entry);
@@ -904,17 +858,11 @@ private:
sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t x, int32_t y);
- // All registered connections mapped by receive pipe file descriptor.
- KeyedVector<int, sp<Connection> > mConnectionsByReceiveFd;
+ // All registered connections mapped by channel file descriptor.
+ KeyedVector<int, sp<Connection> > mConnectionsByFd;
ssize_t getConnectionIndexLocked(const sp<InputChannel>& inputChannel);
- // Active connections are connections that have a non-empty outbound queue.
- // We don't use a ref-counted pointer here because we explicitly abort connections
- // during unregistration which causes the connection's outbound queue to be cleared
- // and the connection itself to be deactivated.
- Vector<Connection*> mActiveConnections;
-
// Input channels that will receive a copy of all input events.
Vector<sp<InputChannel> > mMonitoringChannels;
@@ -927,17 +875,6 @@ private:
void incrementPendingForegroundDispatchesLocked(EventEntry* entry);
void decrementPendingForegroundDispatchesLocked(EventEntry* entry);
- // Throttling state.
- struct ThrottleState {
- nsecs_t minTimeBetweenEvents;
-
- nsecs_t lastEventTime;
- int32_t lastDeviceId;
- uint32_t lastSource;
-
- uint32_t originalSampleCount; // only collected during debugging
- } mThrottleState;
-
// Key repeat tracking.
struct KeyRepeatState {
KeyEntry* lastKeyEntry; // or null if no repeat
@@ -1010,16 +947,13 @@ private:
bool dispatchMotionLocked(
nsecs_t currentTime, MotionEntry* entry,
DropReason* dropReason, nsecs_t* nextWakeupTime);
- void dispatchEventToCurrentInputTargetsLocked(
- nsecs_t currentTime, EventEntry* entry, bool resumeWithAppendedMotionSample);
+ void dispatchEventLocked(nsecs_t currentTime, EventEntry* entry,
+ const Vector<InputTarget>& inputTargets);
void logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry);
void logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry);
- // The input targets that were most recently identified for dispatch.
- bool mCurrentInputTargetsValid; // false while targets are being recomputed
- Vector<InputTarget> mCurrentInputTargets;
-
+ // Keeping track of ANR timeouts.
enum InputTargetWaitCause {
INPUT_TARGET_WAIT_CAUSE_NONE,
INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY,
@@ -1036,8 +970,6 @@ private:
sp<InputWindowHandle> mLastHoverWindowHandle;
// Finding targets for input events.
- void resetTargetsLocked();
- void commitTargetsLocked();
int32_t handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry,
const sp<InputApplicationHandle>& applicationHandle,
const sp<InputWindowHandle>& windowHandle,
@@ -1048,20 +980,22 @@ private:
void resetANRTimeoutsLocked();
int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry,
- nsecs_t* nextWakeupTime);
+ Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime);
int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry,
- nsecs_t* nextWakeupTime, bool* outConflictingPointerActions,
- const MotionSample** outSplitBatchAfterSample);
+ Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime,
+ bool* outConflictingPointerActions);
void addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
- int32_t targetFlags, BitSet32 pointerIds);
- void addMonitoringTargetsLocked();
+ int32_t targetFlags, BitSet32 pointerIds, Vector<InputTarget>& inputTargets);
+ void addMonitoringTargetsLocked(Vector<InputTarget>& inputTargets);
+
void pokeUserActivityLocked(const EventEntry* eventEntry);
bool checkInjectionPermission(const sp<InputWindowHandle>& windowHandle,
const InjectionState* injectionState);
bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle,
int32_t x, int32_t y) const;
- bool isWindowFinishedWithPreviousInputLocked(const sp<InputWindowHandle>& windowHandle);
+ bool isWindowReadyForMoreInputLocked(nsecs_t currentTime,
+ const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry);
String8 getApplicationWindowLabelLocked(const sp<InputApplicationHandle>& applicationHandle,
const sp<InputWindowHandle>& windowHandle);
@@ -1070,22 +1004,19 @@ private:
// with the mutex held makes it easier to ensure that connection invariants are maintained.
// If needed, the methods post commands to run later once the critical bits are done.
void prepareDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
- EventEntry* eventEntry, const InputTarget* inputTarget,
- bool resumeWithAppendedMotionSample);
+ EventEntry* eventEntry, const InputTarget* inputTarget);
void enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp<Connection>& connection,
- EventEntry* eventEntry, const InputTarget* inputTarget,
- bool resumeWithAppendedMotionSample);
+ EventEntry* eventEntry, const InputTarget* inputTarget);
void enqueueDispatchEntryLocked(const sp<Connection>& connection,
- EventEntry* eventEntry, const InputTarget* inputTarget,
- bool resumeWithAppendedMotionSample, int32_t dispatchMode);
+ EventEntry* eventEntry, const InputTarget* inputTarget, int32_t dispatchMode);
void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
- bool handled);
- void startNextDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection);
+ uint32_t seq, bool handled);
void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
bool notify);
- void drainOutboundQueueLocked(Connection* connection);
- static int handleReceiveCallback(int receiveFd, int events, void* data);
+ void drainDispatchQueueLocked(Queue<DispatchEntry>* queue);
+ void releaseDispatchEntryLocked(DispatchEntry* dispatchEntry);
+ static int handleReceiveCallback(int fd, int events, void* data);
void synthesizeCancelationEventsForAllConnectionsLocked(
const CancelationOptions& options);
@@ -1113,10 +1044,8 @@ private:
void deactivateConnectionLocked(Connection* connection);
// Interesting events that we might like to log or tell the framework about.
- void onDispatchCycleStartedLocked(
- nsecs_t currentTime, const sp<Connection>& connection);
void onDispatchCycleFinishedLocked(
- nsecs_t currentTime, const sp<Connection>& connection, bool handled);
+ nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled);
void onDispatchCycleBrokenLocked(
nsecs_t currentTime, const sp<Connection>& connection);
void onANRLocked(
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java
index 250386fa5c3d..41ede2e4b608 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/java/com/android/server/AppWidgetServiceImpl.java
@@ -573,12 +573,13 @@ class AppWidgetServiceImpl {
mBoundRemoteViewsServices.remove(key);
}
+ int userId = UserId.getUserId(id.provider.uid);
// Bind to the RemoteViewsService (which will trigger a callback to the
// RemoteViewsAdapter.onServiceConnected())
final long token = Binder.clearCallingIdentity();
try {
conn = new ServiceConnectionProxy(key, connection);
- mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE);
+ mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE, userId);
mBoundRemoteViewsServices.put(key, conn);
} finally {
Binder.restoreCallingIdentity(token);
@@ -638,11 +639,11 @@ class AppWidgetServiceImpl {
// Check if we need to destroy any services (if no other app widgets are
// referencing the same service)
- decrementAppWidgetServiceRefCount(appWidgetId);
+ decrementAppWidgetServiceRefCount(id);
}
// Destroys the cached factory on the RemoteViewsService's side related to the specified intent
- private void destroyRemoteViewsService(final Intent intent) {
+ private void destroyRemoteViewsService(final Intent intent, AppWidgetId id) {
final ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
@@ -663,11 +664,12 @@ class AppWidgetServiceImpl {
}
};
+ int userId = UserId.getUserId(id.provider.uid);
// Bind to the service and remove the static intent->factory mapping in the
// RemoteViewsService.
final long token = Binder.clearCallingIdentity();
try {
- mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE);
+ mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE, userId);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -687,16 +689,16 @@ class AppWidgetServiceImpl {
// Subtracts from the ref-count for a given RemoteViewsService intent, prompting a delete if
// the ref-count reaches zero.
- private void decrementAppWidgetServiceRefCount(int appWidgetId) {
+ private void decrementAppWidgetServiceRefCount(AppWidgetId id) {
Iterator<FilterComparison> it = mRemoteViewsServicesAppWidgets.keySet().iterator();
while (it.hasNext()) {
final FilterComparison key = it.next();
final HashSet<Integer> ids = mRemoteViewsServicesAppWidgets.get(key);
- if (ids.remove(appWidgetId)) {
+ if (ids.remove(id.appWidgetId)) {
// If we have removed the last app widget referencing this service, then we
// should destroy it and remove it from this set
if (ids.isEmpty()) {
- destroyRemoteViewsService(key.getIntent());
+ destroyRemoteViewsService(key.getIntent(), id);
it.remove();
}
}
@@ -888,10 +890,11 @@ class AppWidgetServiceImpl {
}
};
+ int userId = UserId.getUserId(id.provider.uid);
// Bind to the service and call onDataSetChanged()
final long token = Binder.clearCallingIdentity();
try {
- mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE);
+ mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE, userId);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1343,7 +1346,6 @@ class AppWidgetServiceImpl {
void readStateFromFileLocked(FileInputStream stream) {
boolean success = false;
-
try {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(stream, null);
@@ -1475,7 +1477,7 @@ class AppWidgetServiceImpl {
}
AtomicFile savedStateFile() {
- int userId = Binder.getOrigCallingUser();
+ int userId = UserId.getCallingUserId();
File dir = new File("/data/system/users/" + userId);
File settingsFile = new File(dir, SETTINGS_FILENAME);
if (!dir.exists()) {
diff --git a/services/java/com/android/server/NetworkTimeUpdateService.java b/services/java/com/android/server/NetworkTimeUpdateService.java
index a7d19929133b..1ff914f2afd2 100644
--- a/services/java/com/android/server/NetworkTimeUpdateService.java
+++ b/services/java/com/android/server/NetworkTimeUpdateService.java
@@ -55,7 +55,7 @@ public class NetworkTimeUpdateService {
private static final int EVENT_AUTO_TIME_CHANGED = 1;
private static final int EVENT_POLL_NETWORK_TIME = 2;
- private static final int EVENT_WIFI_CONNECTED = 3;
+ private static final int EVENT_NETWORK_CONNECTED = 3;
/** Normal polling frequency */
private static final long POLLING_INTERVAL_MS = 24L * 60 * 60 * 1000; // 24 hrs
@@ -240,8 +240,9 @@ public class NetworkTimeUpdateService {
if (netInfo != null) {
// Verify that it's a WIFI connection
if (netInfo.getState() == NetworkInfo.State.CONNECTED &&
- netInfo.getType() == ConnectivityManager.TYPE_WIFI ) {
- mHandler.obtainMessage(EVENT_WIFI_CONNECTED).sendToTarget();
+ (netInfo.getType() == ConnectivityManager.TYPE_WIFI ||
+ netInfo.getType() == ConnectivityManager.TYPE_ETHERNET) ) {
+ mHandler.obtainMessage(EVENT_NETWORK_CONNECTED).sendToTarget();
}
}
}
@@ -260,7 +261,7 @@ public class NetworkTimeUpdateService {
switch (msg.what) {
case EVENT_AUTO_TIME_CHANGED:
case EVENT_POLL_NETWORK_TIME:
- case EVENT_WIFI_CONNECTED:
+ case EVENT_NETWORK_CONNECTED:
onPollNetworkTime(msg.what);
break;
}
diff --git a/services/java/com/android/server/SystemBackupAgent.java b/services/java/com/android/server/SystemBackupAgent.java
index da97089b72d2..a7a583c918c7 100644
--- a/services/java/com/android/server/SystemBackupAgent.java
+++ b/services/java/com/android/server/SystemBackupAgent.java
@@ -44,12 +44,16 @@ public class SystemBackupAgent extends BackupAgentHelper {
private static final String WALLPAPER_IMAGE_FILENAME = "wallpaper";
private static final String WALLPAPER_INFO_FILENAME = "wallpaper_info.xml";
- private static final String WALLPAPER_IMAGE_DIR = "/data/data/com.android.settings/files";
- private static final String WALLPAPER_IMAGE = WALLPAPER_IMAGE_DIR + "/" + WALLPAPER_IMAGE_FILENAME;
-
- private static final String WALLPAPER_INFO_DIR = "/data/system";
- private static final String WALLPAPER_INFO = WALLPAPER_INFO_DIR + "/" + WALLPAPER_INFO_FILENAME;
+ // TODO: Will need to change if backing up non-primary user's wallpaper
+ private static final String WALLPAPER_IMAGE_DIR = "/data/system/users/0";
+ private static final String WALLPAPER_IMAGE = WallpaperBackupHelper.WALLPAPER_IMAGE;
+ // TODO: Will need to change if backing up non-primary user's wallpaper
+ private static final String WALLPAPER_INFO_DIR = "/data/system/users/0";
+ private static final String WALLPAPER_INFO = WallpaperBackupHelper.WALLPAPER_INFO;
+ // Use old keys to keep legacy data compatibility and avoid writing two wallpapers
+ private static final String WALLPAPER_IMAGE_KEY = WallpaperBackupHelper.WALLPAPER_IMAGE_KEY;
+ private static final String WALLPAPER_INFO_KEY = WallpaperBackupHelper.WALLPAPER_INFO_KEY;
@Override
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
@@ -58,13 +62,15 @@ public class SystemBackupAgent extends BackupAgentHelper {
WallpaperManagerService wallpaper = (WallpaperManagerService)ServiceManager.getService(
Context.WALLPAPER_SERVICE);
String[] files = new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO };
- if (wallpaper != null && wallpaper.mName != null && wallpaper.mName.length() > 0) {
+ String[] keys = new String[] { WALLPAPER_IMAGE_KEY, WALLPAPER_INFO_KEY };
+ if (wallpaper != null && wallpaper.getName() != null && wallpaper.getName().length() > 0) {
// When the wallpaper has a name, back up the info by itself.
// TODO: Don't rely on the innards of the service object like this!
// TODO: Send a delete for any stored wallpaper image in this case?
files = new String[] { WALLPAPER_INFO };
+ keys = new String[] { WALLPAPER_INFO_KEY };
}
- addHelper("wallpaper", new WallpaperBackupHelper(SystemBackupAgent.this, files));
+ addHelper("wallpaper", new WallpaperBackupHelper(SystemBackupAgent.this, files, keys));
super.onBackup(oldState, data, newState);
}
@@ -90,9 +96,11 @@ public class SystemBackupAgent extends BackupAgentHelper {
throws IOException {
// On restore, we also support a previous data schema "system_files"
addHelper("wallpaper", new WallpaperBackupHelper(SystemBackupAgent.this,
- new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO }));
+ new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO },
+ new String[] { WALLPAPER_IMAGE_KEY, WALLPAPER_INFO_KEY} ));
addHelper("system_files", new WallpaperBackupHelper(SystemBackupAgent.this,
- new String[] { WALLPAPER_IMAGE }));
+ new String[] { WALLPAPER_IMAGE },
+ new String[] { WALLPAPER_IMAGE_KEY} ));
try {
super.onRestore(data, appVersionCode, newState);
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index 4925a4e46e51..8ee12bc5c42e 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -24,6 +24,7 @@ import android.app.IWallpaperManagerCallback;
import android.app.PendingIntent;
import android.app.WallpaperInfo;
import android.app.backup.BackupManager;
+import android.app.backup.WallpaperBackupHelper;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -43,11 +44,13 @@ import android.os.ParcelFileDescriptor;
import android.os.RemoteCallbackList;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.UserId;
import android.service.wallpaper.IWallpaperConnection;
import android.service.wallpaper.IWallpaperEngine;
import android.service.wallpaper.IWallpaperService;
import android.service.wallpaper.WallpaperService;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.Xml;
import android.view.Display;
import android.view.IWindowManager;
@@ -70,6 +73,7 @@ import org.xmlpull.v1.XmlSerializer;
import com.android.internal.content.PackageMonitor;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
+import com.android.server.am.ActivityManagerService;
class WallpaperManagerService extends IWallpaperManager.Stub {
static final String TAG = "WallpaperService";
@@ -83,17 +87,9 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
*/
static final long MIN_WALLPAPER_CRASH_TIME = 10000;
- static final File WALLPAPER_DIR = new File(
- "/data/data/com.android.settings/files");
+ static final File WALLPAPER_BASE_DIR = new File("/data/system/users");
static final String WALLPAPER = "wallpaper";
- static final File WALLPAPER_FILE = new File(WALLPAPER_DIR, WALLPAPER);
-
- /**
- * List of callbacks registered they should each be notified
- * when the wallpaper is changed.
- */
- private final RemoteCallbackList<IWallpaperManagerCallback> mCallbacks
- = new RemoteCallbackList<IWallpaperManagerCallback>();
+ static final String WALLPAPER_INFO = "wallpaper_info.xml";
/**
* Observes the wallpaper for changes and notifies all IWallpaperServiceCallbacks
@@ -101,97 +97,135 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
* wallpaper set and is created for the first time. The CLOSE_WRITE is triggered
* everytime the wallpaper is changed.
*/
- private final FileObserver mWallpaperObserver = new FileObserver(
- WALLPAPER_DIR.getAbsolutePath(), CLOSE_WRITE | DELETE | DELETE_SELF) {
- @Override
- public void onEvent(int event, String path) {
- if (path == null) {
- return;
- }
- synchronized (mLock) {
- // changing the wallpaper means we'll need to back up the new one
- long origId = Binder.clearCallingIdentity();
- BackupManager bm = new BackupManager(mContext);
- bm.dataChanged();
- Binder.restoreCallingIdentity(origId);
-
- File changedFile = new File(WALLPAPER_DIR, path);
- if (WALLPAPER_FILE.equals(changedFile)) {
- notifyCallbacksLocked();
- if (mWallpaperComponent == null || event != CLOSE_WRITE
- || mImageWallpaperPending) {
- if (event == CLOSE_WRITE) {
- mImageWallpaperPending = false;
- }
- bindWallpaperComponentLocked(mImageWallpaperComponent,
- true, false);
- saveSettingsLocked();
- }
+ private class WallpaperObserver extends FileObserver {
+
+ final WallpaperData mWallpaper;
+ final File mWallpaperDir;
+ final File mWallpaperFile;
+
+ public WallpaperObserver(WallpaperData wallpaper) {
+ super(getWallpaperDir(wallpaper.userId).getAbsolutePath(),
+ CLOSE_WRITE | DELETE | DELETE_SELF);
+ mWallpaperDir = getWallpaperDir(wallpaper.userId);
+ mWallpaper = wallpaper;
+ mWallpaperFile = new File(mWallpaperDir, WALLPAPER);
+ }
+
+ @Override
+ public void onEvent(int event, String path) {
+ if (path == null) {
+ return;
+ }
+ synchronized (mLock) {
+ // changing the wallpaper means we'll need to back up the new one
+ long origId = Binder.clearCallingIdentity();
+ BackupManager bm = new BackupManager(mContext);
+ bm.dataChanged();
+ Binder.restoreCallingIdentity(origId);
+
+ File changedFile = new File(mWallpaperDir, path);
+ if (mWallpaperFile.equals(changedFile)) {
+ notifyCallbacksLocked(mWallpaper);
+ if (mWallpaper.wallpaperComponent == null || event != CLOSE_WRITE
+ || mWallpaper.imageWallpaperPending) {
+ if (event == CLOSE_WRITE) {
+ mWallpaper.imageWallpaperPending = false;
}
+ bindWallpaperComponentLocked(mWallpaper.imageWallpaperComponent, true,
+ false, mWallpaper);
+ saveSettingsLocked(mWallpaper);
}
}
- };
-
+ }
+ }
+ }
+
final Context mContext;
final IWindowManager mIWindowManager;
final MyPackageMonitor mMonitor;
+ WallpaperData mLastWallpaper;
- int mWidth = -1;
- int mHeight = -1;
+ SparseArray<WallpaperData> mWallpaperMap = new SparseArray<WallpaperData>();
- /**
- * Client is currently writing a new image wallpaper.
- */
- boolean mImageWallpaperPending;
+ int mCurrentUserId;
+
+ static class WallpaperData {
+
+ int userId;
+
+ File wallpaperFile;
+
+ /**
+ * Client is currently writing a new image wallpaper.
+ */
+ boolean imageWallpaperPending;
+
+ /**
+ * Resource name if using a picture from the wallpaper gallery
+ */
+ String name = "";
+
+ /**
+ * The component name of the currently set live wallpaper.
+ */
+ ComponentName wallpaperComponent;
+
+ /**
+ * The component name of the wallpaper that should be set next.
+ */
+ ComponentName nextWallpaperComponent;
+
+ /**
+ * Name of the component used to display bitmap wallpapers from either the gallery or
+ * built-in wallpapers.
+ */
+ ComponentName imageWallpaperComponent = new ComponentName("com.android.systemui",
+ "com.android.systemui.ImageWallpaper");
+
+ WallpaperConnection connection;
+ long lastDiedTime;
+ boolean wallpaperUpdating;
+ WallpaperObserver wallpaperObserver;
+
+ /**
+ * List of callbacks registered they should each be notified when the wallpaper is changed.
+ */
+ private RemoteCallbackList<IWallpaperManagerCallback> callbacks
+ = new RemoteCallbackList<IWallpaperManagerCallback>();
+
+ int width = -1;
+ int height = -1;
+
+ WallpaperData(int userId) {
+ this.userId = userId;
+ wallpaperFile = new File(getWallpaperDir(userId), WALLPAPER);
+ }
+ }
- /**
- * Resource name if using a picture from the wallpaper gallery
- */
- String mName = "";
-
- /**
- * The component name of the currently set live wallpaper.
- */
- ComponentName mWallpaperComponent;
-
- /**
- * The component name of the wallpaper that should be set next.
- */
- ComponentName mNextWallpaperComponent;
-
- /**
- * Name of the component used to display bitmap wallpapers from either the gallery or
- * built-in wallpapers.
- */
- ComponentName mImageWallpaperComponent = new ComponentName("com.android.systemui",
- "com.android.systemui.ImageWallpaper");
-
- WallpaperConnection mWallpaperConnection;
- long mLastDiedTime;
- boolean mWallpaperUpdating;
-
class WallpaperConnection extends IWallpaperConnection.Stub
implements ServiceConnection {
final WallpaperInfo mInfo;
final Binder mToken = new Binder();
IWallpaperService mService;
IWallpaperEngine mEngine;
+ WallpaperData mWallpaper;
- public WallpaperConnection(WallpaperInfo info) {
+ public WallpaperConnection(WallpaperInfo info, WallpaperData wallpaper) {
mInfo = info;
+ mWallpaper = wallpaper;
}
public void onServiceConnected(ComponentName name, IBinder service) {
synchronized (mLock) {
- if (mWallpaperConnection == this) {
- mLastDiedTime = SystemClock.uptimeMillis();
+ if (mWallpaper.connection == this) {
+ mWallpaper.lastDiedTime = SystemClock.uptimeMillis();
mService = IWallpaperService.Stub.asInterface(service);
- attachServiceLocked(this);
+ attachServiceLocked(this, mWallpaper);
// XXX should probably do saveSettingsLocked() later
// when we have an engine, but I'm not sure about
// locking there and anyway we always need to be able to
// recover if there is something wrong.
- saveSettingsLocked();
+ saveSettingsLocked(mWallpaper);
}
}
}
@@ -200,43 +234,50 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
synchronized (mLock) {
mService = null;
mEngine = null;
- if (mWallpaperConnection == this) {
- Slog.w(TAG, "Wallpaper service gone: " + mWallpaperComponent);
- if (!mWallpaperUpdating && (mLastDiedTime+MIN_WALLPAPER_CRASH_TIME)
- > SystemClock.uptimeMillis()) {
+ if (mWallpaper.connection == this) {
+ Slog.w(TAG, "Wallpaper service gone: " + mWallpaper.wallpaperComponent);
+ if (!mWallpaper.wallpaperUpdating
+ && (mWallpaper.lastDiedTime + MIN_WALLPAPER_CRASH_TIME)
+ > SystemClock.uptimeMillis()
+ && mWallpaper.userId == mCurrentUserId) {
Slog.w(TAG, "Reverting to built-in wallpaper!");
- clearWallpaperLocked(true);
+ clearWallpaperLocked(true, mWallpaper.userId);
}
}
}
}
-
+
public void attachEngine(IWallpaperEngine engine) {
mEngine = engine;
}
-
+
public ParcelFileDescriptor setWallpaper(String name) {
synchronized (mLock) {
- if (mWallpaperConnection == this) {
- return updateWallpaperBitmapLocked(name);
+ if (mWallpaper.connection == this) {
+ return updateWallpaperBitmapLocked(name, mWallpaper);
}
return null;
}
}
}
-
+
class MyPackageMonitor extends PackageMonitor {
@Override
public void onPackageUpdateFinished(String packageName, int uid) {
synchronized (mLock) {
- if (mWallpaperComponent != null &&
- mWallpaperComponent.getPackageName().equals(packageName)) {
- mWallpaperUpdating = false;
- ComponentName comp = mWallpaperComponent;
- clearWallpaperComponentLocked();
- if (!bindWallpaperComponentLocked(comp, false, false)) {
- Slog.w(TAG, "Wallpaper no longer available; reverting to default");
- clearWallpaperLocked(false);
+ for (int i = 0; i < mWallpaperMap.size(); i++) {
+ WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+ if (wallpaper.wallpaperComponent != null
+ && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
+ wallpaper.wallpaperUpdating = false;
+ ComponentName comp = wallpaper.wallpaperComponent;
+ clearWallpaperComponentLocked(wallpaper);
+ // Do this only for the current user's wallpaper
+ if (wallpaper.userId == mCurrentUserId
+ && !bindWallpaperComponentLocked(comp, false, false, wallpaper)) {
+ Slog.w(TAG, "Wallpaper no longer available; reverting to default");
+ clearWallpaperLocked(false, wallpaper.userId);
+ }
}
}
}
@@ -245,72 +286,91 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
@Override
public void onPackageModified(String packageName) {
synchronized (mLock) {
- if (mWallpaperComponent == null ||
- !mWallpaperComponent.getPackageName().equals(packageName)) {
- return;
+ for (int i = 0; i < mWallpaperMap.size(); i++) {
+ WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+ if (wallpaper.wallpaperComponent == null
+ || !wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
+ continue;
+ }
+ doPackagesChanged(true, wallpaper);
}
}
- doPackagesChanged(true);
}
@Override
public void onPackageUpdateStarted(String packageName, int uid) {
synchronized (mLock) {
- if (mWallpaperComponent != null &&
- mWallpaperComponent.getPackageName().equals(packageName)) {
- mWallpaperUpdating = true;
+ for (int i = 0; i < mWallpaperMap.size(); i++) {
+ WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+ if (wallpaper.wallpaperComponent != null
+ && wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
+ wallpaper.wallpaperUpdating = true;
+ }
}
}
}
@Override
public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
- return doPackagesChanged(doit);
+ boolean changed = false;
+ for (int i = 0; i < mWallpaperMap.size(); i++) {
+ WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+ boolean res = doPackagesChanged(doit, wallpaper);
+ changed |= res;
+ }
+ return changed;
}
@Override
public void onSomePackagesChanged() {
- doPackagesChanged(true);
+ for (int i = 0; i < mWallpaperMap.size(); i++) {
+ WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+ doPackagesChanged(true, wallpaper);
+ }
}
-
- boolean doPackagesChanged(boolean doit) {
+
+ boolean doPackagesChanged(boolean doit, WallpaperData wallpaper) {
boolean changed = false;
synchronized (mLock) {
- if (mWallpaperComponent != null) {
- int change = isPackageDisappearing(mWallpaperComponent.getPackageName());
+ if (wallpaper.wallpaperComponent != null) {
+ int change = isPackageDisappearing(wallpaper.wallpaperComponent
+ .getPackageName());
if (change == PACKAGE_PERMANENT_CHANGE
|| change == PACKAGE_TEMPORARY_CHANGE) {
changed = true;
if (doit) {
- Slog.w(TAG, "Wallpaper uninstalled, removing: " + mWallpaperComponent);
- clearWallpaperLocked(false);
+ Slog.w(TAG, "Wallpaper uninstalled, removing: "
+ + wallpaper.wallpaperComponent);
+ clearWallpaperLocked(false, wallpaper.userId);
}
}
}
- if (mNextWallpaperComponent != null) {
- int change = isPackageDisappearing(mNextWallpaperComponent.getPackageName());
+ if (wallpaper.nextWallpaperComponent != null) {
+ int change = isPackageDisappearing(wallpaper.nextWallpaperComponent
+ .getPackageName());
if (change == PACKAGE_PERMANENT_CHANGE
|| change == PACKAGE_TEMPORARY_CHANGE) {
- mNextWallpaperComponent = null;
+ wallpaper.nextWallpaperComponent = null;
}
}
- if (mWallpaperComponent != null
- && isPackageModified(mWallpaperComponent.getPackageName())) {
+ if (wallpaper.wallpaperComponent != null
+ && isPackageModified(wallpaper.wallpaperComponent.getPackageName())) {
try {
mContext.getPackageManager().getServiceInfo(
- mWallpaperComponent, 0);
+ wallpaper.wallpaperComponent, 0);
} catch (NameNotFoundException e) {
- Slog.w(TAG, "Wallpaper component gone, removing: " + mWallpaperComponent);
- clearWallpaperLocked(false);
+ Slog.w(TAG, "Wallpaper component gone, removing: "
+ + wallpaper.wallpaperComponent);
+ clearWallpaperLocked(false, wallpaper.userId);
}
}
- if (mNextWallpaperComponent != null
- && isPackageModified(mNextWallpaperComponent.getPackageName())) {
+ if (wallpaper.nextWallpaperComponent != null
+ && isPackageModified(wallpaper.nextWallpaperComponent.getPackageName())) {
try {
mContext.getPackageManager().getServiceInfo(
- mNextWallpaperComponent, 0);
+ wallpaper.nextWallpaperComponent, 0);
} catch (NameNotFoundException e) {
- mNextWallpaperComponent = null;
+ wallpaper.nextWallpaperComponent = null;
}
}
}
@@ -325,51 +385,110 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
ServiceManager.getService(Context.WINDOW_SERVICE));
mMonitor = new MyPackageMonitor();
mMonitor.register(context, true);
- WALLPAPER_DIR.mkdirs();
- loadSettingsLocked();
- mWallpaperObserver.startWatching();
+ WALLPAPER_BASE_DIR.mkdirs();
+ loadSettingsLocked(0);
}
+ private static File getWallpaperDir(int userId) {
+ return new File(WALLPAPER_BASE_DIR + "/" + userId);
+ }
+
@Override
protected void finalize() throws Throwable {
super.finalize();
- mWallpaperObserver.stopWatching();
+ for (int i = 0; i < mWallpaperMap.size(); i++) {
+ WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+ wallpaper.wallpaperObserver.stopWatching();
+ }
}
public void systemReady() {
if (DEBUG) Slog.v(TAG, "systemReady");
+ WallpaperData wallpaper = mWallpaperMap.get(0);
+ switchWallpaper(wallpaper);
+ wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
+ wallpaper.wallpaperObserver.startWatching();
+ ActivityManagerService ams = (ActivityManagerService) ServiceManager
+ .getService(Context.ACTIVITY_SERVICE);
+ ams.addUserListener(new ActivityManagerService.UserListener() {
+
+ @Override
+ public void onUserChanged(int userId) {
+ switchUser(userId);
+ }
+
+ @Override
+ public void onUserAdded(int userId) {
+ }
+
+ @Override
+ public void onUserRemoved(int userId) {
+ }
+
+ @Override
+ public void onUserLoggedOut(int userId) {
+ }
+
+ });
+ }
+
+ String getName() {
+ return mWallpaperMap.get(0).name;
+ }
+
+ void switchUser(int userId) {
+ synchronized (mLock) {
+ mCurrentUserId = userId;
+ WallpaperData wallpaper = mWallpaperMap.get(userId);
+ if (wallpaper == null) {
+ wallpaper = new WallpaperData(userId);
+ mWallpaperMap.put(userId, wallpaper);
+ loadSettingsLocked(userId);
+ wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
+ wallpaper.wallpaperObserver.startWatching();
+ }
+ switchWallpaper(wallpaper);
+ }
+ }
+
+ void switchWallpaper(WallpaperData wallpaper) {
synchronized (mLock) {
RuntimeException e = null;
try {
- if (bindWallpaperComponentLocked(mNextWallpaperComponent, false, false)) {
+ ComponentName cname = wallpaper.wallpaperComponent != null ?
+ wallpaper.wallpaperComponent : wallpaper.nextWallpaperComponent;
+ if (bindWallpaperComponentLocked(cname, true, false, wallpaper)) {
return;
}
} catch (RuntimeException e1) {
e = e1;
}
Slog.w(TAG, "Failure starting previous wallpaper", e);
- clearWallpaperLocked(false);
+ clearWallpaperLocked(false, wallpaper.userId);
}
}
-
+
public void clearWallpaper() {
if (DEBUG) Slog.v(TAG, "clearWallpaper");
synchronized (mLock) {
- clearWallpaperLocked(false);
+ clearWallpaperLocked(false, UserId.getCallingUserId());
}
}
- public void clearWallpaperLocked(boolean defaultFailed) {
- File f = WALLPAPER_FILE;
+ void clearWallpaperLocked(boolean defaultFailed, int userId) {
+ WallpaperData wallpaper = mWallpaperMap.get(userId);
+ File f = new File(getWallpaperDir(userId), WALLPAPER);
if (f.exists()) {
f.delete();
}
final long ident = Binder.clearCallingIdentity();
RuntimeException e = null;
try {
- mImageWallpaperPending = false;
+ wallpaper.imageWallpaperPending = false;
+ if (userId != mCurrentUserId) return;
if (bindWallpaperComponentLocked(defaultFailed
- ? mImageWallpaperComponent : null, true, false)) {
+ ? wallpaper.imageWallpaperComponent
+ : null, true, false, wallpaper)) {
return;
}
} catch (IllegalArgumentException e1) {
@@ -383,29 +502,35 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
// let's not let it crash the system and just live with no
// wallpaper.
Slog.e(TAG, "Default wallpaper component not found!", e);
- clearWallpaperComponentLocked();
+ clearWallpaperComponentLocked(wallpaper);
}
public void setDimensionHints(int width, int height) throws RemoteException {
checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
+ int userId = UserId.getCallingUserId();
+ WallpaperData wallpaper = mWallpaperMap.get(userId);
+ if (wallpaper == null) {
+ throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
+ }
if (width <= 0 || height <= 0) {
throw new IllegalArgumentException("width and height must be > 0");
}
synchronized (mLock) {
- if (width != mWidth || height != mHeight) {
- mWidth = width;
- mHeight = height;
- saveSettingsLocked();
- if (mWallpaperConnection != null) {
- if (mWallpaperConnection.mEngine != null) {
+ if (width != wallpaper.width || height != wallpaper.height) {
+ wallpaper.width = width;
+ wallpaper.height = height;
+ saveSettingsLocked(wallpaper);
+ if (mCurrentUserId != userId) return; // Don't change the properties now
+ if (wallpaper.connection != null) {
+ if (wallpaper.connection.mEngine != null) {
try {
- mWallpaperConnection.mEngine.setDesiredSize(
+ wallpaper.connection.mEngine.setDesiredSize(
width, height);
} catch (RemoteException e) {
}
- notifyCallbacksLocked();
+ notifyCallbacksLocked(wallpaper);
}
}
}
@@ -414,26 +539,38 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
public int getWidthHint() throws RemoteException {
synchronized (mLock) {
- return mWidth;
+ WallpaperData wallpaper = mWallpaperMap.get(UserId.getCallingUserId());
+ return wallpaper.width;
}
}
public int getHeightHint() throws RemoteException {
synchronized (mLock) {
- return mHeight;
+ WallpaperData wallpaper = mWallpaperMap.get(UserId.getCallingUserId());
+ return wallpaper.height;
}
}
public ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb,
Bundle outParams) {
synchronized (mLock) {
+ // This returns the current user's wallpaper, if called by a system service. Else it
+ // returns the wallpaper for the calling user.
+ int callingUid = Binder.getCallingUid();
+ int wallpaperUserId = 0;
+ if (callingUid == android.os.Process.SYSTEM_UID) {
+ wallpaperUserId = mCurrentUserId;
+ } else {
+ wallpaperUserId = UserId.getUserId(callingUid);
+ }
+ WallpaperData wallpaper = mWallpaperMap.get(wallpaperUserId);
try {
if (outParams != null) {
- outParams.putInt("width", mWidth);
- outParams.putInt("height", mHeight);
+ outParams.putInt("width", wallpaper.width);
+ outParams.putInt("height", wallpaper.height);
}
- mCallbacks.register(cb);
- File f = WALLPAPER_FILE;
+ wallpaper.callbacks.register(cb);
+ File f = new File(getWallpaperDir(wallpaperUserId), WALLPAPER);
if (!f.exists()) {
return null;
}
@@ -447,24 +584,30 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
}
public WallpaperInfo getWallpaperInfo() {
+ int userId = UserId.getCallingUserId();
synchronized (mLock) {
- if (mWallpaperConnection != null) {
- return mWallpaperConnection.mInfo;
+ WallpaperData wallpaper = mWallpaperMap.get(userId);
+ if (wallpaper.connection != null) {
+ return wallpaper.connection.mInfo;
}
return null;
}
}
-
+
public ParcelFileDescriptor setWallpaper(String name) {
if (DEBUG) Slog.v(TAG, "setWallpaper");
-
+ int userId = UserId.getCallingUserId();
+ WallpaperData wallpaper = mWallpaperMap.get(userId);
+ if (wallpaper == null) {
+ throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
+ }
checkPermission(android.Manifest.permission.SET_WALLPAPER);
synchronized (mLock) {
final long ident = Binder.clearCallingIdentity();
try {
- ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name);
+ ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name, wallpaper);
if (pfd != null) {
- mImageWallpaperPending = true;
+ wallpaper.imageWallpaperPending = true;
}
return pfd;
} finally {
@@ -473,19 +616,20 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
}
}
- ParcelFileDescriptor updateWallpaperBitmapLocked(String name) {
+ ParcelFileDescriptor updateWallpaperBitmapLocked(String name, WallpaperData wallpaper) {
if (name == null) name = "";
try {
- if (!WALLPAPER_DIR.exists()) {
- WALLPAPER_DIR.mkdir();
+ File dir = getWallpaperDir(wallpaper.userId);
+ if (!dir.exists()) {
+ dir.mkdir();
FileUtils.setPermissions(
- WALLPAPER_DIR.getPath(),
+ dir.getPath(),
FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH,
-1, -1);
}
- ParcelFileDescriptor fd = ParcelFileDescriptor.open(WALLPAPER_FILE,
+ ParcelFileDescriptor fd = ParcelFileDescriptor.open(new File(dir, WALLPAPER),
MODE_CREATE|MODE_READ_WRITE);
- mName = name;
+ wallpaper.name = name;
return fd;
} catch (FileNotFoundException e) {
Slog.w(TAG, "Error setting wallpaper", e);
@@ -495,31 +639,36 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
public void setWallpaperComponent(ComponentName name) {
if (DEBUG) Slog.v(TAG, "setWallpaperComponent name=" + name);
+ int userId = UserId.getCallingUserId();
+ WallpaperData wallpaper = mWallpaperMap.get(userId);
+ if (wallpaper == null) {
+ throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);
+ }
checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);
synchronized (mLock) {
final long ident = Binder.clearCallingIdentity();
try {
- mImageWallpaperPending = false;
- bindWallpaperComponentLocked(name, false, true);
+ wallpaper.imageWallpaperPending = false;
+ bindWallpaperComponentLocked(name, false, true, wallpaper);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
- boolean bindWallpaperComponentLocked(ComponentName componentName, boolean force, boolean fromUser) {
+ boolean bindWallpaperComponentLocked(ComponentName componentName, boolean force,
+ boolean fromUser, WallpaperData wallpaper) {
if (DEBUG) Slog.v(TAG, "bindWallpaperComponentLocked: componentName=" + componentName);
-
// Has the component changed?
if (!force) {
- if (mWallpaperConnection != null) {
- if (mWallpaperComponent == null) {
+ if (wallpaper.connection != null) {
+ if (wallpaper.wallpaperComponent == null) {
if (componentName == null) {
if (DEBUG) Slog.v(TAG, "bindWallpaperComponentLocked: still using default");
// Still using default wallpaper.
return true;
}
- } else if (mWallpaperComponent.equals(componentName)) {
+ } else if (wallpaper.wallpaperComponent.equals(componentName)) {
// Changing to same wallpaper.
if (DEBUG) Slog.v(TAG, "same wallpaper");
return true;
@@ -538,7 +687,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
}
if (componentName == null) {
// Fall back to static image wallpaper
- componentName = mImageWallpaperComponent;
+ componentName = wallpaper.imageWallpaperComponent;
//clearWallpaperComponentLocked();
//return;
if (DEBUG) Slog.v(TAG, "Using image wallpaper");
@@ -560,7 +709,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
WallpaperInfo wi = null;
Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE);
- if (componentName != null && !componentName.equals(mImageWallpaperComponent)) {
+ if (componentName != null && !componentName.equals(wallpaper.imageWallpaperComponent)) {
// Make sure the selected service is actually a wallpaper service.
List<ResolveInfo> ris = mContext.getPackageManager()
.queryIntentServices(intent, PackageManager.GET_META_DATA);
@@ -599,8 +748,13 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
// Bind the service!
if (DEBUG) Slog.v(TAG, "Binding to:" + componentName);
- WallpaperConnection newConn = new WallpaperConnection(wi);
+ WallpaperConnection newConn = new WallpaperConnection(wi, wallpaper);
intent.setComponent(componentName);
+ int serviceUserId = wallpaper.userId;
+ // Because the image wallpaper is running in the system ui
+ if (componentName.equals(wallpaper.imageWallpaperComponent)) {
+ serviceUserId = 0;
+ }
intent.putExtra(Intent.EXTRA_CLIENT_LABEL,
com.android.internal.R.string.wallpaper_binding_label);
intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
@@ -608,8 +762,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
Intent.createChooser(new Intent(Intent.ACTION_SET_WALLPAPER),
mContext.getText(com.android.internal.R.string.chooser_wallpaper)),
0));
- if (!mContext.bindService(intent, newConn,
- Context.BIND_AUTO_CREATE)) {
+ if (!mContext.bindService(intent, newConn, Context.BIND_AUTO_CREATE, serviceUserId)) {
String msg = "Unable to bind service: "
+ componentName;
if (fromUser) {
@@ -618,18 +771,22 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
Slog.w(TAG, msg);
return false;
}
-
- clearWallpaperComponentLocked();
- mWallpaperComponent = componentName;
- mWallpaperConnection = newConn;
- mLastDiedTime = SystemClock.uptimeMillis();
+ if (wallpaper.userId == mCurrentUserId && mLastWallpaper != null) {
+ detachWallpaperLocked(mLastWallpaper);
+ }
+ wallpaper.wallpaperComponent = componentName;
+ wallpaper.connection = newConn;
+ wallpaper.lastDiedTime = SystemClock.uptimeMillis();
try {
- if (DEBUG) Slog.v(TAG, "Adding window token: " + newConn.mToken);
- mIWindowManager.addWindowToken(newConn.mToken,
- WindowManager.LayoutParams.TYPE_WALLPAPER);
+ if (wallpaper.userId == mCurrentUserId) {
+ if (DEBUG)
+ Slog.v(TAG, "Adding window token: " + newConn.mToken);
+ mIWindowManager.addWindowToken(newConn.mToken,
+ WindowManager.LayoutParams.TYPE_WALLPAPER);
+ mLastWallpaper = wallpaper;
+ }
} catch (RemoteException e) {
}
-
} catch (PackageManager.NameNotFoundException e) {
String msg = "Unknown component " + componentName;
if (fromUser) {
@@ -640,54 +797,58 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
}
return true;
}
-
- void clearWallpaperComponentLocked() {
- mWallpaperComponent = null;
- if (mWallpaperConnection != null) {
- if (mWallpaperConnection.mEngine != null) {
+
+ void detachWallpaperLocked(WallpaperData wallpaper) {
+ if (wallpaper.connection != null) {
+ if (wallpaper.connection.mEngine != null) {
try {
- mWallpaperConnection.mEngine.destroy();
+ wallpaper.connection.mEngine.destroy();
} catch (RemoteException e) {
}
}
- mContext.unbindService(mWallpaperConnection);
+ mContext.unbindService(wallpaper.connection);
try {
- if (DEBUG) Slog.v(TAG, "Removing window token: "
- + mWallpaperConnection.mToken);
- mIWindowManager.removeWindowToken(mWallpaperConnection.mToken);
+ if (DEBUG)
+ Slog.v(TAG, "Removing window token: " + wallpaper.connection.mToken);
+ mIWindowManager.removeWindowToken(wallpaper.connection.mToken);
} catch (RemoteException e) {
}
- mWallpaperConnection.mService = null;
- mWallpaperConnection.mEngine = null;
- mWallpaperConnection = null;
+ wallpaper.connection.mService = null;
+ wallpaper.connection.mEngine = null;
+ wallpaper.connection = null;
}
}
-
- void attachServiceLocked(WallpaperConnection conn) {
+
+ void clearWallpaperComponentLocked(WallpaperData wallpaper) {
+ wallpaper.wallpaperComponent = null;
+ detachWallpaperLocked(wallpaper);
+ }
+
+ void attachServiceLocked(WallpaperConnection conn, WallpaperData wallpaper) {
try {
conn.mService.attach(conn, conn.mToken,
WindowManager.LayoutParams.TYPE_WALLPAPER, false,
- mWidth, mHeight);
+ wallpaper.width, wallpaper.height);
} catch (RemoteException e) {
Slog.w(TAG, "Failed attaching wallpaper; clearing", e);
- if (!mWallpaperUpdating) {
- bindWallpaperComponentLocked(null, false, false);
+ if (!wallpaper.wallpaperUpdating) {
+ bindWallpaperComponentLocked(null, false, false, wallpaper);
}
}
}
-
- private void notifyCallbacksLocked() {
- final int n = mCallbacks.beginBroadcast();
+
+ private void notifyCallbacksLocked(WallpaperData wallpaper) {
+ final int n = wallpaper.callbacks.beginBroadcast();
for (int i = 0; i < n; i++) {
try {
- mCallbacks.getBroadcastItem(i).onWallpaperChanged();
+ wallpaper.callbacks.getBroadcastItem(i).onWallpaperChanged();
} catch (RemoteException e) {
// The RemoteCallbackList will take care of removing
// the dead object for us.
}
}
- mCallbacks.finishBroadcast();
+ wallpaper.callbacks.finishBroadcast();
final Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED);
mContext.sendBroadcast(intent);
}
@@ -699,13 +860,13 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
}
}
- private static JournaledFile makeJournaledFile() {
- final String base = "/data/system/wallpaper_info.xml";
+ private static JournaledFile makeJournaledFile(int userId) {
+ final String base = "/data/system/users/" + userId + "/" + WALLPAPER_INFO;
return new JournaledFile(new File(base), new File(base + ".tmp"));
}
- private void saveSettingsLocked() {
- JournaledFile journal = makeJournaledFile();
+ private void saveSettingsLocked(WallpaperData wallpaper) {
+ JournaledFile journal = makeJournaledFile(wallpaper.userId);
FileOutputStream stream = null;
try {
stream = new FileOutputStream(journal.chooseForWrite(), false);
@@ -714,13 +875,13 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
out.startDocument(null, true);
out.startTag(null, "wp");
- out.attribute(null, "width", Integer.toString(mWidth));
- out.attribute(null, "height", Integer.toString(mHeight));
- out.attribute(null, "name", mName);
- if (mWallpaperComponent != null &&
- !mWallpaperComponent.equals(mImageWallpaperComponent)) {
+ out.attribute(null, "width", Integer.toString(wallpaper.width));
+ out.attribute(null, "height", Integer.toString(wallpaper.height));
+ out.attribute(null, "name", wallpaper.name);
+ if (wallpaper.wallpaperComponent != null
+ && !wallpaper.wallpaperComponent.equals(wallpaper.imageWallpaperComponent)) {
out.attribute(null, "component",
- mWallpaperComponent.flattenToShortString());
+ wallpaper.wallpaperComponent.flattenToShortString());
}
out.endTag(null, "wp");
@@ -739,12 +900,34 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
}
}
- private void loadSettingsLocked() {
+ private void migrateFromOld() {
+ File oldWallpaper = new File(WallpaperBackupHelper.WALLPAPER_IMAGE_KEY);
+ File oldInfo = new File(WallpaperBackupHelper.WALLPAPER_INFO_KEY);
+ if (oldWallpaper.exists()) {
+ File newWallpaper = new File(getWallpaperDir(0), WALLPAPER);
+ oldWallpaper.renameTo(newWallpaper);
+ }
+ if (oldInfo.exists()) {
+ File newInfo = new File(getWallpaperDir(0), WALLPAPER_INFO);
+ oldInfo.renameTo(newInfo);
+ }
+ }
+
+ private void loadSettingsLocked(int userId) {
if (DEBUG) Slog.v(TAG, "loadSettingsLocked");
- JournaledFile journal = makeJournaledFile();
+ JournaledFile journal = makeJournaledFile(userId);
FileInputStream stream = null;
File file = journal.chooseForRead();
+ if (!file.exists()) {
+ // This should only happen one time, when upgrading from a legacy system
+ migrateFromOld();
+ }
+ WallpaperData wallpaper = mWallpaperMap.get(userId);
+ if (wallpaper == null) {
+ wallpaper = new WallpaperData(userId);
+ mWallpaperMap.put(userId, wallpaper);
+ }
boolean success = false;
try {
stream = new FileInputStream(file);
@@ -757,23 +940,26 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
if (type == XmlPullParser.START_TAG) {
String tag = parser.getName();
if ("wp".equals(tag)) {
- mWidth = Integer.parseInt(parser.getAttributeValue(null, "width"));
- mHeight = Integer.parseInt(parser.getAttributeValue(null, "height"));
- mName = parser.getAttributeValue(null, "name");
+ wallpaper.width = Integer.parseInt(parser.getAttributeValue(null, "width"));
+ wallpaper.height = Integer.parseInt(parser
+ .getAttributeValue(null, "height"));
+ wallpaper.name = parser.getAttributeValue(null, "name");
String comp = parser.getAttributeValue(null, "component");
- mNextWallpaperComponent = comp != null
+ wallpaper.nextWallpaperComponent = comp != null
? ComponentName.unflattenFromString(comp)
: null;
- if (mNextWallpaperComponent == null ||
- "android".equals(mNextWallpaperComponent.getPackageName())) {
- mNextWallpaperComponent = mImageWallpaperComponent;
+ if (wallpaper.nextWallpaperComponent == null
+ || "android".equals(wallpaper.nextWallpaperComponent
+ .getPackageName())) {
+ wallpaper.nextWallpaperComponent = wallpaper.imageWallpaperComponent;
}
if (DEBUG) {
- Slog.v(TAG, "mWidth:" + mWidth);
- Slog.v(TAG, "mHeight:" + mHeight);
- Slog.v(TAG, "mName:" + mName);
- Slog.v(TAG, "mNextWallpaperComponent:" + mNextWallpaperComponent);
+ Slog.v(TAG, "mWidth:" + wallpaper.width);
+ Slog.v(TAG, "mHeight:" + wallpaper.height);
+ Slog.v(TAG, "mName:" + wallpaper.name);
+ Slog.v(TAG, "mNextWallpaperComponent:"
+ + wallpaper.nextWallpaperComponent);
}
}
}
@@ -799,70 +985,75 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
}
if (!success) {
- mWidth = -1;
- mHeight = -1;
- mName = "";
+ wallpaper.width = -1;
+ wallpaper.height = -1;
+ wallpaper.name = "";
}
// We always want to have some reasonable width hint.
WindowManager wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
Display d = wm.getDefaultDisplay();
int baseSize = d.getMaximumSizeDimension();
- if (mWidth < baseSize) {
- mWidth = baseSize;
+ if (wallpaper.width < baseSize) {
+ wallpaper.width = baseSize;
}
- if (mHeight < baseSize) {
- mHeight = baseSize;
+ if (wallpaper.height < baseSize) {
+ wallpaper.height = baseSize;
}
}
// Called by SystemBackupAgent after files are restored to disk.
void settingsRestored() {
+ // TODO: If necessary, make it work for secondary users as well. This currently assumes
+ // restores only to the primary user
if (DEBUG) Slog.v(TAG, "settingsRestored");
-
+ WallpaperData wallpaper = null;
boolean success = false;
synchronized (mLock) {
- loadSettingsLocked();
- if (mNextWallpaperComponent != null &&
- !mNextWallpaperComponent.equals(mImageWallpaperComponent)) {
- if (!bindWallpaperComponentLocked(mNextWallpaperComponent, false, false)) {
+ loadSettingsLocked(0);
+ wallpaper = mWallpaperMap.get(0);
+ if (wallpaper.nextWallpaperComponent != null
+ && !wallpaper.nextWallpaperComponent.equals(wallpaper.imageWallpaperComponent)) {
+ if (!bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,
+ wallpaper)) {
// No such live wallpaper or other failure; fall back to the default
// live wallpaper (since the profile being restored indicated that the
// user had selected a live rather than static one).
- bindWallpaperComponentLocked(null, false, false);
+ bindWallpaperComponentLocked(null, false, false, wallpaper);
}
success = true;
} else {
// If there's a wallpaper name, we use that. If that can't be loaded, then we
// use the default.
- if ("".equals(mName)) {
+ if ("".equals(wallpaper.name)) {
if (DEBUG) Slog.v(TAG, "settingsRestored: name is empty");
success = true;
} else {
if (DEBUG) Slog.v(TAG, "settingsRestored: attempting to restore named resource");
- success = restoreNamedResourceLocked();
+ success = restoreNamedResourceLocked(wallpaper);
}
if (DEBUG) Slog.v(TAG, "settingsRestored: success=" + success);
if (success) {
- bindWallpaperComponentLocked(mNextWallpaperComponent, false, false);
+ bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,
+ wallpaper);
}
}
}
if (!success) {
- Slog.e(TAG, "Failed to restore wallpaper: '" + mName + "'");
- mName = "";
- WALLPAPER_FILE.delete();
+ Slog.e(TAG, "Failed to restore wallpaper: '" + wallpaper.name + "'");
+ wallpaper.name = "";
+ getWallpaperDir(0).delete();
}
synchronized (mLock) {
- saveSettingsLocked();
+ saveSettingsLocked(wallpaper);
}
}
- boolean restoreNamedResourceLocked() {
- if (mName.length() > 4 && "res:".equals(mName.substring(0, 4))) {
- String resName = mName.substring(4);
+ boolean restoreNamedResourceLocked(WallpaperData wallpaper) {
+ if (wallpaper.name.length() > 4 && "res:".equals(wallpaper.name.substring(0, 4))) {
+ String resName = wallpaper.name.substring(4);
String pkg = null;
int colon = resName.indexOf(':');
@@ -896,10 +1087,10 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
}
res = r.openRawResource(resId);
- if (WALLPAPER_FILE.exists()) {
- WALLPAPER_FILE.delete();
+ if (wallpaper.wallpaperFile.exists()) {
+ wallpaper.wallpaperFile.delete();
}
- fos = new FileOutputStream(WALLPAPER_FILE);
+ fos = new FileOutputStream(wallpaper.wallpaperFile);
byte[] buffer = new byte[32768];
int amt;
@@ -933,7 +1124,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
}
return false;
}
-
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
@@ -947,20 +1138,35 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
synchronized (mLock) {
pw.println("Current Wallpaper Service state:");
- pw.print(" mWidth="); pw.print(mWidth);
- pw.print(" mHeight="); pw.println(mHeight);
- pw.print(" mName="); pw.println(mName);
- pw.print(" mWallpaperComponent="); pw.println(mWallpaperComponent);
- if (mWallpaperConnection != null) {
- WallpaperConnection conn = mWallpaperConnection;
- pw.print(" Wallpaper connection ");
- pw.print(conn); pw.println(":");
- pw.print(" mInfo.component="); pw.println(conn.mInfo.getComponent());
- pw.print(" mToken="); pw.println(conn.mToken);
- pw.print(" mService="); pw.println(conn.mService);
- pw.print(" mEngine="); pw.println(conn.mEngine);
- pw.print(" mLastDiedTime=");
- pw.println(mLastDiedTime - SystemClock.uptimeMillis());
+ for (int i = 0; i < mWallpaperMap.size(); i++) {
+ WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+ pw.println(" User " + wallpaper.userId + ":");
+ pw.print(" mWidth=");
+ pw.print(wallpaper.width);
+ pw.print(" mHeight=");
+ pw.println(wallpaper.height);
+ pw.print(" mName=");
+ pw.println(wallpaper.name);
+ pw.print(" mWallpaperComponent=");
+ pw.println(wallpaper.wallpaperComponent);
+ if (wallpaper.connection != null) {
+ WallpaperConnection conn = wallpaper.connection;
+ pw.print(" Wallpaper connection ");
+ pw.print(conn);
+ pw.println(":");
+ if (conn.mInfo != null) {
+ pw.print(" mInfo.component=");
+ pw.println(conn.mInfo.getComponent());
+ }
+ pw.print(" mToken=");
+ pw.println(conn.mToken);
+ pw.print(" mService=");
+ pw.println(conn.mService);
+ pw.print(" mEngine=");
+ pw.println(conn.mEngine);
+ pw.print(" mLastDiedTime=");
+ pw.println(wallpaper.lastDiedTime - SystemClock.uptimeMillis());
+ }
}
}
}
diff --git a/services/java/com/android/server/WiredAccessoryObserver.java b/services/java/com/android/server/WiredAccessoryObserver.java
index 6a63eaca8da2..326b94033776 100644
--- a/services/java/com/android/server/WiredAccessoryObserver.java
+++ b/services/java/com/android/server/WiredAccessoryObserver.java
@@ -191,8 +191,12 @@ class WiredAccessoryObserver extends UEventObserver {
mHeadsetState = headsetState;
if (headsetState == 0) {
- Intent intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
- mContext.sendBroadcast(intent);
+ if (mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_sendAudioBecomingNoisy)) {
+ Intent intent = new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
+ mContext.sendBroadcast(intent);
+ }
+
// It can take hundreds of ms flush the audio pipeline after
// apps pause audio playback, but audio route changes are
// immediate, so delay the route change by 1000ms.
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 8bda7559b729..586a67e26d84 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -143,6 +143,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
private final SecurityPolicy mSecurityPolicy;
+ private Service mUiAutomationService;
+
/**
* Handler for delayed event dispatch.
*/
@@ -494,19 +496,15 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
}
// Hook the automation service up.
- Service service = new Service(componentName, accessibilityServiceInfo, true);
- service.onServiceConnected(componentName, listener.asBinder());
+ mUiAutomationService = new Service(componentName, accessibilityServiceInfo, true);
+ mUiAutomationService.onServiceConnected(componentName, listener.asBinder());
}
public void unregisterUiTestAutomationService(IEventListener listener) {
synchronized (mLock) {
- final int serviceCount = mServices.size();
- for (int i = 0; i < serviceCount; i++) {
- Service service = mServices.get(i);
- if (service.mServiceInterface == listener && service.mIsAutomation) {
- // Automation service is not bound, so pretend it died to perform clean up.
- service.binderDied();
- }
+ // Automation service is not bound, so pretend it died to perform clean up.
+ if (mUiAutomationService != null) {
+ mUiAutomationService.binderDied();
}
}
}
@@ -741,7 +739,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
* Manages services by starting enabled ones and stopping disabled ones.
*/
private void manageServicesLocked() {
- unbindAutomationService();
+ // While the UI automation service is running it takes over.
+ if (mUiAutomationService != null) {
+ return;
+ }
populateEnabledServicesLocked(mEnabledServices);
final int enabledInstalledServicesCount = updateServicesStateLocked(mInstalledServices,
mEnabledServices);
@@ -769,21 +770,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
}
/**
- * Unbinds the automation service if such is running.
- */
- private void unbindAutomationService() {
- List<Service> runningServices = mServices;
- int runningServiceCount = mServices.size();
- for (int i = 0; i < runningServiceCount; i++) {
- Service service = runningServices.get(i);
- if (service.mIsAutomation) {
- service.unbind();
- return;
- }
- }
- }
-
- /**
* Populates a list with the {@link ComponentName}s of all enabled
* {@link AccessibilityService}s.
*
@@ -1248,6 +1234,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub
// We no longer have an automation service, so restore
// the state based on values in the settings database.
if (mIsAutomation) {
+ mUiAutomationService = null;
handleAccessibilityEnabledSettingChangedLocked();
}
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 4e1e9d97a75f..ac311b8130c9 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -49,6 +49,7 @@ import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
+import android.app.WallpaperManager;
import android.app.backup.IBackupManager;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
@@ -291,813 +292,12 @@ public final class ActivityManagerService extends ActivityManagerNative
final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
= new ArrayList<PendingActivityLaunch>();
- /**
- * BROADCASTS
- *
- * We keep two broadcast queues and associated bookkeeping, one for those at
- * foreground priority, and one for normal (background-priority) broadcasts.
- */
- public class BroadcastQueue {
- static final String TAG = "BroadcastQueue";
-
- static final int MAX_BROADCAST_HISTORY = 25;
-
- /**
- * Recognizable moniker for this queue
- */
- String mQueueName;
-
- /**
- * Timeout period for this queue's broadcasts
- */
- long mTimeoutPeriod;
-
- /**
- * Lists of all active broadcasts that are to be executed immediately
- * (without waiting for another broadcast to finish). Currently this only
- * contains broadcasts to registered receivers, to avoid spinning up
- * a bunch of processes to execute IntentReceiver components. Background-
- * and foreground-priority broadcasts are queued separately.
- */
- final ArrayList<BroadcastRecord> mParallelBroadcasts
- = new ArrayList<BroadcastRecord>();
- /**
- * List of all active broadcasts that are to be executed one at a time.
- * The object at the top of the list is the currently activity broadcasts;
- * those after it are waiting for the top to finish. As with parallel
- * broadcasts, separate background- and foreground-priority queues are
- * maintained.
- */
- final ArrayList<BroadcastRecord> mOrderedBroadcasts
- = new ArrayList<BroadcastRecord>();
-
- /**
- * Historical data of past broadcasts, for debugging.
- */
- final BroadcastRecord[] mBroadcastHistory
- = new BroadcastRecord[MAX_BROADCAST_HISTORY];
-
- /**
- * Set when we current have a BROADCAST_INTENT_MSG in flight.
- */
- boolean mBroadcastsScheduled = false;
-
- /**
- * True if we have a pending unexpired BROADCAST_TIMEOUT_MSG posted to our handler.
- */
- boolean mPendingBroadcastTimeoutMessage;
-
- /**
- * Intent broadcasts that we have tried to start, but are
- * waiting for the application's process to be created. We only
- * need one per scheduling class (instead of a list) because we always
- * process broadcasts one at a time, so no others can be started while
- * waiting for this one.
- */
- BroadcastRecord mPendingBroadcast = null;
-
- /**
- * The receiver index that is pending, to restart the broadcast if needed.
- */
- int mPendingBroadcastRecvIndex;
-
- BroadcastQueue(String name, long timeoutPeriod) {
- mQueueName = name;
- mTimeoutPeriod = timeoutPeriod;
- }
-
- public boolean isPendingBroadcastProcessLocked(int pid) {
- return mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid;
- }
-
- public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
- mParallelBroadcasts.add(r);
- }
-
- public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
- mOrderedBroadcasts.add(r);
- }
-
- public final boolean replaceParallelBroadcastLocked(BroadcastRecord r) {
- for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
- if (r.intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "***** DROPPING PARALLEL ["
- + mQueueName + "]: " + r.intent);
- mParallelBroadcasts.set(i, r);
- return true;
- }
- }
- return false;
- }
-
- public final boolean replaceOrderedBroadcastLocked(BroadcastRecord r) {
- for (int i=mOrderedBroadcasts.size()-1; i>0; i--) {
- if (r.intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "***** DROPPING ORDERED ["
- + mQueueName + "]: " + r.intent);
- mOrderedBroadcasts.set(i, r);
- return true;
- }
- }
- return false;
- }
-
- public boolean sendPendingBroadcastsLocked(ProcessRecord app) {
- boolean didSomething = false;
- final BroadcastRecord br = mPendingBroadcast;
- if (br != null && br.curApp.pid == app.pid) {
- try {
- mPendingBroadcast = null;
- processCurBroadcastLocked(br, app);
- didSomething = true;
- } catch (Exception e) {
- Slog.w(TAG, "Exception in new application when starting receiver "
- + br.curComponent.flattenToShortString(), e);
- logBroadcastReceiverDiscardLocked(br);
- finishReceiverLocked(br, br.resultCode, br.resultData,
- br.resultExtras, br.resultAbort, true);
- scheduleBroadcastsLocked();
- // We need to reset the state if we fails to start the receiver.
- br.state = BroadcastRecord.IDLE;
- throw new RuntimeException(e.getMessage());
- }
- }
- return didSomething;
- }
-
- public void skipPendingBroadcastLocked(int pid) {
- final BroadcastRecord br = mPendingBroadcast;
- if (br != null && br.curApp.pid == pid) {
- br.state = BroadcastRecord.IDLE;
- br.nextReceiver = mPendingBroadcastRecvIndex;
- mPendingBroadcast = null;
- scheduleBroadcastsLocked();
- }
- }
-
- public void skipCurrentReceiverLocked(ProcessRecord app) {
- boolean reschedule = false;
- BroadcastRecord r = app.curReceiver;
- if (r != null) {
- // The current broadcast is waiting for this app's receiver
- // to be finished. Looks like that's not going to happen, so
- // let the broadcast continue.
- logBroadcastReceiverDiscardLocked(r);
- finishReceiverLocked(r, r.resultCode, r.resultData,
- r.resultExtras, r.resultAbort, true);
- reschedule = true;
- }
-
- r = mPendingBroadcast;
- if (r != null && r.curApp == app) {
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "[" + mQueueName + "] skip & discard pending app " + r);
- logBroadcastReceiverDiscardLocked(r);
- finishReceiverLocked(r, r.resultCode, r.resultData,
- r.resultExtras, r.resultAbort, true);
- reschedule = true;
- }
- if (reschedule) {
- scheduleBroadcastsLocked();
- }
- }
-
- public void scheduleBroadcastsLocked() {
- if (DEBUG_BROADCAST) Slog.v(TAG, "Schedule broadcasts ["
- + mQueueName + "]: current="
- + mBroadcastsScheduled);
-
- if (mBroadcastsScheduled) {
- return;
- }
- mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
- mBroadcastsScheduled = true;
- }
-
- public BroadcastRecord getMatchingOrderedReceiver(IBinder receiver) {
- if (mOrderedBroadcasts.size() > 0) {
- final BroadcastRecord r = mOrderedBroadcasts.get(0);
- if (r != null && r.receiver == receiver) {
- return r;
- }
- }
- return null;
- }
-
- public boolean finishReceiverLocked(BroadcastRecord r, int resultCode,
- String resultData, Bundle resultExtras, boolean resultAbort,
- boolean explicit) {
- int state = r.state;
- r.state = BroadcastRecord.IDLE;
- if (state == BroadcastRecord.IDLE) {
- if (explicit) {
- Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE");
- }
- }
- r.receiver = null;
- r.intent.setComponent(null);
- if (r.curApp != null) {
- r.curApp.curReceiver = null;
- }
- if (r.curFilter != null) {
- r.curFilter.receiverList.curBroadcast = null;
- }
- r.curFilter = null;
- r.curApp = null;
- r.curComponent = null;
- r.curReceiver = null;
- mPendingBroadcast = null;
-
- r.resultCode = resultCode;
- r.resultData = resultData;
- r.resultExtras = resultExtras;
- r.resultAbort = resultAbort;
-
- // We will process the next receiver right now if this is finishing
- // an app receiver (which is always asynchronous) or after we have
- // come back from calling a receiver.
- return state == BroadcastRecord.APP_RECEIVE
- || state == BroadcastRecord.CALL_DONE_RECEIVE;
- }
-
- private final void processNextBroadcast(boolean fromMsg) {
- synchronized(ActivityManagerService.this) {
- BroadcastRecord r;
-
- if (DEBUG_BROADCAST) Slog.v(TAG, "processNextBroadcast ["
- + mQueueName + "]: "
- + mParallelBroadcasts.size() + " broadcasts, "
- + mOrderedBroadcasts.size() + " ordered broadcasts");
-
- updateCpuStats();
-
- if (fromMsg) {
- mBroadcastsScheduled = false;
- }
-
- // First, deliver any non-serialized broadcasts right away.
- while (mParallelBroadcasts.size() > 0) {
- r = mParallelBroadcasts.remove(0);
- r.dispatchTime = SystemClock.uptimeMillis();
- r.dispatchClockTime = System.currentTimeMillis();
- final int N = r.receivers.size();
- if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing parallel broadcast ["
- + mQueueName + "] " + r);
- for (int i=0; i<N; i++) {
- Object target = r.receivers.get(i);
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "Delivering non-ordered on [" + mQueueName + "] to registered "
- + target + ": " + r);
- deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
- }
- addBroadcastToHistoryLocked(r);
- if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Done with parallel broadcast ["
- + mQueueName + "] " + r);
- }
-
- // Now take care of the next serialized one...
-
- // If we are waiting for a process to come up to handle the next
- // broadcast, then do nothing at this point. Just in case, we
- // check that the process we're waiting for still exists.
- if (mPendingBroadcast != null) {
- if (DEBUG_BROADCAST_LIGHT) {
- Slog.v(TAG, "processNextBroadcast ["
- + mQueueName + "]: waiting for "
- + mPendingBroadcast.curApp);
- }
-
- boolean isDead;
- synchronized (mPidsSelfLocked) {
- isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
- }
- if (!isDead) {
- // It's still alive, so keep waiting
- return;
- } else {
- Slog.w(TAG, "pending app ["
- + mQueueName + "]" + mPendingBroadcast.curApp
- + " died before responding to broadcast");
- mPendingBroadcast.state = BroadcastRecord.IDLE;
- mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
- mPendingBroadcast = null;
- }
- }
-
- boolean looped = false;
-
- do {
- if (mOrderedBroadcasts.size() == 0) {
- // No more broadcasts pending, so all done!
- scheduleAppGcsLocked();
- if (looped) {
- // If we had finished the last ordered broadcast, then
- // make sure all processes have correct oom and sched
- // adjustments.
- updateOomAdjLocked();
- }
- return;
- }
- r = mOrderedBroadcasts.get(0);
- boolean forceReceive = false;
-
- // Ensure that even if something goes awry with the timeout
- // detection, we catch "hung" broadcasts here, discard them,
- // and continue to make progress.
- //
- // This is only done if the system is ready so that PRE_BOOT_COMPLETED
- // receivers don't get executed with timeouts. They're intended for
- // one time heavy lifting after system upgrades and can take
- // significant amounts of time.
- int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
- if (mProcessesReady && r.dispatchTime > 0) {
- long now = SystemClock.uptimeMillis();
- if ((numReceivers > 0) &&
- (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
- Slog.w(TAG, "Hung broadcast ["
- + mQueueName + "] discarded after timeout failure:"
- + " now=" + now
- + " dispatchTime=" + r.dispatchTime
- + " startTime=" + r.receiverTime
- + " intent=" + r.intent
- + " numReceivers=" + numReceivers
- + " nextReceiver=" + r.nextReceiver
- + " state=" + r.state);
- broadcastTimeoutLocked(false); // forcibly finish this broadcast
- forceReceive = true;
- r.state = BroadcastRecord.IDLE;
- }
- }
-
- if (r.state != BroadcastRecord.IDLE) {
- if (DEBUG_BROADCAST) Slog.d(TAG,
- "processNextBroadcast("
- + mQueueName + ") called when not idle (state="
- + r.state + ")");
- return;
- }
-
- if (r.receivers == null || r.nextReceiver >= numReceivers
- || r.resultAbort || forceReceive) {
- // No more receivers for this broadcast! Send the final
- // result if requested...
- if (r.resultTo != null) {
- try {
- if (DEBUG_BROADCAST) {
- int seq = r.intent.getIntExtra("seq", -1);
- Slog.i(TAG, "Finishing broadcast ["
- + mQueueName + "] " + r.intent.getAction()
- + " seq=" + seq + " app=" + r.callerApp);
- }
- performReceiveLocked(r.callerApp, r.resultTo,
- new Intent(r.intent), r.resultCode,
- r.resultData, r.resultExtras, false, false);
- // Set this to null so that the reference
- // (local and remote) isnt kept in the mBroadcastHistory.
- r.resultTo = null;
- } catch (RemoteException e) {
- Slog.w(TAG, "Failure ["
- + mQueueName + "] sending broadcast result of "
- + r.intent, e);
- }
- }
-
- if (DEBUG_BROADCAST) Slog.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
- cancelBroadcastTimeoutLocked();
-
- if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Finished with ordered broadcast "
- + r);
-
- // ... and on to the next...
- addBroadcastToHistoryLocked(r);
- mOrderedBroadcasts.remove(0);
- r = null;
- looped = true;
- continue;
- }
- } while (r == null);
-
- // Get the next receiver...
- int recIdx = r.nextReceiver++;
-
- // Keep track of when this receiver started, and make sure there
- // is a timeout message pending to kill it if need be.
- r.receiverTime = SystemClock.uptimeMillis();
- if (recIdx == 0) {
- r.dispatchTime = r.receiverTime;
- r.dispatchClockTime = System.currentTimeMillis();
- if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing ordered broadcast ["
- + mQueueName + "] " + r);
- }
- if (! mPendingBroadcastTimeoutMessage) {
- long timeoutTime = r.receiverTime + mTimeoutPeriod;
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "Submitting BROADCAST_TIMEOUT_MSG ["
- + mQueueName + "] for " + r + " at " + timeoutTime);
- setBroadcastTimeoutLocked(timeoutTime);
- }
-
- Object nextReceiver = r.receivers.get(recIdx);
- if (nextReceiver instanceof BroadcastFilter) {
- // Simple case: this is a registered receiver who gets
- // a direct call.
- BroadcastFilter filter = (BroadcastFilter)nextReceiver;
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "Delivering ordered ["
- + mQueueName + "] to registered "
- + filter + ": " + r);
- deliverToRegisteredReceiverLocked(r, filter, r.ordered);
- if (r.receiver == null || !r.ordered) {
- // The receiver has already finished, so schedule to
- // process the next one.
- if (DEBUG_BROADCAST) Slog.v(TAG, "Quick finishing ["
- + mQueueName + "]: ordered="
- + r.ordered + " receiver=" + r.receiver);
- r.state = BroadcastRecord.IDLE;
- scheduleBroadcastsLocked();
- }
- return;
- }
-
- // Hard case: need to instantiate the receiver, possibly
- // starting its application process to host it.
-
- ResolveInfo info =
- (ResolveInfo)nextReceiver;
-
- boolean skip = false;
- int perm = checkComponentPermission(info.activityInfo.permission,
- r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid,
- info.activityInfo.exported);
- if (perm != PackageManager.PERMISSION_GRANTED) {
- if (!info.activityInfo.exported) {
- Slog.w(TAG, "Permission Denial: broadcasting "
- + r.intent.toString()
- + " from " + r.callerPackage + " (pid=" + r.callingPid
- + ", uid=" + r.callingUid + ")"
- + " is not exported from uid " + info.activityInfo.applicationInfo.uid
- + " due to receiver " + info.activityInfo.packageName
- + "/" + info.activityInfo.name);
- } else {
- Slog.w(TAG, "Permission Denial: broadcasting "
- + r.intent.toString()
- + " from " + r.callerPackage + " (pid=" + r.callingPid
- + ", uid=" + r.callingUid + ")"
- + " requires " + info.activityInfo.permission
- + " due to receiver " + info.activityInfo.packageName
- + "/" + info.activityInfo.name);
- }
- skip = true;
- }
- if (info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&
- r.requiredPermission != null) {
- try {
- perm = AppGlobals.getPackageManager().
- checkPermission(r.requiredPermission,
- info.activityInfo.applicationInfo.packageName);
- } catch (RemoteException e) {
- perm = PackageManager.PERMISSION_DENIED;
- }
- if (perm != PackageManager.PERMISSION_GRANTED) {
- Slog.w(TAG, "Permission Denial: receiving "
- + r.intent + " to "
- + info.activityInfo.applicationInfo.packageName
- + " requires " + r.requiredPermission
- + " due to sender " + r.callerPackage
- + " (uid " + r.callingUid + ")");
- skip = true;
- }
- }
- if (r.curApp != null && r.curApp.crashing) {
- // If the target process is crashing, just skip it.
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "Skipping deliver ordered ["
- + mQueueName + "] " + r + " to " + r.curApp
- + ": process crashing");
- skip = true;
- }
-
- if (skip) {
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "Skipping delivery of ordered ["
- + mQueueName + "] " + r + " for whatever reason");
- r.receiver = null;
- r.curFilter = null;
- r.state = BroadcastRecord.IDLE;
- scheduleBroadcastsLocked();
- return;
- }
-
- r.state = BroadcastRecord.APP_RECEIVE;
- String targetProcess = info.activityInfo.processName;
- r.curComponent = new ComponentName(
- info.activityInfo.applicationInfo.packageName,
- info.activityInfo.name);
- if (r.callingUid != Process.SYSTEM_UID) {
- info.activityInfo = getActivityInfoForUser(info.activityInfo, UserId
- .getUserId(r.callingUid));
- }
- r.curReceiver = info.activityInfo;
- if (DEBUG_MU && r.callingUid > UserId.PER_USER_RANGE) {
- Slog.v(TAG_MU, "Updated broadcast record activity info for secondary user, "
- + info.activityInfo + ", callingUid = " + r.callingUid + ", uid = "
- + info.activityInfo.applicationInfo.uid);
- }
-
- // Broadcast is being executed, its package can't be stopped.
- try {
- AppGlobals.getPackageManager().setPackageStoppedState(
- r.curComponent.getPackageName(), false);
- } catch (RemoteException e) {
- } catch (IllegalArgumentException e) {
- Slog.w(TAG, "Failed trying to unstop package "
- + r.curComponent.getPackageName() + ": " + e);
- }
-
- // Is this receiver's application already running?
- ProcessRecord app = getProcessRecordLocked(targetProcess,
- info.activityInfo.applicationInfo.uid);
- if (app != null && app.thread != null) {
- try {
- app.addPackage(info.activityInfo.packageName);
- processCurBroadcastLocked(r, app);
- return;
- } catch (RemoteException e) {
- Slog.w(TAG, "Exception when sending broadcast to "
- + r.curComponent, e);
- }
-
- // If a dead object exception was thrown -- fall through to
- // restart the application.
- }
-
- // Not running -- get it started, to be executed when the app comes up.
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "Need to start app ["
- + mQueueName + "] " + targetProcess + " for broadcast " + r);
- if ((r.curApp=startProcessLocked(targetProcess,
- info.activityInfo.applicationInfo, true,
- r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
- "broadcast", r.curComponent,
- (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false))
- == null) {
- // Ah, this recipient is unavailable. Finish it if necessary,
- // and mark the broadcast record as ready for the next.
- Slog.w(TAG, "Unable to launch app "
- + info.activityInfo.applicationInfo.packageName + "/"
- + info.activityInfo.applicationInfo.uid + " for broadcast "
- + r.intent + ": process is bad");
- logBroadcastReceiverDiscardLocked(r);
- finishReceiverLocked(r, r.resultCode, r.resultData,
- r.resultExtras, r.resultAbort, true);
- scheduleBroadcastsLocked();
- r.state = BroadcastRecord.IDLE;
- return;
- }
-
- mPendingBroadcast = r;
- mPendingBroadcastRecvIndex = recIdx;
- }
- }
-
- final void setBroadcastTimeoutLocked(long timeoutTime) {
- if (! mPendingBroadcastTimeoutMessage) {
- Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this);
- mHandler.sendMessageAtTime(msg, timeoutTime);
- mPendingBroadcastTimeoutMessage = true;
- }
- }
-
- final void cancelBroadcastTimeoutLocked() {
- if (mPendingBroadcastTimeoutMessage) {
- mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this);
- mPendingBroadcastTimeoutMessage = false;
- }
- }
-
- final void broadcastTimeoutLocked(boolean fromMsg) {
- if (fromMsg) {
- mPendingBroadcastTimeoutMessage = false;
- }
-
- if (mOrderedBroadcasts.size() == 0) {
- return;
- }
-
- long now = SystemClock.uptimeMillis();
- BroadcastRecord r = mOrderedBroadcasts.get(0);
- if (fromMsg) {
- if (mDidDexOpt) {
- // Delay timeouts until dexopt finishes.
- mDidDexOpt = false;
- long timeoutTime = SystemClock.uptimeMillis() + mTimeoutPeriod;
- setBroadcastTimeoutLocked(timeoutTime);
- return;
- }
- if (! mProcessesReady) {
- // Only process broadcast timeouts if the system is ready. That way
- // PRE_BOOT_COMPLETED broadcasts can't timeout as they are intended
- // to do heavy lifting for system up.
- return;
- }
-
- long timeoutTime = r.receiverTime + mTimeoutPeriod;
- if (timeoutTime > now) {
- // We can observe premature timeouts because we do not cancel and reset the
- // broadcast timeout message after each receiver finishes. Instead, we set up
- // an initial timeout then kick it down the road a little further as needed
- // when it expires.
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "Premature timeout ["
- + mQueueName + "] @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
- + timeoutTime);
- setBroadcastTimeoutLocked(timeoutTime);
- return;
- }
- }
-
- Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver
- + ", started " + (now - r.receiverTime) + "ms ago");
- r.receiverTime = now;
- r.anrCount++;
-
- // Current receiver has passed its expiration date.
- if (r.nextReceiver <= 0) {
- Slog.w(TAG, "Timeout on receiver with nextReceiver <= 0");
- return;
- }
-
- ProcessRecord app = null;
- String anrMessage = null;
-
- Object curReceiver = r.receivers.get(r.nextReceiver-1);
- Slog.w(TAG, "Receiver during timeout: " + curReceiver);
- logBroadcastReceiverDiscardLocked(r);
- if (curReceiver instanceof BroadcastFilter) {
- BroadcastFilter bf = (BroadcastFilter)curReceiver;
- if (bf.receiverList.pid != 0
- && bf.receiverList.pid != MY_PID) {
- synchronized (ActivityManagerService.this.mPidsSelfLocked) {
- app = ActivityManagerService.this.mPidsSelfLocked.get(
- bf.receiverList.pid);
- }
- }
- } else {
- app = r.curApp;
- }
-
- if (app != null) {
- anrMessage = "Broadcast of " + r.intent.toString();
- }
-
- if (mPendingBroadcast == r) {
- mPendingBroadcast = null;
- }
-
- // Move on to the next receiver.
- finishReceiverLocked(r, r.resultCode, r.resultData,
- r.resultExtras, r.resultAbort, true);
- scheduleBroadcastsLocked();
-
- if (anrMessage != null) {
- // Post the ANR to the handler since we do not want to process ANRs while
- // potentially holding our lock.
- mHandler.post(new AppNotResponding(app, anrMessage));
- }
- }
-
- private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
- if (r.callingUid < 0) {
- // This was from a registerReceiver() call; ignore it.
- return;
- }
- System.arraycopy(mBroadcastHistory, 0, mBroadcastHistory, 1,
- MAX_BROADCAST_HISTORY-1);
- r.finishTime = SystemClock.uptimeMillis();
- mBroadcastHistory[0] = r;
- }
-
- final void logBroadcastReceiverDiscardLocked(BroadcastRecord r) {
- if (r.nextReceiver > 0) {
- Object curReceiver = r.receivers.get(r.nextReceiver-1);
- if (curReceiver instanceof BroadcastFilter) {
- BroadcastFilter bf = (BroadcastFilter) curReceiver;
- EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_FILTER,
- System.identityHashCode(r),
- r.intent.getAction(),
- r.nextReceiver - 1,
- System.identityHashCode(bf));
- } else {
- EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
- System.identityHashCode(r),
- r.intent.getAction(),
- r.nextReceiver - 1,
- ((ResolveInfo)curReceiver).toString());
- }
- } else {
- Slog.w(TAG, "Discarding broadcast before first receiver is invoked: "
- + r);
- EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
- System.identityHashCode(r),
- r.intent.getAction(),
- r.nextReceiver,
- "NONE");
- }
- }
- final boolean dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
- int opti, boolean dumpAll, String dumpPackage, boolean needSep) {
- if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
- || mPendingBroadcast != null) {
- boolean printed = false;
- for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
- BroadcastRecord br = mParallelBroadcasts.get(i);
- if (dumpPackage != null && !dumpPackage.equals(br.callerPackage)) {
- continue;
- }
- if (!printed) {
- if (needSep) {
- pw.println();
- needSep = false;
- }
- printed = true;
- pw.println(" Active broadcasts [" + mQueueName + "]:");
- }
- pw.println(" Broadcast #" + i + ":");
- br.dump(pw, " ");
- }
- printed = false;
- needSep = true;
- for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
- BroadcastRecord br = mOrderedBroadcasts.get(i);
- if (dumpPackage != null && !dumpPackage.equals(br.callerPackage)) {
- continue;
- }
- if (!printed) {
- if (needSep) {
- pw.println();
- }
- needSep = true;
- pw.println(" Active ordered broadcasts [" + mQueueName + "]:");
- }
- pw.println(" Ordered Broadcast #" + i + ":");
- mOrderedBroadcasts.get(i).dump(pw, " ");
- }
- if (dumpPackage == null || (mPendingBroadcast != null
- && dumpPackage.equals(mPendingBroadcast.callerPackage))) {
- if (needSep) {
- pw.println();
- }
- pw.println(" Pending broadcast [" + mQueueName + "]:");
- if (mPendingBroadcast != null) {
- mPendingBroadcast.dump(pw, " ");
- } else {
- pw.println(" (null)");
- }
- needSep = true;
- }
- }
-
- boolean printed = false;
- for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
- BroadcastRecord r = mBroadcastHistory[i];
- if (r == null) {
- break;
- }
- if (dumpPackage != null && !dumpPackage.equals(r.callerPackage)) {
- continue;
- }
- if (!printed) {
- if (needSep) {
- pw.println();
- }
- needSep = true;
- pw.println(" Historical broadcasts [" + mQueueName + "]:");
- printed = true;
- }
- if (dumpAll) {
- pw.print(" Historical Broadcast #"); pw.print(i); pw.println(":");
- r.dump(pw, " ");
- } else {
- if (i >= 50) {
- pw.println(" ...");
- break;
- }
- pw.print(" #"); pw.print(i); pw.print(": "); pw.println(r);
- }
- }
-
- return needSep;
- }
- }
-
- final BroadcastQueue mFgBroadcastQueue = new BroadcastQueue("foreground", BROADCAST_FG_TIMEOUT);
- final BroadcastQueue mBgBroadcastQueue = new BroadcastQueue("background", BROADCAST_BG_TIMEOUT);
+ BroadcastQueue mFgBroadcastQueue;
+ BroadcastQueue mBgBroadcastQueue;
// Convenient for easy iteration over the queues. Foreground is first
// so that dispatch of foreground broadcasts gets precedence.
- final BroadcastQueue[] mBroadcastQueues = { mFgBroadcastQueue, mBgBroadcastQueue };
+ final BroadcastQueue[] mBroadcastQueues = new BroadcastQueue[2];
BroadcastQueue broadcastQueueForIntent(Intent intent) {
final boolean isFg = (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0;
@@ -1368,24 +568,6 @@ public final class ActivityManagerService extends ActivityManagerNative
*/
final ArrayList mCancelledThumbnails = new ArrayList();
- /**
- * All of the currently running global content providers. Keys are a
- * string containing the provider name and values are a
- * ContentProviderRecord object containing the data about it. Note
- * that a single provider may be published under multiple names, so
- * there may be multiple entries here for a single one in mProvidersByClass.
- */
- final HashMap<String, ContentProviderRecord> mProvidersByName
- = new HashMap<String, ContentProviderRecord>();
-
- /**
- * All of the currently running global content providers. Keys are a
- * string containing the provider's implementation class and values are a
- * ContentProviderRecord object containing the data about it.
- */
- final HashMap<ComponentName, ContentProviderRecord> mProvidersByClass
- = new HashMap<ComponentName, ContentProviderRecord>();
-
final ProviderMap mProviderMap = new ProviderMap();
/**
@@ -1642,8 +824,6 @@ public final class ActivityManagerService extends ActivityManagerNative
static final int UPDATE_CONFIGURATION_MSG = 4;
static final int GC_BACKGROUND_PROCESSES_MSG = 5;
static final int WAIT_FOR_DEBUGGER_MSG = 6;
- static final int BROADCAST_INTENT_MSG = 7;
- static final int BROADCAST_TIMEOUT_MSG = 8;
static final int SERVICE_TIMEOUT_MSG = 12;
static final int UPDATE_TIME_ZONE = 13;
static final int SHOW_UID_ERROR_MSG = 14;
@@ -1663,6 +843,10 @@ public final class ActivityManagerService extends ActivityManagerNative
static final int DISPATCH_PROCESS_DIED = 32;
static final int REPORT_MEM_USAGE = 33;
+ static final int FIRST_ACTIVITY_STACK_MSG = 100;
+ static final int FIRST_BROADCAST_QUEUE_MSG = 200;
+ static final int FIRST_COMPAT_MODE_MSG = 300;
+
AlertDialog mUidAlert;
CompatModeDialog mCompatModeDialog;
long mLastMemUsageReportTime = 0;
@@ -1782,18 +966,6 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
} break;
- case BROADCAST_INTENT_MSG: {
- if (DEBUG_BROADCAST) Slog.v(
- TAG, "Received BROADCAST_INTENT_MSG");
- BroadcastQueue queue = (BroadcastQueue) msg.obj;
- queue.processNextBroadcast(true);
- } break;
- case BROADCAST_TIMEOUT_MSG: {
- final BroadcastQueue queue = (BroadcastQueue) msg.obj;
- synchronized (ActivityManagerService.this) {
- queue.broadcastTimeoutLocked(true);
- }
- } break;
case SERVICE_TIMEOUT_MSG: {
if (mDidDexOpt) {
mDidDexOpt = false;
@@ -2307,6 +1479,11 @@ public final class ActivityManagerService extends ActivityManagerNative
private ActivityManagerService() {
Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
+ mFgBroadcastQueue = new BroadcastQueue(this, "foreground", BROADCAST_FG_TIMEOUT);
+ mBgBroadcastQueue = new BroadcastQueue(this, "background", BROADCAST_BG_TIMEOUT);
+ mBroadcastQueues[0] = mFgBroadcastQueue;
+ mBroadcastQueues[1] = mBgBroadcastQueue;
+
File dataDir = Environment.getDataDirectory();
File systemDir = new File(dataDir, "system");
systemDir.mkdirs();
@@ -3852,21 +3029,6 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- private final class AppNotResponding implements Runnable {
- private final ProcessRecord mApp;
- private final String mAnnotation;
-
- public AppNotResponding(ProcessRecord app, String annotation) {
- mApp = app;
- mAnnotation = annotation;
- }
-
- @Override
- public void run() {
- appNotResponding(mApp, null, null, mAnnotation);
- }
- }
-
final void appNotResponding(ProcessRecord app, ActivityRecord activity,
ActivityRecord parent, final String annotation) {
ArrayList<Integer> firstPids = new ArrayList<Integer>(5);
@@ -4445,7 +3607,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
ArrayList<ContentProviderRecord> providers = new ArrayList<ContentProviderRecord>();
- for (ContentProviderRecord provider : mProvidersByClass.values()) {
+ for (ContentProviderRecord provider : mProviderMap.getProvidersByClass(-1).values()) {
if (provider.info.packageName.equals(name)
&& (provider.proc == null || evenPersistent || !provider.proc.persistent)) {
if (!doit) {
@@ -11372,18 +10534,18 @@ public final class ActivityManagerService extends ActivityManagerNative
}
private ServiceLookupResult retrieveServiceLocked(Intent service,
- String resolvedType, int callingPid, int callingUid) {
+ String resolvedType, int callingPid, int callingUid, int userId) {
ServiceRecord r = null;
if (DEBUG_SERVICE)
Slog.v(TAG, "retrieveServiceLocked: " + service + " type=" + resolvedType
- + " origCallingUid=" + callingUid);
+ + " callingUid=" + callingUid);
if (service.getComponent() != null) {
- r = mServiceMap.getServiceByName(service.getComponent(), Binder.getOrigCallingUser());
+ r = mServiceMap.getServiceByName(service.getComponent(), userId);
}
if (r == null) {
Intent.FilterComparison filter = new Intent.FilterComparison(service);
- r = mServiceMap.getServiceByIntent(filter, Binder.getOrigCallingUser());
+ r = mServiceMap.getServiceByIntent(filter, userId);
}
if (r == null) {
try {
@@ -11397,13 +10559,12 @@ public final class ActivityManagerService extends ActivityManagerNative
": not found");
return null;
}
- if (Binder.getOrigCallingUser() > 0) {
- sInfo.applicationInfo = getAppInfoForUser(sInfo.applicationInfo,
- Binder.getOrigCallingUser());
+ if (userId > 0) {
+ sInfo.applicationInfo = getAppInfoForUser(sInfo.applicationInfo, userId);
}
ComponentName name = new ComponentName(
sInfo.applicationInfo.packageName, sInfo.name);
- r = mServiceMap.getServiceByName(name, Binder.getOrigCallingUser());
+ r = mServiceMap.getServiceByName(name, userId);
if (r == null) {
Intent.FilterComparison filter = new Intent.FilterComparison(
service.cloneFilter());
@@ -11967,7 +11128,7 @@ public final class ActivityManagerService extends ActivityManagerNative
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType,
- callingPid, callingUid);
+ callingPid, callingUid, UserId.getUserId(callingUid));
if (res == null) {
return null;
}
@@ -12217,13 +11378,15 @@ public final class ActivityManagerService extends ActivityManagerNative
public int bindService(IApplicationThread caller, IBinder token,
Intent service, String resolvedType,
- IServiceConnection connection, int flags) {
+ IServiceConnection connection, int flags, int userId) {
enforceNotIsolatedCaller("bindService");
// Refuse possible leaked file descriptors
if (service != null && service.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
+ checkValidCaller(Binder.getCallingUid(), userId);
+
synchronized(this) {
if (DEBUG_SERVICE) Slog.v(TAG, "bindService: " + service
+ " type=" + resolvedType + " conn=" + connection.asBinder()
@@ -12273,7 +11436,7 @@ public final class ActivityManagerService extends ActivityManagerNative
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType,
- Binder.getCallingPid(), Binder.getOrigCallingUid());
+ Binder.getCallingPid(), Binder.getCallingUid(), userId);
if (res == null) {
return 0;
}
@@ -13493,138 +12656,7 @@ public final class ActivityManagerService extends ActivityManagerNative
Binder.restoreCallingIdentity(origId);
}
}
-
- private final void processCurBroadcastLocked(BroadcastRecord r,
- ProcessRecord app) throws RemoteException {
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "Process cur broadcast " + r + " for app " + app);
- if (app.thread == null) {
- throw new RemoteException();
- }
- r.receiver = app.thread.asBinder();
- r.curApp = app;
- app.curReceiver = r;
- updateLruProcessLocked(app, true, true);
-
- // Tell the application to launch this receiver.
- r.intent.setComponent(r.curComponent);
-
- boolean started = false;
- try {
- if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG,
- "Delivering to component " + r.curComponent
- + ": " + r);
- ensurePackageDexOpt(r.intent.getComponent().getPackageName());
- app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
- compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
- r.resultCode, r.resultData, r.resultExtras, r.ordered);
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "Process cur broadcast " + r + " DELIVERED for app " + app);
- started = true;
- } finally {
- if (!started) {
- if (DEBUG_BROADCAST) Slog.v(TAG,
- "Process cur broadcast " + r + ": NOT STARTED!");
- r.receiver = null;
- r.curApp = null;
- app.curReceiver = null;
- }
- }
-
- }
-
- static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
- Intent intent, int resultCode, String data, Bundle extras,
- boolean ordered, boolean sticky) throws RemoteException {
- // Send the intent to the receiver asynchronously using one-way binder calls.
- if (app != null && app.thread != null) {
- // If we have an app thread, do the call through that so it is
- // correctly ordered with other one-way calls.
- app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
- data, extras, ordered, sticky);
- } else {
- receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);
- }
- }
- private final void deliverToRegisteredReceiverLocked(BroadcastRecord r,
- BroadcastFilter filter, boolean ordered) {
- boolean skip = false;
- if (filter.requiredPermission != null) {
- int perm = checkComponentPermission(filter.requiredPermission,
- r.callingPid, r.callingUid, -1, true);
- if (perm != PackageManager.PERMISSION_GRANTED) {
- Slog.w(TAG, "Permission Denial: broadcasting "
- + r.intent.toString()
- + " from " + r.callerPackage + " (pid="
- + r.callingPid + ", uid=" + r.callingUid + ")"
- + " requires " + filter.requiredPermission
- + " due to registered receiver " + filter);
- skip = true;
- }
- }
- if (r.requiredPermission != null) {
- int perm = checkComponentPermission(r.requiredPermission,
- filter.receiverList.pid, filter.receiverList.uid, -1, true);
- if (perm != PackageManager.PERMISSION_GRANTED) {
- Slog.w(TAG, "Permission Denial: receiving "
- + r.intent.toString()
- + " to " + filter.receiverList.app
- + " (pid=" + filter.receiverList.pid
- + ", uid=" + filter.receiverList.uid + ")"
- + " requires " + r.requiredPermission
- + " due to sender " + r.callerPackage
- + " (uid " + r.callingUid + ")");
- skip = true;
- }
- }
-
- if (!skip) {
- // If this is not being sent as an ordered broadcast, then we
- // don't want to touch the fields that keep track of the current
- // state of ordered broadcasts.
- if (ordered) {
- r.receiver = filter.receiverList.receiver.asBinder();
- r.curFilter = filter;
- filter.receiverList.curBroadcast = r;
- r.state = BroadcastRecord.CALL_IN_RECEIVE;
- if (filter.receiverList.app != null) {
- // Bump hosting application to no longer be in background
- // scheduling class. Note that we can't do that if there
- // isn't an app... but we can only be in that case for
- // things that directly call the IActivityManager API, which
- // are already core system stuff so don't matter for this.
- r.curApp = filter.receiverList.app;
- filter.receiverList.app.curReceiver = r;
- updateOomAdjLocked();
- }
- }
- try {
- if (DEBUG_BROADCAST_LIGHT) {
- int seq = r.intent.getIntExtra("seq", -1);
- Slog.i(TAG, "Delivering to " + filter
- + " (seq=" + seq + "): " + r);
- }
- performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
- new Intent(r.intent), r.resultCode,
- r.resultData, r.resultExtras, r.ordered, r.initialSticky);
- if (ordered) {
- r.state = BroadcastRecord.CALL_DONE_RECEIVE;
- }
- } catch (RemoteException e) {
- Slog.w(TAG, "Failure sending broadcast " + r.intent, e);
- if (ordered) {
- r.receiver = null;
- r.curFilter = null;
- filter.receiverList.curBroadcast = null;
- if (filter.receiverList.app != null) {
- filter.receiverList.app.curReceiver = null;
- }
- }
- }
- }
- }
-
// =========================================================
// INSTRUMENTATION
// =========================================================
@@ -15287,6 +14319,25 @@ public final class ActivityManagerService extends ActivityManagerNative
private int mCurrentUserId;
private SparseIntArray mLoggedInUsers = new SparseIntArray(5);
+ private ArrayList<UserListener> mUserListeners = new ArrayList<UserListener>(3);
+
+ public interface UserListener {
+ public void onUserChanged(int userId);
+
+ public void onUserAdded(int userId);
+
+ public void onUserRemoved(int userId);
+
+ public void onUserLoggedOut(int userId);
+ }
+
+ public void addUserListener(UserListener listener) {
+ synchronized (this) {
+ if (!mUserListeners.contains(listener)) {
+ mUserListeners.add(listener);
+ }
+ }
+ }
public boolean switchUser(int userId) {
final int callingUid = Binder.getCallingUid();
@@ -15297,6 +14348,8 @@ public final class ActivityManagerService extends ActivityManagerNative
if (mCurrentUserId == userId)
return true;
+ ArrayList<UserListener> listeners;
+
synchronized (this) {
// Check if user is already logged in, otherwise check if user exists first before
// adding to the list of logged in users.
@@ -15312,6 +14365,12 @@ public final class ActivityManagerService extends ActivityManagerNative
if (!haveActivities) {
startHomeActivityLocked(userId);
}
+
+ listeners = (ArrayList<UserListener>) mUserListeners.clone();
+ }
+ // Inform the listeners
+ for (UserListener listener : listeners) {
+ listener.onUserChanged(userId);
}
return true;
}
@@ -15331,6 +14390,12 @@ public final class ActivityManagerService extends ActivityManagerNative
return false;
}
+ private void checkValidCaller(int uid, int userId) {
+ if (UserId.getUserId(uid) == userId || uid == Process.SYSTEM_UID || uid == 0) return;
+
+ throw new SecurityException("Caller uid=" + uid
+ + " is not privileged to communicate with user=" + userId);
+ }
private int applyUserId(int uid, int userId) {
return UserId.getUid(userId, uid);
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index f59f0c1a9055..e8c8275f554a 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -283,13 +283,13 @@ final class ActivityStack {
private int mCurrentUser;
- static final int SLEEP_TIMEOUT_MSG = 8;
- static final int PAUSE_TIMEOUT_MSG = 9;
- static final int IDLE_TIMEOUT_MSG = 10;
- static final int IDLE_NOW_MSG = 11;
- static final int LAUNCH_TIMEOUT_MSG = 16;
- static final int DESTROY_TIMEOUT_MSG = 17;
- static final int RESUME_TOP_ACTIVITY_MSG = 19;
+ static final int SLEEP_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG;
+ static final int PAUSE_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 1;
+ static final int IDLE_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 2;
+ static final int IDLE_NOW_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 3;
+ static final int LAUNCH_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 4;
+ static final int DESTROY_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 5;
+ static final int RESUME_TOP_ACTIVITY_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 6;
final Handler mHandler = new Handler() {
//public Handler() {
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java
new file mode 100644
index 000000000000..39b63db08c6b
--- /dev/null
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -0,0 +1,1017 @@
+/*
+ * Copyright (C) 2012 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.am;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+import android.app.AppGlobals;
+import android.content.ComponentName;
+import android.content.IIntentReceiver;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.UserId;
+import android.util.EventLog;
+import android.util.Slog;
+
+/**
+ * BROADCASTS
+ *
+ * We keep two broadcast queues and associated bookkeeping, one for those at
+ * foreground priority, and one for normal (background-priority) broadcasts.
+ */
+public class BroadcastQueue {
+ static final String TAG = "BroadcastQueue";
+ static final String TAG_MU = ActivityManagerService.TAG_MU;
+ static final boolean DEBUG_BROADCAST = ActivityManagerService.DEBUG_BROADCAST;
+ static final boolean DEBUG_BROADCAST_LIGHT = ActivityManagerService.DEBUG_BROADCAST_LIGHT;
+ static final boolean DEBUG_MU = ActivityManagerService.DEBUG_MU;
+
+ static final int MAX_BROADCAST_HISTORY = 25;
+
+ final ActivityManagerService mService;
+
+ /**
+ * Recognizable moniker for this queue
+ */
+ final String mQueueName;
+
+ /**
+ * Timeout period for this queue's broadcasts
+ */
+ final long mTimeoutPeriod;
+
+ /**
+ * Lists of all active broadcasts that are to be executed immediately
+ * (without waiting for another broadcast to finish). Currently this only
+ * contains broadcasts to registered receivers, to avoid spinning up
+ * a bunch of processes to execute IntentReceiver components. Background-
+ * and foreground-priority broadcasts are queued separately.
+ */
+ final ArrayList<BroadcastRecord> mParallelBroadcasts
+ = new ArrayList<BroadcastRecord>();
+ /**
+ * List of all active broadcasts that are to be executed one at a time.
+ * The object at the top of the list is the currently activity broadcasts;
+ * those after it are waiting for the top to finish. As with parallel
+ * broadcasts, separate background- and foreground-priority queues are
+ * maintained.
+ */
+ final ArrayList<BroadcastRecord> mOrderedBroadcasts
+ = new ArrayList<BroadcastRecord>();
+
+ /**
+ * Historical data of past broadcasts, for debugging.
+ */
+ final BroadcastRecord[] mBroadcastHistory
+ = new BroadcastRecord[MAX_BROADCAST_HISTORY];
+
+ /**
+ * Set when we current have a BROADCAST_INTENT_MSG in flight.
+ */
+ boolean mBroadcastsScheduled = false;
+
+ /**
+ * True if we have a pending unexpired BROADCAST_TIMEOUT_MSG posted to our handler.
+ */
+ boolean mPendingBroadcastTimeoutMessage;
+
+ /**
+ * Intent broadcasts that we have tried to start, but are
+ * waiting for the application's process to be created. We only
+ * need one per scheduling class (instead of a list) because we always
+ * process broadcasts one at a time, so no others can be started while
+ * waiting for this one.
+ */
+ BroadcastRecord mPendingBroadcast = null;
+
+ /**
+ * The receiver index that is pending, to restart the broadcast if needed.
+ */
+ int mPendingBroadcastRecvIndex;
+
+ static final int BROADCAST_INTENT_MSG = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG;
+ static final int BROADCAST_TIMEOUT_MSG = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG + 1;
+
+ final Handler mHandler = new Handler() {
+ //public Handler() {
+ // if (localLOGV) Slog.v(TAG, "Handler started!");
+ //}
+
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case BROADCAST_INTENT_MSG: {
+ if (DEBUG_BROADCAST) Slog.v(
+ TAG, "Received BROADCAST_INTENT_MSG");
+ processNextBroadcast(true);
+ } break;
+ case BROADCAST_TIMEOUT_MSG: {
+ synchronized (mService) {
+ broadcastTimeoutLocked(true);
+ }
+ } break;
+ }
+ }
+ };
+
+ private final class AppNotResponding implements Runnable {
+ private final ProcessRecord mApp;
+ private final String mAnnotation;
+
+ public AppNotResponding(ProcessRecord app, String annotation) {
+ mApp = app;
+ mAnnotation = annotation;
+ }
+
+ @Override
+ public void run() {
+ mService.appNotResponding(mApp, null, null, mAnnotation);
+ }
+ }
+
+ BroadcastQueue(ActivityManagerService service, String name, long timeoutPeriod) {
+ mService = service;
+ mQueueName = name;
+ mTimeoutPeriod = timeoutPeriod;
+ }
+
+ public boolean isPendingBroadcastProcessLocked(int pid) {
+ return mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid;
+ }
+
+ public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
+ mParallelBroadcasts.add(r);
+ }
+
+ public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
+ mOrderedBroadcasts.add(r);
+ }
+
+ public final boolean replaceParallelBroadcastLocked(BroadcastRecord r) {
+ for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
+ if (r.intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "***** DROPPING PARALLEL ["
+ + mQueueName + "]: " + r.intent);
+ mParallelBroadcasts.set(i, r);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public final boolean replaceOrderedBroadcastLocked(BroadcastRecord r) {
+ for (int i=mOrderedBroadcasts.size()-1; i>0; i--) {
+ if (r.intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "***** DROPPING ORDERED ["
+ + mQueueName + "]: " + r.intent);
+ mOrderedBroadcasts.set(i, r);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private final void processCurBroadcastLocked(BroadcastRecord r,
+ ProcessRecord app) throws RemoteException {
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "Process cur broadcast " + r + " for app " + app);
+ if (app.thread == null) {
+ throw new RemoteException();
+ }
+ r.receiver = app.thread.asBinder();
+ r.curApp = app;
+ app.curReceiver = r;
+ mService.updateLruProcessLocked(app, true, true);
+
+ // Tell the application to launch this receiver.
+ r.intent.setComponent(r.curComponent);
+
+ boolean started = false;
+ try {
+ if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG,
+ "Delivering to component " + r.curComponent
+ + ": " + r);
+ mService.ensurePackageDexOpt(r.intent.getComponent().getPackageName());
+ app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
+ mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
+ r.resultCode, r.resultData, r.resultExtras, r.ordered);
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "Process cur broadcast " + r + " DELIVERED for app " + app);
+ started = true;
+ } finally {
+ if (!started) {
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "Process cur broadcast " + r + ": NOT STARTED!");
+ r.receiver = null;
+ r.curApp = null;
+ app.curReceiver = null;
+ }
+ }
+ }
+
+ public boolean sendPendingBroadcastsLocked(ProcessRecord app) {
+ boolean didSomething = false;
+ final BroadcastRecord br = mPendingBroadcast;
+ if (br != null && br.curApp.pid == app.pid) {
+ try {
+ mPendingBroadcast = null;
+ processCurBroadcastLocked(br, app);
+ didSomething = true;
+ } catch (Exception e) {
+ Slog.w(TAG, "Exception in new application when starting receiver "
+ + br.curComponent.flattenToShortString(), e);
+ logBroadcastReceiverDiscardLocked(br);
+ finishReceiverLocked(br, br.resultCode, br.resultData,
+ br.resultExtras, br.resultAbort, true);
+ scheduleBroadcastsLocked();
+ // We need to reset the state if we fails to start the receiver.
+ br.state = BroadcastRecord.IDLE;
+ throw new RuntimeException(e.getMessage());
+ }
+ }
+ return didSomething;
+ }
+
+ public void skipPendingBroadcastLocked(int pid) {
+ final BroadcastRecord br = mPendingBroadcast;
+ if (br != null && br.curApp.pid == pid) {
+ br.state = BroadcastRecord.IDLE;
+ br.nextReceiver = mPendingBroadcastRecvIndex;
+ mPendingBroadcast = null;
+ scheduleBroadcastsLocked();
+ }
+ }
+
+ public void skipCurrentReceiverLocked(ProcessRecord app) {
+ boolean reschedule = false;
+ BroadcastRecord r = app.curReceiver;
+ if (r != null) {
+ // The current broadcast is waiting for this app's receiver
+ // to be finished. Looks like that's not going to happen, so
+ // let the broadcast continue.
+ logBroadcastReceiverDiscardLocked(r);
+ finishReceiverLocked(r, r.resultCode, r.resultData,
+ r.resultExtras, r.resultAbort, true);
+ reschedule = true;
+ }
+
+ r = mPendingBroadcast;
+ if (r != null && r.curApp == app) {
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "[" + mQueueName + "] skip & discard pending app " + r);
+ logBroadcastReceiverDiscardLocked(r);
+ finishReceiverLocked(r, r.resultCode, r.resultData,
+ r.resultExtras, r.resultAbort, true);
+ reschedule = true;
+ }
+ if (reschedule) {
+ scheduleBroadcastsLocked();
+ }
+ }
+
+ public void scheduleBroadcastsLocked() {
+ if (DEBUG_BROADCAST) Slog.v(TAG, "Schedule broadcasts ["
+ + mQueueName + "]: current="
+ + mBroadcastsScheduled);
+
+ if (mBroadcastsScheduled) {
+ return;
+ }
+ mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
+ mBroadcastsScheduled = true;
+ }
+
+ public BroadcastRecord getMatchingOrderedReceiver(IBinder receiver) {
+ if (mOrderedBroadcasts.size() > 0) {
+ final BroadcastRecord r = mOrderedBroadcasts.get(0);
+ if (r != null && r.receiver == receiver) {
+ return r;
+ }
+ }
+ return null;
+ }
+
+ public boolean finishReceiverLocked(BroadcastRecord r, int resultCode,
+ String resultData, Bundle resultExtras, boolean resultAbort,
+ boolean explicit) {
+ int state = r.state;
+ r.state = BroadcastRecord.IDLE;
+ if (state == BroadcastRecord.IDLE) {
+ if (explicit) {
+ Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE");
+ }
+ }
+ r.receiver = null;
+ r.intent.setComponent(null);
+ if (r.curApp != null) {
+ r.curApp.curReceiver = null;
+ }
+ if (r.curFilter != null) {
+ r.curFilter.receiverList.curBroadcast = null;
+ }
+ r.curFilter = null;
+ r.curApp = null;
+ r.curComponent = null;
+ r.curReceiver = null;
+ mPendingBroadcast = null;
+
+ r.resultCode = resultCode;
+ r.resultData = resultData;
+ r.resultExtras = resultExtras;
+ r.resultAbort = resultAbort;
+
+ // We will process the next receiver right now if this is finishing
+ // an app receiver (which is always asynchronous) or after we have
+ // come back from calling a receiver.
+ return state == BroadcastRecord.APP_RECEIVE
+ || state == BroadcastRecord.CALL_DONE_RECEIVE;
+ }
+
+ private static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
+ Intent intent, int resultCode, String data, Bundle extras,
+ boolean ordered, boolean sticky) throws RemoteException {
+ // Send the intent to the receiver asynchronously using one-way binder calls.
+ if (app != null && app.thread != null) {
+ // If we have an app thread, do the call through that so it is
+ // correctly ordered with other one-way calls.
+ app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
+ data, extras, ordered, sticky);
+ } else {
+ receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);
+ }
+ }
+
+ private final void deliverToRegisteredReceiverLocked(BroadcastRecord r,
+ BroadcastFilter filter, boolean ordered) {
+ boolean skip = false;
+ if (filter.requiredPermission != null) {
+ int perm = mService.checkComponentPermission(filter.requiredPermission,
+ r.callingPid, r.callingUid, -1, true);
+ if (perm != PackageManager.PERMISSION_GRANTED) {
+ Slog.w(TAG, "Permission Denial: broadcasting "
+ + r.intent.toString()
+ + " from " + r.callerPackage + " (pid="
+ + r.callingPid + ", uid=" + r.callingUid + ")"
+ + " requires " + filter.requiredPermission
+ + " due to registered receiver " + filter);
+ skip = true;
+ }
+ }
+ if (r.requiredPermission != null) {
+ int perm = mService.checkComponentPermission(r.requiredPermission,
+ filter.receiverList.pid, filter.receiverList.uid, -1, true);
+ if (perm != PackageManager.PERMISSION_GRANTED) {
+ Slog.w(TAG, "Permission Denial: receiving "
+ + r.intent.toString()
+ + " to " + filter.receiverList.app
+ + " (pid=" + filter.receiverList.pid
+ + ", uid=" + filter.receiverList.uid + ")"
+ + " requires " + r.requiredPermission
+ + " due to sender " + r.callerPackage
+ + " (uid " + r.callingUid + ")");
+ skip = true;
+ }
+ }
+
+ if (!skip) {
+ // If this is not being sent as an ordered broadcast, then we
+ // don't want to touch the fields that keep track of the current
+ // state of ordered broadcasts.
+ if (ordered) {
+ r.receiver = filter.receiverList.receiver.asBinder();
+ r.curFilter = filter;
+ filter.receiverList.curBroadcast = r;
+ r.state = BroadcastRecord.CALL_IN_RECEIVE;
+ if (filter.receiverList.app != null) {
+ // Bump hosting application to no longer be in background
+ // scheduling class. Note that we can't do that if there
+ // isn't an app... but we can only be in that case for
+ // things that directly call the IActivityManager API, which
+ // are already core system stuff so don't matter for this.
+ r.curApp = filter.receiverList.app;
+ filter.receiverList.app.curReceiver = r;
+ mService.updateOomAdjLocked();
+ }
+ }
+ try {
+ if (DEBUG_BROADCAST_LIGHT) {
+ int seq = r.intent.getIntExtra("seq", -1);
+ Slog.i(TAG, "Delivering to " + filter
+ + " (seq=" + seq + "): " + r);
+ }
+ performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
+ new Intent(r.intent), r.resultCode,
+ r.resultData, r.resultExtras, r.ordered, r.initialSticky);
+ if (ordered) {
+ r.state = BroadcastRecord.CALL_DONE_RECEIVE;
+ }
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failure sending broadcast " + r.intent, e);
+ if (ordered) {
+ r.receiver = null;
+ r.curFilter = null;
+ filter.receiverList.curBroadcast = null;
+ if (filter.receiverList.app != null) {
+ filter.receiverList.app.curReceiver = null;
+ }
+ }
+ }
+ }
+ }
+
+ final void processNextBroadcast(boolean fromMsg) {
+ synchronized(mService) {
+ BroadcastRecord r;
+
+ if (DEBUG_BROADCAST) Slog.v(TAG, "processNextBroadcast ["
+ + mQueueName + "]: "
+ + mParallelBroadcasts.size() + " broadcasts, "
+ + mOrderedBroadcasts.size() + " ordered broadcasts");
+
+ mService.updateCpuStats();
+
+ if (fromMsg) {
+ mBroadcastsScheduled = false;
+ }
+
+ // First, deliver any non-serialized broadcasts right away.
+ while (mParallelBroadcasts.size() > 0) {
+ r = mParallelBroadcasts.remove(0);
+ r.dispatchTime = SystemClock.uptimeMillis();
+ r.dispatchClockTime = System.currentTimeMillis();
+ final int N = r.receivers.size();
+ if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing parallel broadcast ["
+ + mQueueName + "] " + r);
+ for (int i=0; i<N; i++) {
+ Object target = r.receivers.get(i);
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "Delivering non-ordered on [" + mQueueName + "] to registered "
+ + target + ": " + r);
+ deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
+ }
+ addBroadcastToHistoryLocked(r);
+ if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Done with parallel broadcast ["
+ + mQueueName + "] " + r);
+ }
+
+ // Now take care of the next serialized one...
+
+ // If we are waiting for a process to come up to handle the next
+ // broadcast, then do nothing at this point. Just in case, we
+ // check that the process we're waiting for still exists.
+ if (mPendingBroadcast != null) {
+ if (DEBUG_BROADCAST_LIGHT) {
+ Slog.v(TAG, "processNextBroadcast ["
+ + mQueueName + "]: waiting for "
+ + mPendingBroadcast.curApp);
+ }
+
+ boolean isDead;
+ synchronized (mService.mPidsSelfLocked) {
+ isDead = (mService.mPidsSelfLocked.get(
+ mPendingBroadcast.curApp.pid) == null);
+ }
+ if (!isDead) {
+ // It's still alive, so keep waiting
+ return;
+ } else {
+ Slog.w(TAG, "pending app ["
+ + mQueueName + "]" + mPendingBroadcast.curApp
+ + " died before responding to broadcast");
+ mPendingBroadcast.state = BroadcastRecord.IDLE;
+ mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
+ mPendingBroadcast = null;
+ }
+ }
+
+ boolean looped = false;
+
+ do {
+ if (mOrderedBroadcasts.size() == 0) {
+ // No more broadcasts pending, so all done!
+ mService.scheduleAppGcsLocked();
+ if (looped) {
+ // If we had finished the last ordered broadcast, then
+ // make sure all processes have correct oom and sched
+ // adjustments.
+ mService.updateOomAdjLocked();
+ }
+ return;
+ }
+ r = mOrderedBroadcasts.get(0);
+ boolean forceReceive = false;
+
+ // Ensure that even if something goes awry with the timeout
+ // detection, we catch "hung" broadcasts here, discard them,
+ // and continue to make progress.
+ //
+ // This is only done if the system is ready so that PRE_BOOT_COMPLETED
+ // receivers don't get executed with timeouts. They're intended for
+ // one time heavy lifting after system upgrades and can take
+ // significant amounts of time.
+ int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
+ if (mService.mProcessesReady && r.dispatchTime > 0) {
+ long now = SystemClock.uptimeMillis();
+ if ((numReceivers > 0) &&
+ (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
+ Slog.w(TAG, "Hung broadcast ["
+ + mQueueName + "] discarded after timeout failure:"
+ + " now=" + now
+ + " dispatchTime=" + r.dispatchTime
+ + " startTime=" + r.receiverTime
+ + " intent=" + r.intent
+ + " numReceivers=" + numReceivers
+ + " nextReceiver=" + r.nextReceiver
+ + " state=" + r.state);
+ broadcastTimeoutLocked(false); // forcibly finish this broadcast
+ forceReceive = true;
+ r.state = BroadcastRecord.IDLE;
+ }
+ }
+
+ if (r.state != BroadcastRecord.IDLE) {
+ if (DEBUG_BROADCAST) Slog.d(TAG,
+ "processNextBroadcast("
+ + mQueueName + ") called when not idle (state="
+ + r.state + ")");
+ return;
+ }
+
+ if (r.receivers == null || r.nextReceiver >= numReceivers
+ || r.resultAbort || forceReceive) {
+ // No more receivers for this broadcast! Send the final
+ // result if requested...
+ if (r.resultTo != null) {
+ try {
+ if (DEBUG_BROADCAST) {
+ int seq = r.intent.getIntExtra("seq", -1);
+ Slog.i(TAG, "Finishing broadcast ["
+ + mQueueName + "] " + r.intent.getAction()
+ + " seq=" + seq + " app=" + r.callerApp);
+ }
+ performReceiveLocked(r.callerApp, r.resultTo,
+ new Intent(r.intent), r.resultCode,
+ r.resultData, r.resultExtras, false, false);
+ // Set this to null so that the reference
+ // (local and remote) isnt kept in the mBroadcastHistory.
+ r.resultTo = null;
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failure ["
+ + mQueueName + "] sending broadcast result of "
+ + r.intent, e);
+ }
+ }
+
+ if (DEBUG_BROADCAST) Slog.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
+ cancelBroadcastTimeoutLocked();
+
+ if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Finished with ordered broadcast "
+ + r);
+
+ // ... and on to the next...
+ addBroadcastToHistoryLocked(r);
+ mOrderedBroadcasts.remove(0);
+ r = null;
+ looped = true;
+ continue;
+ }
+ } while (r == null);
+
+ // Get the next receiver...
+ int recIdx = r.nextReceiver++;
+
+ // Keep track of when this receiver started, and make sure there
+ // is a timeout message pending to kill it if need be.
+ r.receiverTime = SystemClock.uptimeMillis();
+ if (recIdx == 0) {
+ r.dispatchTime = r.receiverTime;
+ r.dispatchClockTime = System.currentTimeMillis();
+ if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG, "Processing ordered broadcast ["
+ + mQueueName + "] " + r);
+ }
+ if (! mPendingBroadcastTimeoutMessage) {
+ long timeoutTime = r.receiverTime + mTimeoutPeriod;
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "Submitting BROADCAST_TIMEOUT_MSG ["
+ + mQueueName + "] for " + r + " at " + timeoutTime);
+ setBroadcastTimeoutLocked(timeoutTime);
+ }
+
+ Object nextReceiver = r.receivers.get(recIdx);
+ if (nextReceiver instanceof BroadcastFilter) {
+ // Simple case: this is a registered receiver who gets
+ // a direct call.
+ BroadcastFilter filter = (BroadcastFilter)nextReceiver;
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "Delivering ordered ["
+ + mQueueName + "] to registered "
+ + filter + ": " + r);
+ deliverToRegisteredReceiverLocked(r, filter, r.ordered);
+ if (r.receiver == null || !r.ordered) {
+ // The receiver has already finished, so schedule to
+ // process the next one.
+ if (DEBUG_BROADCAST) Slog.v(TAG, "Quick finishing ["
+ + mQueueName + "]: ordered="
+ + r.ordered + " receiver=" + r.receiver);
+ r.state = BroadcastRecord.IDLE;
+ scheduleBroadcastsLocked();
+ }
+ return;
+ }
+
+ // Hard case: need to instantiate the receiver, possibly
+ // starting its application process to host it.
+
+ ResolveInfo info =
+ (ResolveInfo)nextReceiver;
+
+ boolean skip = false;
+ int perm = mService.checkComponentPermission(info.activityInfo.permission,
+ r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid,
+ info.activityInfo.exported);
+ if (perm != PackageManager.PERMISSION_GRANTED) {
+ if (!info.activityInfo.exported) {
+ Slog.w(TAG, "Permission Denial: broadcasting "
+ + r.intent.toString()
+ + " from " + r.callerPackage + " (pid=" + r.callingPid
+ + ", uid=" + r.callingUid + ")"
+ + " is not exported from uid " + info.activityInfo.applicationInfo.uid
+ + " due to receiver " + info.activityInfo.packageName
+ + "/" + info.activityInfo.name);
+ } else {
+ Slog.w(TAG, "Permission Denial: broadcasting "
+ + r.intent.toString()
+ + " from " + r.callerPackage + " (pid=" + r.callingPid
+ + ", uid=" + r.callingUid + ")"
+ + " requires " + info.activityInfo.permission
+ + " due to receiver " + info.activityInfo.packageName
+ + "/" + info.activityInfo.name);
+ }
+ skip = true;
+ }
+ if (info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&
+ r.requiredPermission != null) {
+ try {
+ perm = AppGlobals.getPackageManager().
+ checkPermission(r.requiredPermission,
+ info.activityInfo.applicationInfo.packageName);
+ } catch (RemoteException e) {
+ perm = PackageManager.PERMISSION_DENIED;
+ }
+ if (perm != PackageManager.PERMISSION_GRANTED) {
+ Slog.w(TAG, "Permission Denial: receiving "
+ + r.intent + " to "
+ + info.activityInfo.applicationInfo.packageName
+ + " requires " + r.requiredPermission
+ + " due to sender " + r.callerPackage
+ + " (uid " + r.callingUid + ")");
+ skip = true;
+ }
+ }
+ if (r.curApp != null && r.curApp.crashing) {
+ // If the target process is crashing, just skip it.
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "Skipping deliver ordered ["
+ + mQueueName + "] " + r + " to " + r.curApp
+ + ": process crashing");
+ skip = true;
+ }
+
+ if (skip) {
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "Skipping delivery of ordered ["
+ + mQueueName + "] " + r + " for whatever reason");
+ r.receiver = null;
+ r.curFilter = null;
+ r.state = BroadcastRecord.IDLE;
+ scheduleBroadcastsLocked();
+ return;
+ }
+
+ r.state = BroadcastRecord.APP_RECEIVE;
+ String targetProcess = info.activityInfo.processName;
+ r.curComponent = new ComponentName(
+ info.activityInfo.applicationInfo.packageName,
+ info.activityInfo.name);
+ if (r.callingUid != Process.SYSTEM_UID) {
+ info.activityInfo = mService.getActivityInfoForUser(info.activityInfo, UserId
+ .getUserId(r.callingUid));
+ }
+ r.curReceiver = info.activityInfo;
+ if (DEBUG_MU && r.callingUid > UserId.PER_USER_RANGE) {
+ Slog.v(TAG_MU, "Updated broadcast record activity info for secondary user, "
+ + info.activityInfo + ", callingUid = " + r.callingUid + ", uid = "
+ + info.activityInfo.applicationInfo.uid);
+ }
+
+ // Broadcast is being executed, its package can't be stopped.
+ try {
+ AppGlobals.getPackageManager().setPackageStoppedState(
+ r.curComponent.getPackageName(), false);
+ } catch (RemoteException e) {
+ } catch (IllegalArgumentException e) {
+ Slog.w(TAG, "Failed trying to unstop package "
+ + r.curComponent.getPackageName() + ": " + e);
+ }
+
+ // Is this receiver's application already running?
+ ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
+ info.activityInfo.applicationInfo.uid);
+ if (app != null && app.thread != null) {
+ try {
+ app.addPackage(info.activityInfo.packageName);
+ processCurBroadcastLocked(r, app);
+ return;
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Exception when sending broadcast to "
+ + r.curComponent, e);
+ }
+
+ // If a dead object exception was thrown -- fall through to
+ // restart the application.
+ }
+
+ // Not running -- get it started, to be executed when the app comes up.
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "Need to start app ["
+ + mQueueName + "] " + targetProcess + " for broadcast " + r);
+ if ((r.curApp=mService.startProcessLocked(targetProcess,
+ info.activityInfo.applicationInfo, true,
+ r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
+ "broadcast", r.curComponent,
+ (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false))
+ == null) {
+ // Ah, this recipient is unavailable. Finish it if necessary,
+ // and mark the broadcast record as ready for the next.
+ Slog.w(TAG, "Unable to launch app "
+ + info.activityInfo.applicationInfo.packageName + "/"
+ + info.activityInfo.applicationInfo.uid + " for broadcast "
+ + r.intent + ": process is bad");
+ logBroadcastReceiverDiscardLocked(r);
+ finishReceiverLocked(r, r.resultCode, r.resultData,
+ r.resultExtras, r.resultAbort, true);
+ scheduleBroadcastsLocked();
+ r.state = BroadcastRecord.IDLE;
+ return;
+ }
+
+ mPendingBroadcast = r;
+ mPendingBroadcastRecvIndex = recIdx;
+ }
+ }
+
+ final void setBroadcastTimeoutLocked(long timeoutTime) {
+ if (! mPendingBroadcastTimeoutMessage) {
+ Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this);
+ mHandler.sendMessageAtTime(msg, timeoutTime);
+ mPendingBroadcastTimeoutMessage = true;
+ }
+ }
+
+ final void cancelBroadcastTimeoutLocked() {
+ if (mPendingBroadcastTimeoutMessage) {
+ mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this);
+ mPendingBroadcastTimeoutMessage = false;
+ }
+ }
+
+ final void broadcastTimeoutLocked(boolean fromMsg) {
+ if (fromMsg) {
+ mPendingBroadcastTimeoutMessage = false;
+ }
+
+ if (mOrderedBroadcasts.size() == 0) {
+ return;
+ }
+
+ long now = SystemClock.uptimeMillis();
+ BroadcastRecord r = mOrderedBroadcasts.get(0);
+ if (fromMsg) {
+ if (mService.mDidDexOpt) {
+ // Delay timeouts until dexopt finishes.
+ mService.mDidDexOpt = false;
+ long timeoutTime = SystemClock.uptimeMillis() + mTimeoutPeriod;
+ setBroadcastTimeoutLocked(timeoutTime);
+ return;
+ }
+ if (!mService.mProcessesReady) {
+ // Only process broadcast timeouts if the system is ready. That way
+ // PRE_BOOT_COMPLETED broadcasts can't timeout as they are intended
+ // to do heavy lifting for system up.
+ return;
+ }
+
+ long timeoutTime = r.receiverTime + mTimeoutPeriod;
+ if (timeoutTime > now) {
+ // We can observe premature timeouts because we do not cancel and reset the
+ // broadcast timeout message after each receiver finishes. Instead, we set up
+ // an initial timeout then kick it down the road a little further as needed
+ // when it expires.
+ if (DEBUG_BROADCAST) Slog.v(TAG,
+ "Premature timeout ["
+ + mQueueName + "] @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
+ + timeoutTime);
+ setBroadcastTimeoutLocked(timeoutTime);
+ return;
+ }
+ }
+
+ Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver
+ + ", started " + (now - r.receiverTime) + "ms ago");
+ r.receiverTime = now;
+ r.anrCount++;
+
+ // Current receiver has passed its expiration date.
+ if (r.nextReceiver <= 0) {
+ Slog.w(TAG, "Timeout on receiver with nextReceiver <= 0");
+ return;
+ }
+
+ ProcessRecord app = null;
+ String anrMessage = null;
+
+ Object curReceiver = r.receivers.get(r.nextReceiver-1);
+ Slog.w(TAG, "Receiver during timeout: " + curReceiver);
+ logBroadcastReceiverDiscardLocked(r);
+ if (curReceiver instanceof BroadcastFilter) {
+ BroadcastFilter bf = (BroadcastFilter)curReceiver;
+ if (bf.receiverList.pid != 0
+ && bf.receiverList.pid != ActivityManagerService.MY_PID) {
+ synchronized (mService.mPidsSelfLocked) {
+ app = mService.mPidsSelfLocked.get(
+ bf.receiverList.pid);
+ }
+ }
+ } else {
+ app = r.curApp;
+ }
+
+ if (app != null) {
+ anrMessage = "Broadcast of " + r.intent.toString();
+ }
+
+ if (mPendingBroadcast == r) {
+ mPendingBroadcast = null;
+ }
+
+ // Move on to the next receiver.
+ finishReceiverLocked(r, r.resultCode, r.resultData,
+ r.resultExtras, r.resultAbort, true);
+ scheduleBroadcastsLocked();
+
+ if (anrMessage != null) {
+ // Post the ANR to the handler since we do not want to process ANRs while
+ // potentially holding our lock.
+ mHandler.post(new AppNotResponding(app, anrMessage));
+ }
+ }
+
+ private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
+ if (r.callingUid < 0) {
+ // This was from a registerReceiver() call; ignore it.
+ return;
+ }
+ System.arraycopy(mBroadcastHistory, 0, mBroadcastHistory, 1,
+ MAX_BROADCAST_HISTORY-1);
+ r.finishTime = SystemClock.uptimeMillis();
+ mBroadcastHistory[0] = r;
+ }
+
+ final void logBroadcastReceiverDiscardLocked(BroadcastRecord r) {
+ if (r.nextReceiver > 0) {
+ Object curReceiver = r.receivers.get(r.nextReceiver-1);
+ if (curReceiver instanceof BroadcastFilter) {
+ BroadcastFilter bf = (BroadcastFilter) curReceiver;
+ EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_FILTER,
+ System.identityHashCode(r),
+ r.intent.getAction(),
+ r.nextReceiver - 1,
+ System.identityHashCode(bf));
+ } else {
+ EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
+ System.identityHashCode(r),
+ r.intent.getAction(),
+ r.nextReceiver - 1,
+ ((ResolveInfo)curReceiver).toString());
+ }
+ } else {
+ Slog.w(TAG, "Discarding broadcast before first receiver is invoked: "
+ + r);
+ EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
+ System.identityHashCode(r),
+ r.intent.getAction(),
+ r.nextReceiver,
+ "NONE");
+ }
+ }
+
+ final boolean dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
+ int opti, boolean dumpAll, String dumpPackage, boolean needSep) {
+ if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
+ || mPendingBroadcast != null) {
+ boolean printed = false;
+ for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
+ BroadcastRecord br = mParallelBroadcasts.get(i);
+ if (dumpPackage != null && !dumpPackage.equals(br.callerPackage)) {
+ continue;
+ }
+ if (!printed) {
+ if (needSep) {
+ pw.println();
+ needSep = false;
+ }
+ printed = true;
+ pw.println(" Active broadcasts [" + mQueueName + "]:");
+ }
+ pw.println(" Broadcast #" + i + ":");
+ br.dump(pw, " ");
+ }
+ printed = false;
+ needSep = true;
+ for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
+ BroadcastRecord br = mOrderedBroadcasts.get(i);
+ if (dumpPackage != null && !dumpPackage.equals(br.callerPackage)) {
+ continue;
+ }
+ if (!printed) {
+ if (needSep) {
+ pw.println();
+ }
+ needSep = true;
+ pw.println(" Active ordered broadcasts [" + mQueueName + "]:");
+ }
+ pw.println(" Ordered Broadcast #" + i + ":");
+ mOrderedBroadcasts.get(i).dump(pw, " ");
+ }
+ if (dumpPackage == null || (mPendingBroadcast != null
+ && dumpPackage.equals(mPendingBroadcast.callerPackage))) {
+ if (needSep) {
+ pw.println();
+ }
+ pw.println(" Pending broadcast [" + mQueueName + "]:");
+ if (mPendingBroadcast != null) {
+ mPendingBroadcast.dump(pw, " ");
+ } else {
+ pw.println(" (null)");
+ }
+ needSep = true;
+ }
+ }
+
+ boolean printed = false;
+ for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
+ BroadcastRecord r = mBroadcastHistory[i];
+ if (r == null) {
+ break;
+ }
+ if (dumpPackage != null && !dumpPackage.equals(r.callerPackage)) {
+ continue;
+ }
+ if (!printed) {
+ if (needSep) {
+ pw.println();
+ }
+ needSep = true;
+ pw.println(" Historical broadcasts [" + mQueueName + "]:");
+ printed = true;
+ }
+ if (dumpAll) {
+ pw.print(" Historical Broadcast #"); pw.print(i); pw.println(":");
+ r.dump(pw, " ");
+ } else {
+ if (i >= 50) {
+ pw.println(" ...");
+ break;
+ }
+ pw.print(" #"); pw.print(i); pw.print(": "); pw.println(r);
+ }
+ }
+
+ return needSep;
+ }
+}
diff --git a/services/java/com/android/server/am/BroadcastRecord.java b/services/java/com/android/server/am/BroadcastRecord.java
index 6738e4fc76c0..dd560fc5e7b9 100644
--- a/services/java/com/android/server/am/BroadcastRecord.java
+++ b/services/java/com/android/server/am/BroadcastRecord.java
@@ -59,7 +59,7 @@ class BroadcastRecord extends Binder {
IBinder receiver; // who is currently running, null if none.
int state;
int anrCount; // has this broadcast record hit any ANRs?
- ActivityManagerService.BroadcastQueue queue; // the outbound queue handling this broadcast
+ BroadcastQueue queue; // the outbound queue handling this broadcast
static final int IDLE = 0;
static final int APP_RECEIVE = 1;
@@ -162,7 +162,7 @@ class BroadcastRecord extends Binder {
}
}
- BroadcastRecord(ActivityManagerService.BroadcastQueue _queue,
+ BroadcastRecord(BroadcastQueue _queue,
Intent _intent, ProcessRecord _callerApp, String _callerPackage,
int _callingPid, int _callingUid, String _requiredPermission,
List _receivers, IIntentReceiver _resultTo, int _resultCode,
diff --git a/services/java/com/android/server/am/CompatModePackages.java b/services/java/com/android/server/am/CompatModePackages.java
index f65648624229..cd722025a37b 100644
--- a/services/java/com/android/server/am/CompatModePackages.java
+++ b/services/java/com/android/server/am/CompatModePackages.java
@@ -41,7 +41,7 @@ public class CompatModePackages {
private final HashMap<String, Integer> mPackages = new HashMap<String, Integer>();
- private static final int MSG_WRITE = 1;
+ private static final int MSG_WRITE = ActivityManagerService.FIRST_COMPAT_MODE_MSG;
private final Handler mHandler = new Handler() {
@Override public void handleMessage(Message msg) {
diff --git a/services/java/com/android/server/am/ProviderMap.java b/services/java/com/android/server/am/ProviderMap.java
index 06353f64c0d3..2021e0d1bdb8 100644
--- a/services/java/com/android/server/am/ProviderMap.java
+++ b/services/java/com/android/server/am/ProviderMap.java
@@ -158,7 +158,7 @@ public class ProviderMap {
}
}
- private HashMap<ComponentName, ContentProviderRecord> getProvidersByClass(int optionalUserId) {
+ HashMap<ComponentName, ContentProviderRecord> getProvidersByClass(int optionalUserId) {
final int userId = optionalUserId >= 0
? optionalUserId : Binder.getOrigCallingUser();
final HashMap<ComponentName, ContentProviderRecord> map = mProvidersByClassPerUser.get(userId);
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index fdb6e4ca85ef..ebf954bf398f 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -2012,6 +2012,39 @@ final class Settings {
return false;
}
+ static final void printFlags(PrintWriter pw, int val, Object[] spec) {
+ pw.print("[ ");
+ for (int i=0; i<spec.length; i+=2) {
+ int mask = (Integer)spec[i];
+ if ((val & mask) != 0) {
+ pw.print(spec[i+1]);
+ pw.print(" ");
+ }
+ }
+ pw.print("]");
+ }
+
+ static final Object[] FLAG_DUMP_SPEC = new Object[] {
+ ApplicationInfo.FLAG_SYSTEM, "SYSTEM",
+ ApplicationInfo.FLAG_DEBUGGABLE, "DEBUGGABLE",
+ ApplicationInfo.FLAG_HAS_CODE, "HAS_CODE",
+ ApplicationInfo.FLAG_PERSISTENT, "PERSISTENT",
+ ApplicationInfo.FLAG_FACTORY_TEST, "FACTORY_TEST",
+ ApplicationInfo.FLAG_ALLOW_TASK_REPARENTING, "ALLOW_TASK_REPARENTING",
+ ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA, "ALLOW_CLEAR_USER_DATA",
+ ApplicationInfo.FLAG_UPDATED_SYSTEM_APP, "UPDATED_SYSTEM_APP",
+ ApplicationInfo.FLAG_TEST_ONLY, "TEST_ONLY",
+ ApplicationInfo.FLAG_VM_SAFE_MODE, "VM_SAFE_MODE",
+ ApplicationInfo.FLAG_ALLOW_BACKUP, "ALLOW_BACKUP",
+ ApplicationInfo.FLAG_KILL_AFTER_RESTORE, "KILL_AFTER_RESTORE",
+ ApplicationInfo.FLAG_RESTORE_ANY_VERSION, "RESTORE_ANY_VERSION",
+ ApplicationInfo.FLAG_EXTERNAL_STORAGE, "EXTERNAL_STORAGE",
+ ApplicationInfo.FLAG_LARGE_HEAP, "LARGE_HEAP",
+ ApplicationInfo.FLAG_STOPPED, "STOPPED",
+ ApplicationInfo.FLAG_FORWARD_LOCK, "FORWARD_LOCK",
+ ApplicationInfo.FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE",
+ };
+
void dumpPackagesLPr(PrintWriter pw, String packageName, DumpState dumpState) {
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
final Date date = new Date();
@@ -2052,6 +2085,7 @@ final class Settings {
pw.print(" nativeLibraryPath="); pw.println(ps.nativeLibraryPathString);
pw.print(" versionCode="); pw.println(ps.versionCode);
if (ps.pkg != null) {
+ pw.print(" flags="); printFlags(pw, ps.pkg.applicationInfo.flags, FLAG_DUMP_SPEC); pw.println();
pw.print(" versionName="); pw.println(ps.pkg.mVersionName);
pw.print(" dataDir="); pw.println(ps.pkg.applicationInfo.dataDir);
pw.print(" targetSdk="); pw.println(ps.pkg.applicationInfo.targetSdkVersion);
diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java
index 8f51466e359a..ed83fbe45c37 100644
--- a/services/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/java/com/android/server/usb/UsbDeviceManager.java
@@ -46,6 +46,7 @@ import android.os.storage.StorageVolume;
import android.os.SystemProperties;
import android.os.UEventObserver;
import android.provider.Settings;
+import android.util.Pair;
import android.util.Slog;
import java.io.File;
@@ -54,7 +55,10 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.LinkedList;
import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
/**
* UsbDeviceManager manages USB state in device mode.
@@ -88,6 +92,8 @@ public class UsbDeviceManager {
// which need debouncing.
private static final int UPDATE_DELAY = 1000;
+ private static final String BOOT_MODE_PROPERTY = "ro.bootmode";
+
private UsbHandler mHandler;
private boolean mBootCompleted;
@@ -98,6 +104,7 @@ public class UsbDeviceManager {
private final boolean mHasUsbAccessory;
private boolean mUseUsbNotification;
private boolean mAdbEnabled;
+ private Map<String, List<Pair<String, String>>> mOemModeMap;
private class AdbSettingsObserver extends ContentObserver {
public AdbSettingsObserver() {
@@ -138,6 +145,8 @@ public class UsbDeviceManager {
mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
initRndisAddress();
+ readOemUsbOverrideConfig();
+
// create a thread for our Handler
HandlerThread thread = new HandlerThread("UsbDeviceManager",
Process.THREAD_PRIORITY_BACKGROUND);
@@ -259,6 +268,10 @@ public class UsbDeviceManager {
// persist.sys.usb.config should never be unset. But if it is, set it to "adb"
// so we have a chance of debugging what happened.
mDefaultFunctions = SystemProperties.get("persist.sys.usb.config", "adb");
+
+ // Check if USB mode needs to be overridden depending on OEM specific bootmode.
+ mDefaultFunctions = processOemUsbOverride(mDefaultFunctions);
+
// 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");
@@ -381,7 +394,11 @@ public class UsbDeviceManager {
}
private void setEnabledFunctions(String functions, boolean makeDefault) {
- if (functions != null && makeDefault) {
+
+ // Do not update persystent.sys.usb.config if the device is booted up
+ // with OEM specific mode.
+ if (functions != null && makeDefault && !needsOemUsbOverride()) {
+
if (mAdbEnabled) {
functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
} else {
@@ -410,6 +427,10 @@ public class UsbDeviceManager {
if (functions == null) {
functions = mDefaultFunctions;
}
+
+ // Override with bootmode specific usb mode if needed
+ functions = processOemUsbOverride(functions);
+
if (mAdbEnabled) {
functions = addFunction(functions, UsbManager.USB_FUNCTION_ADB);
} else {
@@ -671,6 +692,53 @@ public class UsbDeviceManager {
}
}
+ private void readOemUsbOverrideConfig() {
+ String[] configList = mContext.getResources().getStringArray(
+ com.android.internal.R.array.config_oemUsbModeOverride);
+
+ if (configList != null) {
+ for (String config: configList) {
+ String[] items = config.split(":");
+ if (items.length == 3) {
+ if (mOemModeMap == null) {
+ mOemModeMap = new HashMap<String, List<Pair<String, String>>>();
+ }
+ List overrideList = mOemModeMap.get(items[0]);
+ if (overrideList == null) {
+ overrideList = new LinkedList<Pair<String, String>>();
+ mOemModeMap.put(items[0], overrideList);
+ }
+ overrideList.add(new Pair<String, String>(items[1], items[2]));
+ }
+ }
+ }
+ }
+
+ private boolean needsOemUsbOverride() {
+ if (mOemModeMap == null) return false;
+
+ String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
+ return (mOemModeMap.get(bootMode) != null) ? true : false;
+ }
+
+ private String processOemUsbOverride(String usbFunctions) {
+ if ((usbFunctions == null) || (mOemModeMap == null)) return usbFunctions;
+
+ String bootMode = SystemProperties.get(BOOT_MODE_PROPERTY, "unknown");
+
+ List<Pair<String, String>> overrides = mOemModeMap.get(bootMode);
+ if (overrides != null) {
+ for (Pair<String, String> pair: overrides) {
+ if (pair.first.equals(usbFunctions)) {
+ Slog.d(TAG, "OEM USB override: " + pair.first + " ==> " + pair.second);
+ return pair.second;
+ }
+ }
+ }
+ // return passed in functions as is.
+ return usbFunctions;
+ }
+
public void dump(FileDescriptor fd, PrintWriter pw) {
if (mHandler != null) {
mHandler.dump(fd, pw);
diff --git a/services/java/com/android/server/wm/InputManager.java b/services/java/com/android/server/wm/InputManager.java
index a4f0a0c24f8c..56c351975c50 100644
--- a/services/java/com/android/server/wm/InputManager.java
+++ b/services/java/com/android/server/wm/InputManager.java
@@ -668,25 +668,6 @@ public class InputManager implements Watchdog.Monitor {
}
@SuppressWarnings("unused")
- public int getMaxEventsPerSecond() {
- int result = 0;
- try {
- result = Integer.parseInt(SystemProperties.get("windowsmgr.max_events_per_sec"));
- } catch (NumberFormatException e) {
- }
- if (result < 1) {
- // This number equates to the refresh rate * 1.5. The rate should be at least
- // equal to the screen refresh rate. We increase the rate by 50% to compensate for
- // the discontinuity between the actual rate that events come in at (they do
- // not necessarily come in constantly and are not handled synchronously).
- // Ideally, we would use Display.getRefreshRate(), but as this does not necessarily
- // return a sensible result, we use '60' as our default assumed refresh rate.
- result = 90;
- }
- return result;
- }
-
- @SuppressWarnings("unused")
public int getPointerLayer() {
return mWindowManagerService.mPolicy.windowTypeToLayerLw(
WindowManager.LayoutParams.TYPE_POINTER)
diff --git a/services/java/com/android/server/wm/ScreenRotationAnimation.java b/services/java/com/android/server/wm/ScreenRotationAnimation.java
index 55fb03831b6c..04a039fbcd56 100644
--- a/services/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -16,6 +16,8 @@
package com.android.server.wm;
+import java.io.PrintWriter;
+
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
@@ -96,6 +98,46 @@ class ScreenRotationAnimation {
final Matrix mTmpMatrix = new Matrix();
final float[] mTmpFloats = new float[9];
+ public void printTo(String prefix, PrintWriter pw) {
+ pw.print(prefix); pw.print("mSurface="); pw.print(mSurface);
+ pw.print(" mWidth="); pw.print(mWidth);
+ pw.print(" mHeight="); pw.println(mHeight);
+ pw.print(prefix); pw.print("mBlackFrame="); pw.println(mBlackFrame);
+ pw.print(prefix); pw.print("mSnapshotRotation="); pw.print(mSnapshotRotation);
+ pw.print(" mSnapshotDeltaRotation="); pw.print(mSnapshotDeltaRotation);
+ pw.print(" mCurRotation="); pw.println(mCurRotation);
+ pw.print(prefix); pw.print("mOriginalRotation="); pw.print(mOriginalRotation);
+ pw.print(" mOriginalWidth="); pw.print(mOriginalWidth);
+ pw.print(" mOriginalHeight="); pw.println(mOriginalHeight);
+ pw.print(prefix); pw.print("mStarted="); pw.print(mStarted);
+ pw.print(" mAnimRunning="); pw.print(mAnimRunning);
+ pw.print(" mFinishAnimReady="); pw.print(mFinishAnimReady);
+ pw.print(" mFinishAnimStartTime="); pw.println(mFinishAnimStartTime);
+ pw.print(prefix); pw.print("mStartExitAnimation="); pw.print(mStartExitAnimation);
+ pw.print(" "); mStartExitTransformation.printShortString(pw); pw.println();
+ pw.print(prefix); pw.print("mStartEnterAnimation="); pw.print(mStartEnterAnimation);
+ pw.print(" "); mStartEnterTransformation.printShortString(pw); pw.println();
+ pw.print(prefix); pw.print("mFinishExitAnimation="); pw.print(mFinishExitAnimation);
+ pw.print(" "); mFinishExitTransformation.printShortString(pw); pw.println();
+ pw.print(prefix); pw.print("mFinishEnterAnimation="); pw.print(mFinishEnterAnimation);
+ pw.print(" "); mFinishEnterTransformation.printShortString(pw); pw.println();
+ pw.print(prefix); pw.print("mRotateExitAnimation="); pw.print(mRotateExitAnimation);
+ pw.print(" "); mRotateExitTransformation.printShortString(pw); pw.println();
+ pw.print(prefix); pw.print("mRotateEnterAnimation="); pw.print(mRotateEnterAnimation);
+ pw.print(" "); mRotateEnterTransformation.printShortString(pw); pw.println();
+ pw.print(prefix); pw.print("mLastRotateExitAnimation=");
+ pw.print(mLastRotateExitAnimation);
+ pw.print(" "); mLastRotateExitTransformation.printShortString(pw); pw.println();
+ pw.print(prefix); pw.print("mExitTransformation=");
+ mExitTransformation.printShortString(pw); pw.println();
+ pw.print(prefix); pw.print("mEnterTransformation=");
+ mEnterTransformation.printShortString(pw); pw.println();
+ pw.print(prefix); pw.print("mSnapshotInitialMatrix=");
+ mSnapshotInitialMatrix.printShortString(pw);
+ pw.print(" mSnapshotFinalMatrix="); mSnapshotFinalMatrix.printShortString(pw);
+ pw.println();
+ }
+
public ScreenRotationAnimation(Context context, SurfaceSession session,
boolean inTransaction, int originalWidth, int originalHeight, int originalRotation) {
mContext = context;
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 3b5ec035ec51..bdbaab498b97 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -7636,6 +7636,8 @@ public class WindowManagerService extends IWindowManager.Stub
mInnerFields.mAnimating = true;
} else {
updateRotation = true;
+ mScreenRotationAnimation.kill();
+ mScreenRotationAnimation = null;
}
}
}
@@ -8708,7 +8710,7 @@ public class WindowManagerService extends IWindowManager.Stub
mInnerFields.mAnimating = false;
// SECOND LOOP: Execute animations and update visibility of windows.
- updateRotation =
+ updateRotation |=
updateAppsAndRotationAnimationsLocked(currentTime, innerDw, innerDh);
if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: seq="
@@ -9012,11 +9014,6 @@ public class WindowManagerService extends IWindowManager.Stub
mTurnOnScreen = false;
}
- if (updateRotation && mScreenRotationAnimation != null) {
- mScreenRotationAnimation.kill();
- mScreenRotationAnimation = null;
- }
-
if (updateRotation) {
if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
if (updateRotationUncheckedLocked(false)) {
@@ -9387,7 +9384,7 @@ public class WindowManagerService extends IWindowManager.Stub
}
if (CUSTOM_SCREEN_ROTATION) {
- if (mScreenRotationAnimation != null && mScreenRotationAnimation.isAnimating()) {
+ if (mScreenRotationAnimation != null) {
mScreenRotationAnimation.kill();
mScreenRotationAnimation = null;
}
@@ -9918,11 +9915,15 @@ public class WindowManagerService extends IWindowManager.Stub
pw.print(" mLastWindowForcedOrientation"); pw.print(mLastWindowForcedOrientation);
pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation);
pw.print(" mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount);
- pw.print(" mTraversalScheduled="); pw.print(mTraversalScheduled);
- pw.print(" mWindowAnimationScale="); pw.print(mWindowAnimationScale);
- pw.print(" mTransitionWindowAnimationScale="); pw.println(mTransitionAnimationScale);
+ if (mScreenRotationAnimation != null) {
+ pw.println(" mScreenRotationAnimation:");
+ mScreenRotationAnimation.printTo(" ", pw);
+ }
+ pw.print(" mWindowAnimationScale="); pw.print(mWindowAnimationScale);
+ pw.print(" mTransitionWindowAnimationScale="); pw.print(mTransitionAnimationScale);
pw.print(" mAnimatorDurationScale="); pw.println(mAnimatorDurationScale);
- pw.print(" mNextAppTransition=0x");
+ pw.print(" mTraversalScheduled="); pw.print(mTraversalScheduled);
+ pw.print(" mNextAppTransition=0x");
pw.print(Integer.toHexString(mNextAppTransition));
pw.print(" mAppTransitionReady="); pw.println(mAppTransitionReady);
pw.print(" mAppTransitionRunning="); pw.print(mAppTransitionRunning);
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index e163826e1597..5c3e0021e0a5 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -71,7 +71,6 @@ static struct {
jmethodID getExcludedDeviceNames;
jmethodID getKeyRepeatTimeout;
jmethodID getKeyRepeatDelay;
- jmethodID getMaxEventsPerSecond;
jmethodID getHoverTapTimeout;
jmethodID getHoverTapSlop;
jmethodID getDoubleTapTimeout;
@@ -586,12 +585,6 @@ void NativeInputManager::getDispatcherConfiguration(InputDispatcherConfiguration
if (!checkAndClearExceptionFromCallback(env, "getKeyRepeatDelay")) {
outConfig->keyRepeatDelay = milliseconds_to_nanoseconds(keyRepeatDelay);
}
-
- jint maxEventsPerSecond = env->CallIntMethod(mCallbacksObj,
- gCallbacksClassInfo.getMaxEventsPerSecond);
- if (!checkAndClearExceptionFromCallback(env, "getMaxEventsPerSecond")) {
- outConfig->maxEventsPerSecond = maxEventsPerSecond;
- }
}
bool NativeInputManager::isKeyRepeatEnabled() {
@@ -1480,9 +1473,6 @@ int register_android_server_InputManager(JNIEnv* env) {
GET_METHOD_ID(gCallbacksClassInfo.getLongPressTimeout, clazz,
"getLongPressTimeout", "()I");
- GET_METHOD_ID(gCallbacksClassInfo.getMaxEventsPerSecond, clazz,
- "getMaxEventsPerSecond", "()I");
-
GET_METHOD_ID(gCallbacksClassInfo.getPointerLayer, clazz,
"getPointerLayer", "()I");
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 5da3d97706bc..24a4876ee4ef 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -1438,7 +1438,8 @@ public class PhoneNumberUtils
* phoneNumber doesn't have the country code.
* @param defaultCountryIso
* the ISO 3166-1 two letters country code whose convention will
- * be used if the phoneNumberE164 is null or invalid.
+ * be used if the phoneNumberE164 is null or invalid, or if phoneNumber
+ * contains IDD.
* @return the formatted number if the given number has been formatted,
* otherwise, return the given number.
*
@@ -1457,9 +1458,13 @@ public class PhoneNumberUtils
if (phoneNumberE164 != null && phoneNumberE164.length() >= 2
&& phoneNumberE164.charAt(0) == '+') {
try {
- PhoneNumber pn = util.parse(phoneNumberE164, defaultCountryIso);
+ // The number to be parsed is in E164 format, so the default region used doesn't
+ // matter.
+ PhoneNumber pn = util.parse(phoneNumberE164, "ZZ");
String regionCode = util.getRegionCodeForNumber(pn);
- if (!TextUtils.isEmpty(regionCode)) {
+ if (!TextUtils.isEmpty(regionCode) &&
+ // This makes sure phoneNumber doesn't contain an IDD
+ normalizeNumber(phoneNumber).indexOf(phoneNumberE164.substring(1)) <= 0) {
defaultCountryIso = regionCode;
}
} catch (NumberParseException e) {
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 5b7627295902..9d9680d4a43f 100644
--- a/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/PhoneNumberUtilsTest.java
@@ -512,6 +512,9 @@ public class PhoneNumberUtilsTest extends AndroidTestCase {
public void testFormatNumber() {
assertEquals("(650) 291-0000", PhoneNumberUtils.formatNumber("650 2910000", "US"));
assertEquals("223-4567", PhoneNumberUtils.formatNumber("2234567", "US"));
+ assertEquals("011 86 10 8888 0000",
+ PhoneNumberUtils.formatNumber("011861088880000", "US"));
+ assertEquals("010 8888 0000", PhoneNumberUtils.formatNumber("01088880000", "CN"));
// formatNumber doesn't format alpha numbers, but keep them as they are.
assertEquals("800-GOOG-114", PhoneNumberUtils.formatNumber("800-GOOG-114", "US"));
}
@@ -542,6 +545,16 @@ public class PhoneNumberUtilsTest extends AndroidTestCase {
// Using the phoneNumberE164's country code
assertEquals("(650) 291-0000",
PhoneNumberUtils.formatNumber("6502910000", "+16502910000", "CN"));
+ // Using the default country code for a phone number containing the IDD
+ assertEquals("011 86 10 8888 0000",
+ PhoneNumberUtils.formatNumber("011861088880000", "+861088880000", "US"));
+ assertEquals("00 86 10 8888 0000",
+ PhoneNumberUtils.formatNumber("00861088880000", "+861088880000", "GB"));
+ assertEquals("+86 10 8888 0000",
+ PhoneNumberUtils.formatNumber("+861088880000", "+861088880000", "GB"));
+ // Wrong default country, so no formatting is done
+ assertEquals("011861088880000",
+ PhoneNumberUtils.formatNumber("011861088880000", "+861088880000", "GB"));
// The phoneNumberE164 is null
assertEquals("(650) 291-0000", PhoneNumberUtils.formatNumber("6502910000", null, "US"));
// The given number has a country code.
@@ -553,7 +566,11 @@ public class PhoneNumberUtilsTest extends AndroidTestCase {
// An invalid Polish number should be left as it is. Note Poland doesn't use '0' as a
// national prefix; therefore, the leading '0' makes the number invalid.
assertEquals("0506128687", PhoneNumberUtils.formatNumber("0506128687", null, "PL"));
+ // Wrong default country, so no formatting is done
+ assertEquals("011861088880000",
+ PhoneNumberUtils.formatNumber("011861088880000", "", "GB"));
}
+
@SmallTest
public void testIsEmergencyNumber() {
// There are two parallel sets of tests here: one for the
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index 0b4fc51454b2..674c0b700b5a 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -333,6 +333,12 @@ public class MockContext extends Context {
throw new UnsupportedOperationException();
}
+ /** @hide */
+ @Override
+ public boolean bindService(Intent service, ServiceConnection conn, int flags, int userId) {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public void unbindService(ServiceConnection conn) {
throw new UnsupportedOperationException();
diff --git a/tests/BiDiTests/res/layout/grid_layout_ltr.xml b/tests/BiDiTests/res/layout/grid_layout_ltr.xml
index 46ea6580cb96..e320809d8a72 100644
--- a/tests/BiDiTests/res/layout/grid_layout_ltr.xml
+++ b/tests/BiDiTests/res/layout/grid_layout_ltr.xml
@@ -57,6 +57,27 @@
<EditText
android:ems="8"/>
+ <TextView
+ android:text="You can configure email in just a few steps:"
+ android:textSize="16dip"
+ android:layout_columnSpan="4"
+ android:layout_gravity="start"/>
+
+ <TextView
+ android:text="Email address:"
+ android:layout_gravity="end"/>
+
+ <EditText
+ android:ems="10"/>
+
+ <TextView
+ android:text="Password:"
+ android:layout_column="0"
+ android:layout_gravity="end"/>
+
+ <EditText
+ android:ems="8"/>
+
<Space
android:layout_row="4"
android:layout_column="0"
diff --git a/tests/BiDiTests/res/layout/grid_layout_rtl.xml b/tests/BiDiTests/res/layout/grid_layout_rtl.xml
index 947e13c84a5e..6d3aae66fc96 100644
--- a/tests/BiDiTests/res/layout/grid_layout_rtl.xml
+++ b/tests/BiDiTests/res/layout/grid_layout_rtl.xml
@@ -57,6 +57,27 @@
<EditText
android:ems="8"/>
+ <TextView
+ android:text="You can configure email in just a few steps:"
+ android:textSize="16dip"
+ android:layout_columnSpan="4"
+ android:layout_gravity="end"/>
+
+ <TextView
+ android:text="Email address:"
+ android:layout_gravity="start"/>
+
+ <EditText
+ android:ems="10"/>
+
+ <TextView
+ android:text="Password:"
+ android:layout_column="0"
+ android:layout_gravity="start"/>
+
+ <EditText
+ android:ems="8"/>
+
<Space
android:layout_row="4"
android:layout_column="0"
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeLtr.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeLtr.java
index 859b8fb70bdd..2b5e674f6334 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeLtr.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeLtr.java
@@ -23,7 +23,6 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.GridLayout;
-
import android.widget.*;
import static android.text.InputType.*;
@@ -62,8 +61,8 @@ public class BiDiTestGridLayoutCodeLtr extends Fragment {
Spec row7 = spec(6);
Spec col1a = spec(0, 4, CENTER);
- Spec col1b = spec(0, 4, START);
- Spec col1c = spec(0, END);
+ Spec col1b = spec(0, 4, LEFT);
+ Spec col1c = spec(0, RIGHT);
Spec col2 = spec(1, START);
Spec col3 = spec(2, FILL);
Spec col4a = spec(3);
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeRtl.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeRtl.java
index fac8c950d26c..3a03c6cd65a7 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeRtl.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestGridLayoutCodeRtl.java
@@ -22,6 +22,7 @@ import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.GridLayout;
import android.widget.*;
import static android.text.InputType.*;
@@ -60,8 +61,8 @@ public class BiDiTestGridLayoutCodeRtl extends Fragment {
Spec row7 = spec(6);
Spec col1a = spec(0, 4, CENTER);
- Spec col1b = spec(0, 4, START);
- Spec col1c = spec(0, END);
+ Spec col1b = spec(0, 4, LEFT);
+ Spec col1c = spec(0, RIGHT);
Spec col2 = spec(1, START);
Spec col3 = spec(2, FILL);
Spec col4a = spec(3);
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
index c0ba8cf53254..83c9c3d727f6 100644
--- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java
@@ -22,12 +22,12 @@ import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
-import android.content.Intent;
import android.content.DialogInterface.OnClickListener;
+import android.content.Intent;
import android.graphics.Bitmap;
-import android.graphics.Canvas;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.Bitmap.Config;
+import android.graphics.Canvas;
import android.net.http.SslError;
import android.os.Bundle;
import android.os.Environment;
@@ -36,7 +36,6 @@ import android.os.Message;
import android.util.Log;
import android.view.ViewGroup;
import android.view.Window;
-import android.webkit.CookieManager;
import android.webkit.ConsoleMessage;
import android.webkit.CookieManager;
import android.webkit.GeolocationPermissions;
@@ -904,9 +903,7 @@ public class TestShellActivity extends Activity implements LayoutTestController
settings.setWorkersEnabled(false);
settings.setXSSAuditorEnabled(false);
settings.setPageCacheCapacity(0);
- // this enables cpu upload path (as opposed to gpu upload path)
- // and it's only meant to be a temporary workaround!
- settings.setProperty("enable_cpu_upload_path", "true");
+ settings.setProperty("use_minimal_memory", "false");
}
private WebView mWebView;
diff --git a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/mandelbrot.rs b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/mandelbrot.rs
index a7987b381298..0ffb0e5a7a37 100644
--- a/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/mandelbrot.rs
+++ b/tests/RenderScriptTests/ComputePerf/src/com/example/android/rs/computeperf/mandelbrot.rs
@@ -25,13 +25,14 @@ void root(uchar4 *v_out, uint32_t x, uint32_t y) {
p.y = -1.f + ((float)y / gDimY) * 2.f;
float2 t = 0;
+ float2 t2 = t * t;
int iteration = 0;
- while((t.x*t.x + t.y*t.y < 4.f) && (iteration < gMaxIteration)) {
- float2 t2 = t * t;
+ while((t2.x + t2.y < 4.f) && (iteration < gMaxIteration)) {
float xtemp = t2.x - t2.y + p.x;
t.y = 2 * t.x * t.y + p.y;
t.x = xtemp;
iteration++;
+ t2 = t * t;
}
if(iteration >= gMaxIteration) {
diff --git a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
index 3615f6057eb2..73682600ec10 100644
--- a/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
+++ b/tests/RenderScriptTests/ImageProcessing/src/com/android/rs/image/ImageProcessingActivity.java
@@ -283,6 +283,9 @@ public class ImageProcessingActivity extends Activity
mRadius = MAX_RADIUS;
mScript.set_radius(mRadius);
+ mScript.invoke_filter();
+ mRS.finish();
+
long t = java.lang.System.currentTimeMillis();
mScript.invoke_filter();
diff --git a/tests/RenderScriptTests/PerfTest/res/raw/singletexfm.glsl b/tests/RenderScriptTests/PerfTest/res/raw/singletexfm.glsl
new file mode 100644
index 000000000000..656961c5b2e5
--- /dev/null
+++ b/tests/RenderScriptTests/PerfTest/res/raw/singletexfm.glsl
@@ -0,0 +1,8 @@
+varying vec2 varTex0;
+
+void main() {
+ lowp vec3 col0 = texture2D(UNI_Tex0, varTex0).rgb;
+ gl_FragColor.xyz = col0 * UNI_modulate.rgb;
+ gl_FragColor.w = UNI_modulate.a;
+}
+
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java
index ba70c7148e89..41f664a0414b 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java
@@ -35,18 +35,22 @@ public class FillTest implements RsBenchBaseTest{
// Custom shaders
private ProgramFragment mProgFragmentMultitex;
private ProgramFragment mProgFragmentSingletex;
+ private ProgramFragment mProgFragmentSingletexModulate;
private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options();
int mBenchmarkDimX;
int mBenchmarkDimY;
private ScriptC_fill_test mFillScript;
ScriptField_TestScripts_s.Item[] mTests;
+ ScriptField_FillTestFragData_s mFragData;
private final String[] mNames = {
"Fill screen 10x singletexture",
"Fill screen 10x 3tex multitexture",
"Fill screen 10x blended singletexture",
- "Fill screen 10x blended 3tex multitexture"
+ "Fill screen 10x blended 3tex multitexture",
+ "Fill screen 3x modulate blended singletexture",
+ "Fill screen 1x modulate blended singletexture",
};
public FillTest() {
@@ -88,6 +92,8 @@ public class FillTest implements RsBenchBaseTest{
addTest(index++, 0 /*testId*/, 0 /*blend*/, 10 /*quadCount*/);
addTest(index++, 1 /*testId*/, 1 /*blend*/, 10 /*quadCount*/);
addTest(index++, 0 /*testId*/, 1 /*blend*/, 10 /*quadCount*/);
+ addTest(index++, 2 /*testId*/, 1 /*blend*/, 3 /*quadCount*/);
+ addTest(index++, 2 /*testId*/, 1 /*blend*/, 1 /*quadCount*/);
return true;
}
@@ -112,6 +118,14 @@ public class FillTest implements RsBenchBaseTest{
pfbCustom.setShader(mRes, R.raw.singletexf);
pfbCustom.addTexture(Program.TextureType.TEXTURE_2D);
mProgFragmentSingletex = pfbCustom.create();
+
+ pfbCustom = new ProgramFragment.Builder(mRS);
+ pfbCustom.setShader(mRes, R.raw.singletexfm);
+ pfbCustom.addTexture(Program.TextureType.TEXTURE_2D);
+ mFragData = new ScriptField_FillTestFragData_s(mRS, 1);
+ pfbCustom.addConstant(mFragData.getType());
+ mProgFragmentSingletexModulate = pfbCustom.create();
+ mProgFragmentSingletexModulate.bindConstants(mFragData.getAllocation(), 0);
}
private Allocation loadTextureARGB(int id) {
@@ -140,6 +154,7 @@ public class FillTest implements RsBenchBaseTest{
mFillScript.set_gProgVertex(progVertex);
mFillScript.set_gProgFragmentTexture(mProgFragmentSingletex);
+ mFillScript.set_gProgFragmentTextureModulate(mProgFragmentSingletexModulate);
mFillScript.set_gProgFragmentMultitex(mProgFragmentMultitex);
mFillScript.set_gProgStoreBlendNone(ProgramStore.BLEND_NONE_DEPTH_NONE(mRS));
mFillScript.set_gProgStoreBlendAlpha(ProgramStore.BLEND_ALPHA_DEPTH_NONE(mRS));
@@ -150,5 +165,7 @@ public class FillTest implements RsBenchBaseTest{
mFillScript.set_gTexOpaque(loadTextureRGB(R.drawable.data));
mFillScript.set_gTexTransparent(loadTextureARGB(R.drawable.leaf));
mFillScript.set_gTexChecker(loadTextureRGB(R.drawable.checker));
+
+ mFillScript.bind_gFragData(mFragData);
}
}
diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/fill_test.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/fill_test.rs
index 23832d394eda..281f830d328a 100644
--- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/fill_test.rs
+++ b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/fill_test.rs
@@ -21,6 +21,7 @@
rs_program_vertex gProgVertex;
rs_program_fragment gProgFragmentTexture;
+rs_program_fragment gProgFragmentTextureModulate;
rs_program_fragment gProgFragmentMultitex;
rs_program_store gProgStoreBlendNone;
@@ -41,6 +42,11 @@ typedef struct FillTestData_s {
} FillTestData;
FillTestData *gData;
+typedef struct FillTestFragData_s {
+ float4 modulate;
+} FillTestFragData;
+FillTestFragData *gFragData;
+
static float gDt = 0.0f;
void init() {
@@ -58,7 +64,7 @@ static void bindProgramVertexOrtho() {
rsgProgramVertexLoadProjectionMatrix(&proj);
}
-static void displaySingletexFill(bool blend, int quadCount) {
+static void displaySingletexFill(bool blend, int quadCount, bool modulate) {
bindProgramVertexOrtho();
rs_matrix4x4 matrix;
rsMatrixLoadIdentity(&matrix);
@@ -70,9 +76,21 @@ static void displaySingletexFill(bool blend, int quadCount) {
} else {
rsgBindProgramStore(gProgStoreBlendAlpha);
}
- rsgBindProgramFragment(gProgFragmentTexture);
- rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
- rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque);
+ if (modulate) {
+ rsgBindProgramFragment(gProgFragmentTextureModulate);
+ rsgBindSampler(gProgFragmentTextureModulate, 0, gLinearClamp);
+ rsgBindTexture(gProgFragmentTextureModulate, 0, gTexOpaque);
+
+ gFragData->modulate.r = 0.8f;
+ gFragData->modulate.g = 0.7f;
+ gFragData->modulate.b = 0.8f;
+ gFragData->modulate.a = 0.5f;
+ rsgAllocationSyncAll(rsGetAllocation(gFragData));
+ } else {
+ rsgBindProgramFragment(gProgFragmentTexture);
+ rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp);
+ rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque);
+ }
for (int i = 0; i < quadCount; i ++) {
float startX = 5 * i, startY = 5 * i;
@@ -128,7 +146,10 @@ void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32
displayMultitextureSample(gData->blend == 1 ? true : false, gData->quadCount);
break;
case 1:
- displaySingletexFill(gData->blend == 1 ? true : false, gData->quadCount);
+ displaySingletexFill(gData->blend == 1 ? true : false, gData->quadCount, false);
+ break;
+ case 2:
+ displaySingletexFill(gData->blend == 1 ? true : false, gData->quadCount, true);
break;
default:
rsDebug("Wrong test number", 0);
diff --git a/tests/RenderScriptTests/SceneGraph/Android.mk b/tests/RenderScriptTests/SceneGraph/Android.mk
new file mode 100644
index 000000000000..ba4b3c50f3ae
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/Android.mk
@@ -0,0 +1,26 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
+
+LOCAL_PACKAGE_NAME := SceneGraphTest
+
+include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/SceneGraph/AndroidManifest.xml b/tests/RenderScriptTests/SceneGraph/AndroidManifest.xml
new file mode 100644
index 000000000000..e8d1e8e2b080
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.testapp">
+ <uses-permission
+ android:name="android.permission.INTERNET" />
+ <application android:label="SceneGraphTest">
+ <activity android:name="TestApp"
+ android:label="SceneGraphTest">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:name="FileSelector"
+ android:label="FileSelector"
+ android:hardwareAccelerated="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/RenderScriptTests/SceneGraph/assets/blue.jpg b/tests/RenderScriptTests/SceneGraph/assets/blue.jpg
new file mode 100644
index 000000000000..494e77a199e1
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/blue.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/carbonfiber.jpg b/tests/RenderScriptTests/SceneGraph/assets/carbonfiber.jpg
new file mode 100644
index 000000000000..2fcecb0be1f5
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/carbonfiber.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/green.jpg b/tests/RenderScriptTests/SceneGraph/assets/green.jpg
new file mode 100644
index 000000000000..a86a754fe2e3
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/green.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/grey.jpg b/tests/RenderScriptTests/SceneGraph/assets/grey.jpg
new file mode 100644
index 000000000000..5870b1af055e
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/grey.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/orange.jpg b/tests/RenderScriptTests/SceneGraph/assets/orange.jpg
new file mode 100644
index 000000000000..7dbe942af1a8
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/orange.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/orientation_test.a3d b/tests/RenderScriptTests/SceneGraph/assets/orientation_test.a3d
new file mode 100644
index 000000000000..07318ae11249
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/orientation_test.a3d
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/orientation_test.dae b/tests/RenderScriptTests/SceneGraph/assets/orientation_test.dae
new file mode 100644
index 000000000000..7eef443fa0e2
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/orientation_test.dae
@@ -0,0 +1,1102 @@
+<?xml version="1.0" ?>
+<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1">
+ <asset>
+ <contributor>
+ <author>alexst</author>
+ <authoring_tool>OpenCOLLADA2010</authoring_tool>
+ <comments>ColladaMaya export options: bakeTransforms=0;relativePaths=0;copyTextures=0;exportTriangles=1;exportCgfxFileReferences=0; isSampling=0;curveConstrainSampling=0;removeStaticCurves=1;exportPolygonMeshes=1;exportLights=1; exportCameras=1;exportJointsAndSkin=1;exportAnimations=0;exportInvisibleNodes=0;exportDefaultCameras=0; exportTexCoords=1;exportNormals=1;exportNormalsPerVertex=1;exportVertexColors=0;exportVertexColorsPerVertex=0; exportTexTangents=0;exportTangents=0;exportReferencedMaterials=1;exportMaterialsOnly=0; exportXRefs=1;dereferenceXRefs=1;exportCameraAsLookat=0;cameraXFov=0;cameraYFov=1;doublePrecision=0</comments>
+ <source_data>file:///Volumes/Android/art/orientation_test.mb</source_data>
+ </contributor>
+ <created>2011-09-30T15:31:38</created>
+ <modified>2011-09-30T15:31:38</modified>
+ <unit meter="0.01" name="centimeter" />
+ <up_axis>Y_UP</up_axis>
+ </asset>
+ <library_cameras>
+ <camera id="cameraShape1" name="cameraShape1">
+ <optics>
+ <technique_common>
+ <perspective>
+ <yfov>37.8493</yfov>
+ <aspect_ratio>1.5</aspect_ratio>
+ <znear>1</znear>
+ <zfar>400</zfar>
+ </perspective>
+ </technique_common>
+ </optics>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <film_fit>0</film_fit>
+ <film_fit_offset>0</film_fit_offset>
+ <film_offsetX>0</film_offsetX>
+ <film_offsetY>0</film_offsetY>
+ <horizontal_aperture>3.599993</horizontal_aperture>
+ <lens_squeeze>1</lens_squeeze>
+ <originalMayaNodeId>cameraShape1</originalMayaNodeId>
+ <vertical_aperture>2.399995</vertical_aperture>
+ </technique>
+ </extra>
+ </camera>
+ <camera id="CameraDistShape" name="CameraDistShape">
+ <optics>
+ <technique_common>
+ <perspective>
+ <yfov>37.8493</yfov>
+ <aspect_ratio>1.5</aspect_ratio>
+ <znear>1</znear>
+ <zfar>1000</zfar>
+ </perspective>
+ </technique_common>
+ </optics>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <film_fit>0</film_fit>
+ <film_fit_offset>0</film_fit_offset>
+ <film_offsetX>0</film_offsetX>
+ <film_offsetY>0</film_offsetY>
+ <horizontal_aperture>3.599993</horizontal_aperture>
+ <lens_squeeze>1</lens_squeeze>
+ <originalMayaNodeId>CameraDistShape</originalMayaNodeId>
+ <vertical_aperture>2.399995</vertical_aperture>
+ </technique>
+ </extra>
+ </camera>
+ </library_cameras>
+ <library_materials>
+ <material id="Paint1" name="Paint1">
+ <instance_effect url="#Paint1-fx" />
+ </material>
+ <material id="lambert2" name="lambert2">
+ <instance_effect url="#lambert2-fx" />
+ </material>
+ <material id="Plastic" name="Plastic">
+ <instance_effect url="#Plastic-fx" />
+ </material>
+ <material id="Metal" name="Metal">
+ <instance_effect url="#Metal-fx" />
+ </material>
+ <material id="PlasticCenter" name="PlasticCenter">
+ <instance_effect url="#PlasticCenter-fx" />
+ </material>
+ <material id="PlasticRed" name="PlasticRed">
+ <instance_effect url="#PlasticRed-fx" />
+ </material>
+ <material id="lambert10" name="lambert10">
+ <instance_effect url="#lambert10-fx" />
+ </material>
+ <material id="lambert11" name="lambert11">
+ <instance_effect url="#lambert11-fx" />
+ </material>
+ </library_materials>
+ <library_effects>
+ <effect id="Metal-fx">
+ <profile_COMMON>
+ <newparam sid="file23-surface">
+ <surface type="2D">
+ <init_from>file23</init_from>
+ </surface>
+ </newparam>
+ <newparam sid="file23-sampler">
+ <sampler2D>
+ <source>file23-surface</source>
+ </sampler2D>
+ </newparam>
+ <technique sid="common">
+ <lambert>
+ <emission>
+ <color>0 0 0 1</color>
+ </emission>
+ <ambient>
+ <color>0 0 0 1</color>
+ </ambient>
+ <diffuse>
+ <texture texture="file23-sampler" texcoord="TEX0">
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <blend_mode>NONE</blend_mode>
+ <coverageU>1</coverageU>
+ <coverageV>1</coverageV>
+ <fast>0</fast>
+ <mirrorU>0</mirrorU>
+ <mirrorV>0</mirrorV>
+ <noiseU>0</noiseU>
+ <noiseV>0</noiseV>
+ <offsetU>0</offsetU>
+ <offsetV>0</offsetV>
+ <repeatU>1</repeatU>
+ <repeatV>1</repeatV>
+ <rotateFrame>0</rotateFrame>
+ <rotateUV>0</rotateUV>
+ <stagger>0</stagger>
+ <translateFrameU>0</translateFrameU>
+ <translateFrameV>0</translateFrameV>
+ <wrapU>1</wrapU>
+ <wrapV>1</wrapV>
+ </technique>
+ </extra>
+ </texture>
+ </diffuse>
+ <transparent opaque="RGB_ZERO">
+ <color>0 0 0 1</color>
+ </transparent>
+ <transparency>
+ <float>1</float>
+ </transparency>
+ </lambert>
+ </technique>
+ </profile_COMMON>
+ </effect>
+ <effect id="Paint1-fx">
+ <profile_COMMON>
+ <newparam sid="file25-surface">
+ <surface type="2D">
+ <init_from>file25</init_from>
+ </surface>
+ </newparam>
+ <newparam sid="file25-sampler">
+ <sampler2D>
+ <source>file25-surface</source>
+ </sampler2D>
+ </newparam>
+ <technique sid="common">
+ <lambert>
+ <emission>
+ <color>0 0 0 1</color>
+ </emission>
+ <ambient>
+ <color>0 0 0 1</color>
+ </ambient>
+ <diffuse>
+ <texture texture="file25-sampler" texcoord="TEX0">
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <blend_mode>NONE</blend_mode>
+ <coverageU>1</coverageU>
+ <coverageV>1</coverageV>
+ <fast>0</fast>
+ <mirrorU>0</mirrorU>
+ <mirrorV>0</mirrorV>
+ <noiseU>0</noiseU>
+ <noiseV>0</noiseV>
+ <offsetU>0</offsetU>
+ <offsetV>0</offsetV>
+ <repeatU>1</repeatU>
+ <repeatV>1</repeatV>
+ <rotateFrame>0</rotateFrame>
+ <rotateUV>0</rotateUV>
+ <stagger>0</stagger>
+ <translateFrameU>0</translateFrameU>
+ <translateFrameV>0</translateFrameV>
+ <wrapU>1</wrapU>
+ <wrapV>1</wrapV>
+ </technique>
+ </extra>
+ </texture>
+ </diffuse>
+ <transparent opaque="RGB_ZERO">
+ <color>0 0 0 1</color>
+ </transparent>
+ <transparency>
+ <float>1</float>
+ </transparency>
+ </lambert>
+ </technique>
+ </profile_COMMON>
+ </effect>
+ <effect id="Plastic-fx">
+ <profile_COMMON>
+ <newparam sid="file24-surface">
+ <surface type="2D">
+ <init_from>file24</init_from>
+ </surface>
+ </newparam>
+ <newparam sid="file24-sampler">
+ <sampler2D>
+ <source>file24-surface</source>
+ </sampler2D>
+ </newparam>
+ <technique sid="common">
+ <lambert>
+ <emission>
+ <color>0 0 0 1</color>
+ </emission>
+ <ambient>
+ <color>0 0 0 1</color>
+ </ambient>
+ <diffuse>
+ <texture texture="file24-sampler" texcoord="TEX0">
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <blend_mode>NONE</blend_mode>
+ <coverageU>1</coverageU>
+ <coverageV>1</coverageV>
+ <fast>0</fast>
+ <mirrorU>0</mirrorU>
+ <mirrorV>0</mirrorV>
+ <noiseU>0</noiseU>
+ <noiseV>0</noiseV>
+ <offsetU>0</offsetU>
+ <offsetV>0</offsetV>
+ <repeatU>1</repeatU>
+ <repeatV>1</repeatV>
+ <rotateFrame>0</rotateFrame>
+ <rotateUV>0</rotateUV>
+ <stagger>0</stagger>
+ <translateFrameU>0</translateFrameU>
+ <translateFrameV>0</translateFrameV>
+ <wrapU>1</wrapU>
+ <wrapV>1</wrapV>
+ </technique>
+ </extra>
+ </texture>
+ </diffuse>
+ <transparent opaque="RGB_ZERO">
+ <color>0 0 0 1</color>
+ </transparent>
+ <transparency>
+ <float>1</float>
+ </transparency>
+ </lambert>
+ </technique>
+ </profile_COMMON>
+ </effect>
+ <effect id="PlasticCenter-fx">
+ <profile_COMMON>
+ <newparam sid="file24-surface">
+ <surface type="2D">
+ <init_from>file24</init_from>
+ </surface>
+ </newparam>
+ <newparam sid="file24-sampler">
+ <sampler2D>
+ <source>file24-surface</source>
+ </sampler2D>
+ </newparam>
+ <technique sid="common">
+ <lambert>
+ <emission>
+ <color>0 0 0 1</color>
+ </emission>
+ <ambient>
+ <color>0 0 0 1</color>
+ </ambient>
+ <diffuse>
+ <texture texture="file24-sampler" texcoord="TEX0">
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <blend_mode>NONE</blend_mode>
+ <coverageU>1</coverageU>
+ <coverageV>1</coverageV>
+ <fast>0</fast>
+ <mirrorU>0</mirrorU>
+ <mirrorV>0</mirrorV>
+ <noiseU>0</noiseU>
+ <noiseV>0</noiseV>
+ <offsetU>0</offsetU>
+ <offsetV>0</offsetV>
+ <repeatU>1</repeatU>
+ <repeatV>1</repeatV>
+ <rotateFrame>0</rotateFrame>
+ <rotateUV>0</rotateUV>
+ <stagger>0</stagger>
+ <translateFrameU>0</translateFrameU>
+ <translateFrameV>0</translateFrameV>
+ <wrapU>1</wrapU>
+ <wrapV>1</wrapV>
+ </technique>
+ </extra>
+ </texture>
+ </diffuse>
+ <transparent opaque="RGB_ZERO">
+ <color>0 0 0 1</color>
+ </transparent>
+ <transparency>
+ <float>1</float>
+ </transparency>
+ </lambert>
+ </technique>
+ </profile_COMMON>
+ </effect>
+ <effect id="PlasticRed-fx">
+ <profile_COMMON>
+ <newparam sid="file23-surface">
+ <surface type="2D">
+ <init_from>file23</init_from>
+ </surface>
+ </newparam>
+ <newparam sid="file23-sampler">
+ <sampler2D>
+ <source>file23-surface</source>
+ </sampler2D>
+ </newparam>
+ <technique sid="common">
+ <lambert>
+ <emission>
+ <color>0 0 0 1</color>
+ </emission>
+ <ambient>
+ <color>0 0 0 1</color>
+ </ambient>
+ <diffuse>
+ <texture texture="file23-sampler" texcoord="TEX0">
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <blend_mode>NONE</blend_mode>
+ <coverageU>1</coverageU>
+ <coverageV>1</coverageV>
+ <fast>0</fast>
+ <mirrorU>0</mirrorU>
+ <mirrorV>0</mirrorV>
+ <noiseU>0</noiseU>
+ <noiseV>0</noiseV>
+ <offsetU>0</offsetU>
+ <offsetV>0</offsetV>
+ <repeatU>1</repeatU>
+ <repeatV>1</repeatV>
+ <rotateFrame>0</rotateFrame>
+ <rotateUV>0</rotateUV>
+ <stagger>0</stagger>
+ <translateFrameU>0</translateFrameU>
+ <translateFrameV>0</translateFrameV>
+ <wrapU>1</wrapU>
+ <wrapV>1</wrapV>
+ </technique>
+ </extra>
+ </texture>
+ </diffuse>
+ <transparent opaque="RGB_ZERO">
+ <color>0 0 0 1</color>
+ </transparent>
+ <transparency>
+ <float>1</float>
+ </transparency>
+ </lambert>
+ </technique>
+ </profile_COMMON>
+ </effect>
+ <effect id="lambert10-fx">
+ <profile_COMMON>
+ <newparam sid="file28-surface">
+ <surface type="2D">
+ <init_from>file28</init_from>
+ </surface>
+ </newparam>
+ <newparam sid="file28-sampler">
+ <sampler2D>
+ <source>file28-surface</source>
+ </sampler2D>
+ </newparam>
+ <technique sid="common">
+ <lambert>
+ <emission>
+ <color>0 0 0 1</color>
+ </emission>
+ <ambient>
+ <color>0 0 0 1</color>
+ </ambient>
+ <diffuse>
+ <texture texture="file28-sampler" texcoord="TEX0">
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <blend_mode>NONE</blend_mode>
+ <coverageU>1</coverageU>
+ <coverageV>1</coverageV>
+ <fast>0</fast>
+ <mirrorU>0</mirrorU>
+ <mirrorV>0</mirrorV>
+ <noiseU>0</noiseU>
+ <noiseV>0</noiseV>
+ <offsetU>0</offsetU>
+ <offsetV>0</offsetV>
+ <repeatU>1</repeatU>
+ <repeatV>1</repeatV>
+ <rotateFrame>0</rotateFrame>
+ <rotateUV>0</rotateUV>
+ <stagger>0</stagger>
+ <translateFrameU>0</translateFrameU>
+ <translateFrameV>0</translateFrameV>
+ <wrapU>1</wrapU>
+ <wrapV>1</wrapV>
+ </technique>
+ </extra>
+ </texture>
+ </diffuse>
+ <transparent opaque="RGB_ZERO">
+ <color>0 0 0 1</color>
+ </transparent>
+ <transparency>
+ <float>1</float>
+ </transparency>
+ </lambert>
+ </technique>
+ </profile_COMMON>
+ </effect>
+ <effect id="lambert11-fx">
+ <profile_COMMON>
+ <newparam sid="file29-surface">
+ <surface type="2D">
+ <init_from>file29</init_from>
+ </surface>
+ </newparam>
+ <newparam sid="file29-sampler">
+ <sampler2D>
+ <source>file29-surface</source>
+ </sampler2D>
+ </newparam>
+ <technique sid="common">
+ <lambert>
+ <emission>
+ <color>0 0 0 1</color>
+ </emission>
+ <ambient>
+ <color>0 0 0 1</color>
+ </ambient>
+ <diffuse>
+ <texture texture="file29-sampler" texcoord="TEX0">
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <blend_mode>NONE</blend_mode>
+ <coverageU>1</coverageU>
+ <coverageV>1</coverageV>
+ <fast>0</fast>
+ <mirrorU>0</mirrorU>
+ <mirrorV>0</mirrorV>
+ <noiseU>0</noiseU>
+ <noiseV>0</noiseV>
+ <offsetU>0</offsetU>
+ <offsetV>0</offsetV>
+ <repeatU>1</repeatU>
+ <repeatV>1</repeatV>
+ <rotateFrame>0</rotateFrame>
+ <rotateUV>0</rotateUV>
+ <stagger>0</stagger>
+ <translateFrameU>0</translateFrameU>
+ <translateFrameV>0</translateFrameV>
+ <wrapU>1</wrapU>
+ <wrapV>1</wrapV>
+ </technique>
+ </extra>
+ </texture>
+ </diffuse>
+ <transparent opaque="RGB_ZERO">
+ <color>0 0 0 1</color>
+ </transparent>
+ <transparency>
+ <float>1</float>
+ </transparency>
+ </lambert>
+ </technique>
+ </profile_COMMON>
+ </effect>
+ <effect id="lambert2-fx">
+ <profile_COMMON>
+ <newparam sid="file22-surface">
+ <surface type="2D">
+ <init_from>file22</init_from>
+ </surface>
+ </newparam>
+ <newparam sid="file22-sampler">
+ <sampler2D>
+ <source>file22-surface</source>
+ </sampler2D>
+ </newparam>
+ <technique sid="common">
+ <lambert>
+ <emission>
+ <color>0 0 0 1</color>
+ </emission>
+ <ambient>
+ <color>0 0 0 1</color>
+ </ambient>
+ <diffuse>
+ <texture texture="file22-sampler" texcoord="TEX0">
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <blend_mode>NONE</blend_mode>
+ <coverageU>1</coverageU>
+ <coverageV>1</coverageV>
+ <fast>0</fast>
+ <mirrorU>0</mirrorU>
+ <mirrorV>0</mirrorV>
+ <noiseU>0</noiseU>
+ <noiseV>0</noiseV>
+ <offsetU>0</offsetU>
+ <offsetV>0</offsetV>
+ <repeatU>1</repeatU>
+ <repeatV>1</repeatV>
+ <rotateFrame>0</rotateFrame>
+ <rotateUV>0</rotateUV>
+ <stagger>0</stagger>
+ <translateFrameU>0</translateFrameU>
+ <translateFrameV>0</translateFrameV>
+ <wrapU>1</wrapU>
+ <wrapV>1</wrapV>
+ </technique>
+ </extra>
+ </texture>
+ </diffuse>
+ <transparent opaque="RGB_ZERO">
+ <color>0 0 0 1</color>
+ </transparent>
+ <transparency>
+ <float>1</float>
+ </transparency>
+ </lambert>
+ </technique>
+ </profile_COMMON>
+ </effect>
+ </library_effects>
+ <library_images>
+ <image id="file29" name="file29" height="0" width="0">
+ <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/blue.jpg</init_from>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <dgnode_type>kFile</dgnode_type>
+ <image_sequence>0</image_sequence>
+ <originalMayaNodeId>file29</originalMayaNodeId>
+ </technique>
+ </extra>
+ </image>
+ <image id="file25" name="file25" height="0" width="0">
+ <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/carbonfiber.jpg</init_from>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <dgnode_type>kFile</dgnode_type>
+ <image_sequence>0</image_sequence>
+ <originalMayaNodeId>file25</originalMayaNodeId>
+ </technique>
+ </extra>
+ </image>
+ <image id="file28" name="file28" height="0" width="0">
+ <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/green.jpg</init_from>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <dgnode_type>kFile</dgnode_type>
+ <image_sequence>0</image_sequence>
+ <originalMayaNodeId>file28</originalMayaNodeId>
+ </technique>
+ </extra>
+ </image>
+ <image id="file22" name="file22" height="0" width="0">
+ <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/grey.jpg</init_from>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <dgnode_type>kFile</dgnode_type>
+ <image_sequence>0</image_sequence>
+ <originalMayaNodeId>file22</originalMayaNodeId>
+ </technique>
+ </extra>
+ </image>
+ <image id="file24" name="file24" height="0" width="0">
+ <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/orange.jpg</init_from>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <dgnode_type>kFile</dgnode_type>
+ <image_sequence>0</image_sequence>
+ <originalMayaNodeId>file24</originalMayaNodeId>
+ </technique>
+ </extra>
+ </image>
+ <image id="file23" name="file23" height="0" width="0">
+ <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/red.jpg</init_from>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <dgnode_type>kFile</dgnode_type>
+ <image_sequence>0</image_sequence>
+ <originalMayaNodeId>file23</originalMayaNodeId>
+ </technique>
+ </extra>
+ </image>
+ </library_images>
+ <library_visual_scenes>
+ <visual_scene id="VisualSceneNode" name="orientation_test">
+ <node id="camera1" name="camera1">
+ <translate sid="translate">24.5791 14.1321 31.4654</translate>
+ <rotate sid="rotateZ">0 0 1 0</rotate>
+ <rotate sid="rotateY">0 1 0 42</rotate>
+ <rotate sid="rotateX">1 0 0 -16.2</rotate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_camera url="#cameraShape1" />
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>camera1</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="CameraAim" name="CameraAim">
+ <translate sid="translate">0.0209301 3.68542 2.06912</translate>
+ <rotate sid="rotateY">0 1 0 43.2561</rotate>
+ <rotate sid="rotateX">1 0 0 -20</rotate>
+ <scale sid="scale">1 1 1</scale>
+ <node id="CameraDist" name="CameraDist">
+ <translate sid="translate">0 0 45</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_camera url="#CameraDistShape" />
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>CameraDist</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>CameraAim</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere4" name="pSphere4">
+ <translate sid="translate">-9.69237 0 7.70498</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape4">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert7SG" target="#Paint1">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere4</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere1" name="pSphere1">
+ <translate sid="translate">13.0966 0 5.76254</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape1">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert7SG" target="#Paint1">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere1</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere2" name="pSphere2">
+ <translate sid="translate">21.7661 0 -13.6375</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape2">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert7SG" target="#Paint1">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere2</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere3" name="pSphere3">
+ <translate sid="translate">-13.862 0 -13.6154</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape3">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert7SG" target="#Paint1">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere3</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere5" name="pSphere5">
+ <translate sid="translate">31.0862 0 18.5992</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape5">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert7SG" target="#Paint1">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere5</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pCube1" name="pCube1">
+ <translate sid="translate">0 0 0</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pCubeShape1">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert4SG" target="#lambert2">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pCube1</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="group1" name="group1">
+ <translate sid="translate">0 0 0</translate>
+ <rotate sid="rotateZ">0 0 1 -162.693</rotate>
+ <rotate sid="rotateY">0 1 0 21.3345</rotate>
+ <rotate sid="rotateX">1 0 0 -100.567</rotate>
+ <scale sid="scale">1 1 1</scale>
+ <node id="pSphere6" name="pSphere6">
+ <translate sid="translate">-13.862 0 -13.6154</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape6">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert6SG" target="#Plastic">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere6</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere7" name="pSphere7">
+ <translate sid="translate">-9.69237 0 7.70498</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape7">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert6SG" target="#Plastic">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere7</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere8" name="pSphere8">
+ <translate sid="translate">21.7661 0 -13.6375</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape8">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert6SG" target="#Plastic">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere8</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere9" name="pSphere9">
+ <translate sid="translate">13.0966 0 5.76254</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape9">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert6SG" target="#Plastic">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere9</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>group1</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="group2" name="group2">
+ <translate sid="translate">0 0 0</translate>
+ <rotate sid="rotateZ">0 0 1 45.4017</rotate>
+ <rotate sid="rotateY">0 1 0 79.393</rotate>
+ <rotate sid="rotateX">1 0 0 5.10889</rotate>
+ <scale sid="scale">1 1 1</scale>
+ <node id="pSphere10" name="pSphere10">
+ <translate sid="translate">31.0862 0 18.5992</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape10">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert5SG" target="#Metal">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere10</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere11" name="pSphere11">
+ <translate sid="translate">13.0966 0 5.76254</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape11">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert5SG" target="#Metal">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere11</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere12" name="pSphere12">
+ <translate sid="translate">7.4784 16.3496 7.36882</translate>
+ <rotate sid="rotateZ">0 0 1 17.3073</rotate>
+ <rotate sid="rotateY">0 1 0 158.666</rotate>
+ <rotate sid="rotateX">1 0 0 79.4335</rotate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape12">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert5SG" target="#Metal">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere12</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere13" name="pSphere13">
+ <translate sid="translate">-9.69237 0 7.70498</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape13">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert5SG" target="#Metal">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere13</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere14" name="pSphere14">
+ <translate sid="translate">11.3635 -4.3926 2.21012</translate>
+ <rotate sid="rotateZ">0 0 1 17.3073</rotate>
+ <rotate sid="rotateY">0 1 0 158.666</rotate>
+ <rotate sid="rotateX">1 0 0 79.4335</rotate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape14">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert5SG" target="#Metal">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere14</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere15" name="pSphere15">
+ <translate sid="translate">21.7661 0 -13.6375</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape15">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert5SG" target="#Metal">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere15</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere16" name="pSphere16">
+ <translate sid="translate">-9.5945 -8.92317 -5.74901</translate>
+ <rotate sid="rotateZ">0 0 1 17.3073</rotate>
+ <rotate sid="rotateY">0 1 0 158.666</rotate>
+ <rotate sid="rotateX">1 0 0 79.4335</rotate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape16">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert5SG" target="#Metal">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere16</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere17" name="pSphere17">
+ <translate sid="translate">-13.862 0 -13.6154</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape17">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert5SG" target="#Metal">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere17</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pSphere18" name="pSphere18">
+ <translate sid="translate">-24.2135 6.497 -5.58935</translate>
+ <rotate sid="rotateZ">0 0 1 17.3073</rotate>
+ <rotate sid="rotateY">0 1 0 158.666</rotate>
+ <rotate sid="rotateX">1 0 0 79.4335</rotate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pSphereShape18">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert5SG" target="#Metal">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pSphere18</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>group2</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pCube2" name="pCube2">
+ <translate sid="translate">0 0 0</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pCubeShape2">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert8SG" target="#PlasticCenter">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pCube2</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pCube3" name="pCube3">
+ <translate sid="translate">15 0 0</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pCubeShape3">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert9SG" target="#PlasticRed">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pCube3</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pCube4" name="pCube4">
+ <translate sid="translate">0 15 0</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pCubeShape4">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert10SG" target="#lambert10">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pCube4</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ <node id="pCube5" name="pCube5">
+ <translate sid="translate">0 0 15</translate>
+ <scale sid="scale">1 1 1</scale>
+ <instance_geometry url="#pCubeShape5">
+ <bind_material>
+ <technique_common>
+ <instance_material symbol="lambert11SG" target="#lambert11">
+ <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" />
+ </instance_material>
+ </technique_common>
+ </bind_material>
+ </instance_geometry>
+ <extra>
+ <technique profile="OpenCOLLADAMaya">
+ <originalMayaNodeId>pCube5</originalMayaNodeId>
+ </technique>
+ </extra>
+ </node>
+ </visual_scene>
+ </library_visual_scenes>
+ <scene>
+ <instance_visual_scene url="#VisualSceneNode" />
+ </scene>
+</COLLADA>
diff --git a/tests/RenderScriptTests/SceneGraph/assets/paint.jpg b/tests/RenderScriptTests/SceneGraph/assets/paint.jpg
new file mode 100644
index 000000000000..0791045b5c18
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/paint.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/assets/red.jpg b/tests/RenderScriptTests/SceneGraph/assets/red.jpg
new file mode 100644
index 000000000000..320a2a6ad187
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/assets/red.jpg
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/res/drawable-nodpi/robot.png b/tests/RenderScriptTests/SceneGraph/res/drawable-nodpi/robot.png
new file mode 100644
index 000000000000..f7353fd61c5b
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/drawable-nodpi/robot.png
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/res/menu/loader_menu.xml b/tests/RenderScriptTests/SceneGraph/res/menu/loader_menu.xml
new file mode 100644
index 000000000000..9ea3010759b6
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/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/load_model"
+ android:title="@string/load_model" />
+ <item android:id="@+id/use_blur"
+ android:title="@string/use_blur" />
+</menu>
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/blur_h.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/blur_h.glsl
new file mode 100644
index 000000000000..fa468cc3620c
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/blur_h.glsl
@@ -0,0 +1,15 @@
+varying vec2 varTex0;
+
+void main() {
+ vec2 blurCoord = varTex0;
+ blurCoord.x = varTex0.x + UNI_blurOffset0;
+ vec3 col = texture2D(UNI_Tex0, blurCoord).rgb;
+ blurCoord.x = varTex0.x + UNI_blurOffset1;
+ col += texture2D(UNI_Tex0, blurCoord).rgb;
+ blurCoord.x = varTex0.x + UNI_blurOffset2;
+ col += texture2D(UNI_Tex0, blurCoord).rgb;
+ blurCoord.x = varTex0.x + UNI_blurOffset3;
+ col += texture2D(UNI_Tex0, blurCoord).rgb;
+
+ gl_FragColor = vec4(col * 0.25, 0.0); //texture2D(UNI_Tex0, varTex0);
+}
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/blur_v.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/blur_v.glsl
new file mode 100644
index 000000000000..a644a3e6b8fb
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/blur_v.glsl
@@ -0,0 +1,17 @@
+varying vec2 varTex0;
+
+void main() {
+ vec2 blurCoord = varTex0;
+ blurCoord.y = varTex0.y + UNI_blurOffset0;
+ vec3 col = texture2D(UNI_Tex0, blurCoord).rgb;
+ blurCoord.y = varTex0.y + UNI_blurOffset1;
+ col += texture2D(UNI_Tex0, blurCoord).rgb;
+ blurCoord.y = varTex0.y + UNI_blurOffset2;
+ col += texture2D(UNI_Tex0, blurCoord).rgb;
+ blurCoord.y = varTex0.y + UNI_blurOffset3;
+ col += texture2D(UNI_Tex0, blurCoord).rgb;
+
+ col = col * 0.25;
+
+ gl_FragColor = vec4(col, 0.0); //texture2D(UNI_Tex0, varTex0);
+}
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/blur_vertex.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/blur_vertex.glsl
new file mode 100644
index 000000000000..bc824b6eb77e
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/blur_vertex.glsl
@@ -0,0 +1,7 @@
+varying vec2 varTex0;
+
+void main() {
+ gl_Position = ATTRIB_position;
+ varTex0 = ATTRIB_texture0;
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/diffuse.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/diffuse.glsl
new file mode 100644
index 000000000000..5d8938bc5a4e
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/diffuse.glsl
@@ -0,0 +1,19 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+void main() {
+
+ vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz);
+ vec3 worldNorm = (varWorldNormal);
+
+ vec3 light0Vec = V;
+ vec3 light0R = reflect(light0Vec, worldNorm);
+ float light0_Diffuse = dot(worldNorm, light0Vec);
+
+ vec2 t0 = varTex0.xy;
+ lowp vec4 col = texture2D(UNI_Tex0, t0).rgba;
+ col.xyz = col.xyz * light0_Diffuse * 1.2;
+ gl_FragColor = col; //vec4(0.0, 1.0, 0.0, 0.0);
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/metal.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/metal.glsl
new file mode 100644
index 000000000000..51f06124d759
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/metal.glsl
@@ -0,0 +1,23 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+void main() {
+
+ vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz);
+ vec3 worldNorm = normalize(varWorldNormal);
+
+ vec3 light0Vec = V;
+ vec3 light0R = reflect(light0Vec, worldNorm);
+ float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0);
+ float light0Spec = clamp(dot(-light0R, V), 0.001, 1.0);
+ float light0_Specular = pow(light0Spec, 15.0) * 0.5;
+
+ vec2 t0 = varTex0.xy;
+ lowp vec4 col = texture2D(UNI_Tex0, t0).rgba;
+ col.xyz = col.xyz * (textureCube(UNI_Tex1, worldNorm).rgb * 0.5 + vec3(light0_Diffuse));
+ col.xyz += light0_Specular * vec3(0.8, 0.8, 1.0);
+
+ gl_FragColor = col;
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/paintf.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/paintf.glsl
new file mode 100644
index 000000000000..893d55399003
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/paintf.glsl
@@ -0,0 +1,26 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+void main() {
+
+ vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz);
+ vec3 worldNorm = normalize(varWorldNormal);
+
+ vec3 light0Vec = V;
+ vec3 light0R = reflect(light0Vec, worldNorm);
+ float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.01, 0.99);
+ float light0Spec = clamp(dot(-light0R, V), 0.001, 1.0);
+ float light0_Specular = pow(light0Spec, 150.0) * 0.5;
+
+ vec2 t0 = varTex0.xy;
+ lowp vec4 col = texture2D(UNI_Tex0, t0).rgba;
+ col.xyz = col.xyz * light0_Diffuse * 1.1;
+ col.xyz += light0_Specular * vec3(0.8, 0.8, 1.0);
+
+ float fresnel = mix(pow(1.0 - light0_Diffuse, 15.0), 1.0, 0.1);
+ col.xyz = mix(col.xyz, textureCube(UNI_Tex1, -light0R).rgb * 2.4, fresnel);
+ col.w = 0.8;
+ gl_FragColor = col;
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/plastic.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/plastic.glsl
new file mode 100644
index 000000000000..ceb53bd232d2
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/plastic.glsl
@@ -0,0 +1,22 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+void main() {
+
+ vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz);
+ vec3 worldNorm = normalize(varWorldNormal);
+
+ vec3 light0Vec = V;
+ vec3 light0R = reflect(light0Vec, worldNorm);
+ float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0);
+ float light0Spec = clamp(dot(-light0R, V), 0.001, 1.0);
+ float light0_Specular = pow(light0Spec, 10.0) * 0.5;
+
+ vec2 t0 = varTex0.xy;
+ lowp vec4 col = texture2D(UNI_Tex0, t0).rgba;
+ col.xyz = col.xyz * light0_Diffuse * 1.2;
+ col.xyz += light0_Specular * vec3(0.8, 0.8, 1.0);
+ gl_FragColor = col;
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/plastic_lights.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/plastic_lights.glsl
new file mode 100644
index 000000000000..b2536226afb7
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/plastic_lights.glsl
@@ -0,0 +1,29 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+void main() {
+
+ vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz);
+ vec3 worldNorm = normalize(varWorldNormal);
+
+ vec3 light0Vec = normalize(UNI_lightPos_0.xyz - varWorldPos.xyz);
+ vec3 light0R = reflect(light0Vec, worldNorm);
+ float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0);
+ float light0Spec = clamp(dot(-light0R, V), 0.001, 1.0);
+ float light0_Specular = pow(light0Spec, 10.0) * 0.7;
+
+ vec3 light1Vec = normalize(UNI_lightPos_1.xyz - varWorldPos.xyz);
+ vec3 light1R = reflect(light1Vec, worldNorm);
+ float light1_Diffuse = clamp(dot(worldNorm, light1Vec), 0.0, 1.0);
+ float light1Spec = clamp(dot(-light1R, V), 0.001, 1.0);
+ float light1_Specular = pow(light1Spec, 10.0) * 0.7;
+
+ vec2 t0 = varTex0.xy;
+ lowp vec4 col = UNI_diffuse;
+ col.xyz = col.xyz * (light0_Diffuse * UNI_lightColor_0.xyz +
+ light1_Diffuse * UNI_lightColor_1.xyz);
+ col.xyz += (light0_Specular + light1_Specular);
+ gl_FragColor = col;
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/robot.a3d b/tests/RenderScriptTests/SceneGraph/res/raw/robot.a3d
new file mode 100644
index 000000000000..f48895cd8451
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/robot.a3d
Binary files differ
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/select_color.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/select_color.glsl
new file mode 100644
index 000000000000..42b231aa8657
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/select_color.glsl
@@ -0,0 +1,13 @@
+varying vec2 varTex0;
+
+void main() {
+ vec3 col = texture2D(UNI_Tex0, varTex0).rgb;
+
+ vec3 desat = vec3(0.299, 0.587, 0.114);
+ float lum = dot(desat, col);
+ float stepVal = step(lum, 0.8);
+ col = mix(col, vec3(0.0), stepVal)*0.5;
+
+ gl_FragColor = vec4(col, 0.0);
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/shader2v.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/shader2v.glsl
new file mode 100644
index 000000000000..1ea234f0a77b
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/shader2v.glsl
@@ -0,0 +1,17 @@
+varying vec3 varWorldPos;
+varying vec3 varWorldNormal;
+varying vec2 varTex0;
+
+// This is where actual shader code begins
+void main() {
+ vec4 objPos = ATTRIB_position;
+ vec4 worldPos = UNI_model * objPos;
+ gl_Position = UNI_viewProj * worldPos;
+
+ mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz);
+ vec3 worldNorm = model3 * ATTRIB_normal;
+
+ varWorldPos = worldPos.xyz;
+ varWorldNormal = worldNorm;
+ varTex0 = ATTRIB_texture0;
+}
diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/texture.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/texture.glsl
new file mode 100644
index 000000000000..dd709cf01f9d
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/res/raw/texture.glsl
@@ -0,0 +1,7 @@
+varying vec2 varTex0;
+
+void main() {
+ lowp vec4 col = texture2D(UNI_Tex0, varTex0).rgba;
+ gl_FragColor = col;
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/res/values/strings.xml b/tests/RenderScriptTests/SceneGraph/res/values/strings.xml
new file mode 100644
index 000000000000..c916d791c143
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/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="load_model">Load Model</string>
+ <string name="use_blur">Use Blur</string>
+</resources>
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Camera.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Camera.java
new file mode 100644
index 000000000000..42f2be5e1f59
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Camera.java
@@ -0,0 +1,118 @@
+/*
+ * 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.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import com.android.scenegraph.SceneManager;
+
+import android.renderscript.*;
+import android.renderscript.Matrix4f;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class Camera extends SceneGraphBase {
+
+ Transform mTransform;
+
+ ScriptField_Camera_s.Item mData;
+ ScriptField_Camera_s mField;
+
+ public Camera() {
+ mData = new ScriptField_Camera_s.Item();
+ mData.near = 0.1f;
+ mData.far = 1000.0f;
+ mData.horizontalFOV = 60.0f;
+ mData.aspect = 0;
+ }
+
+ public void setTransform(Transform t) {
+ mTransform = t;
+ if (mField != null) {
+ mField.set_transformMatrix(0, mTransform.getRSData().getAllocation(), true);
+ mField.set_isDirty(0, 1, true);
+ }
+ }
+ public void setFOV(float fov) {
+ mData.horizontalFOV = fov;
+ if (mField != null) {
+ mField.set_horizontalFOV(0, fov, true);
+ mField.set_isDirty(0, 1, true);
+ }
+ }
+
+ public void setNear(float n) {
+ mData.near = n;
+ if (mField != null) {
+ mField.set_near(0, n, true);
+ mField.set_isDirty(0, 1, true);
+ }
+ }
+
+ public void setFar(float f) {
+ mData.far = f;
+ if (mField != null) {
+ mField.set_far(0, f, true);
+ mField.set_isDirty(0, 1, true);
+ }
+ }
+
+ public void setName(String n) {
+ super.setName(n);
+ if (mField != null) {
+ RenderScriptGL rs = SceneManager.getRS();
+ mData.name = getNameAlloc(rs);
+ mField.set_name(0, mData.name, true);
+ mField.set_isDirty(0, 1, true);
+ }
+ }
+
+ ScriptField_Camera_s getRSData() {
+ if (mField != null) {
+ return mField;
+ }
+
+ RenderScriptGL rs = SceneManager.getRS();
+ if (rs == null) {
+ return null;
+ }
+
+ if (mTransform == null) {
+ throw new RuntimeException("Cameras without transforms are invalid");
+ }
+
+ mField = new ScriptField_Camera_s(rs, 1);
+
+ mData.transformMatrix = mTransform.getRSData().getAllocation();
+ mData.transformTimestamp = 1;
+ mData.timestamp = 1;
+ mData.isDirty = 1;
+ mData.name = getNameAlloc(rs);
+ mField.set(mData, 0, true);
+
+ return mField;
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaParser.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaParser.java
new file mode 100644
index 000000000000..d954313da12d
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaParser.java
@@ -0,0 +1,563 @@
+/*
+ * 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.scenegraph;
+import com.android.scenegraph.CompoundTransform.TranslateComponent;
+import com.android.scenegraph.CompoundTransform.RotateComponent;
+import com.android.scenegraph.CompoundTransform.ScaleComponent;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.StringTokenizer;
+import java.util.HashMap;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import android.renderscript.*;
+import android.util.Log;
+
+public class ColladaParser {
+ static final String TAG = "ColladaParser";
+ Document mDom;
+
+ HashMap<String, LightBase> mLights;
+ HashMap<String, Camera> mCameras;
+ HashMap<String, ArrayList<ShaderParam> > mEffectsParams;
+ HashMap<String, Texture2D> mImages;
+ HashMap<String, Texture2D> mSamplerImageMap;
+ HashMap<String, String> mMeshIdNameMap;
+ Scene mScene;
+
+ String mRootDir;
+
+ String toString(Float3 v) {
+ String valueStr = v.x + " " + v.y + " " + v.z;
+ return valueStr;
+ }
+
+ String toString(Float4 v) {
+ String valueStr = v.x + " " + v.y + " " + v.z + " " + v.w;
+ return valueStr;
+ }
+
+ public ColladaParser(){
+ mLights = new HashMap<String, LightBase>();
+ mCameras = new HashMap<String, Camera>();
+ mEffectsParams = new HashMap<String, ArrayList<ShaderParam> >();
+ mImages = new HashMap<String, Texture2D>();
+ mMeshIdNameMap = new HashMap<String, String>();
+ }
+
+ public void init(InputStream is, String rootDir) {
+ mLights.clear();
+ mCameras.clear();
+ mEffectsParams.clear();
+
+ mRootDir = rootDir;
+
+ long start = System.currentTimeMillis();
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ try {
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ mDom = db.parse(is);
+ } catch(ParserConfigurationException e) {
+ e.printStackTrace();
+ } catch(SAXException e) {
+ e.printStackTrace();
+ } catch(IOException e) {
+ e.printStackTrace();
+ }
+ long end = System.currentTimeMillis();
+ Log.v("TIMER", " Parse time: " + (end - start));
+ exportSceneData();
+ }
+
+ Scene getScene() {
+ return mScene;
+ }
+
+ private void exportSceneData(){
+ mScene = new Scene();
+
+ Element docEle = mDom.getDocumentElement();
+ NodeList nl = docEle.getElementsByTagName("light");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element l = (Element)nl.item(i);
+ convertLight(l);
+ }
+ }
+
+ nl = docEle.getElementsByTagName("camera");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element c = (Element)nl.item(i);
+ convertCamera(c);
+ }
+ }
+
+ nl = docEle.getElementsByTagName("image");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element img = (Element)nl.item(i);
+ convertImage(img);
+ }
+ }
+
+ nl = docEle.getElementsByTagName("effect");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element e = (Element)nl.item(i);
+ convertEffects(e);
+ }
+ }
+
+ // Material is just a link to the effect
+ nl = docEle.getElementsByTagName("material");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element m = (Element)nl.item(i);
+ convertMaterials(m);
+ }
+ }
+
+ // Look through the geometry list and build up a correlation between id's and names
+ nl = docEle.getElementsByTagName("geometry");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element m = (Element)nl.item(i);
+ convertGeometries(m);
+ }
+ }
+
+
+ nl = docEle.getElementsByTagName("visual_scene");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element s = (Element)nl.item(i);
+ getScene(s);
+ }
+ }
+ }
+
+ private void getRenderable(Element shape, Transform t) {
+ String geoURL = shape.getAttribute("url").substring(1);
+ String geoName = mMeshIdNameMap.get(geoURL);
+ if (geoName != null) {
+ geoURL = geoName;
+ }
+ //RenderableGroup group = new RenderableGroup();
+ //group.setName(geoURL.substring(1));
+ //mScene.appendRenderable(group);
+ NodeList nl = shape.getElementsByTagName("instance_material");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element materialRef = (Element)nl.item(i);
+ String meshIndexName = materialRef.getAttribute("symbol");
+ String materialName = materialRef.getAttribute("target");
+
+ Renderable d = new Renderable();
+ d.setMesh(geoURL, meshIndexName);
+ d.setMaterialName(materialName.substring(1));
+ d.setName(geoURL);
+
+ //Log.v(TAG, "Created drawable geo " + geoURL + " index " + meshIndexName + " material " + materialName);
+
+ d.setTransform(t);
+ //Log.v(TAG, "Set source param " + t.getName());
+
+ // Now find all the parameters that exist on the material
+ ArrayList<ShaderParam> materialParams;
+ materialParams = mEffectsParams.get(materialName.substring(1));
+ for (int pI = 0; pI < materialParams.size(); pI ++) {
+ d.appendSourceParams(materialParams.get(pI));
+ //Log.v(TAG, "Set source param i: " + pI + " name " + materialParams.get(pI).getParamName());
+ }
+ mScene.appendRenderable(d);
+ //group.appendChildren(d);
+ }
+ }
+ }
+
+ private void updateLight(Element shape, Transform t) {
+ String lightURL = shape.getAttribute("url");
+ // collada uses a uri structure to link things,
+ // but we ignore it for now and do a simple search
+ LightBase light = mLights.get(lightURL.substring(1));
+ if (light != null) {
+ light.setTransform(t);
+ //Log.v(TAG, "Set Light " + light.getName() + " " + t.getName());
+ }
+ }
+
+ private void updateCamera(Element shape, Transform t) {
+ String camURL = shape.getAttribute("url");
+ // collada uses a uri structure to link things,
+ // but we ignore it for now and do a simple search
+ Camera cam = mCameras.get(camURL.substring(1));
+ if (cam != null) {
+ cam.setTransform(t);
+ //Log.v(TAG, "Set Camera " + cam.getName() + " " + t.getName());
+ }
+ }
+
+ private void getNode(Element node, Transform parent, String indent) {
+ String name = node.getAttribute("name");
+ String id = node.getAttribute("id");
+ CompoundTransform current = new CompoundTransform();
+ current.setName(name);
+ if (parent != null) {
+ parent.appendChild(current);
+ } else {
+ mScene.appendTransform(current);
+ }
+
+ mScene.addToTransformMap(current);
+
+ //Log.v(TAG, indent + "|");
+ //Log.v(TAG, indent + "[" + name + "]");
+
+ Node childNode = node.getFirstChild();
+ while (childNode != null) {
+ if (childNode.getNodeType() == Node.ELEMENT_NODE) {
+ Element field = (Element)childNode;
+ String fieldName = field.getTagName();
+ String description = field.getAttribute("sid");
+ if (fieldName.equals("translate")) {
+ Float3 value = getFloat3(field);
+ current.addComponent(new TranslateComponent(description, value));
+ //Log.v(TAG, indent + " translate " + description + toString(value));
+ } else if (fieldName.equals("rotate")) {
+ Float4 value = getFloat4(field);
+ //Log.v(TAG, indent + " rotate " + description + toString(value));
+ Float3 axis = new Float3(value.x, value.y, value.z);
+ current.addComponent(new RotateComponent(description, axis, value.w));
+ } else if (fieldName.equals("scale")) {
+ Float3 value = getFloat3(field);
+ //Log.v(TAG, indent + " scale " + description + toString(value));
+ current.addComponent(new ScaleComponent(description, value));
+ } else if (fieldName.equals("instance_geometry")) {
+ getRenderable(field, current);
+ } else if (fieldName.equals("instance_light")) {
+ updateLight(field, current);
+ } else if (fieldName.equals("instance_camera")) {
+ updateCamera(field, current);
+ } else if (fieldName.equals("node")) {
+ getNode(field, current, indent + " ");
+ }
+ }
+ childNode = childNode.getNextSibling();
+ }
+ }
+
+ // This will find the actual texture node, which is sometimes hidden behind a sampler
+ // and sometimes referenced directly
+ Texture2D getTexture(String samplerName) {
+ String texName = samplerName;
+
+ // Check to see if the image file is hidden by a sampler surface link combo
+ Element sampler = mDom.getElementById(samplerName);
+ if (sampler != null) {
+ NodeList nl = sampler.getElementsByTagName("source");
+ if (nl != null && nl.getLength() == 1) {
+ Element ref = (Element)nl.item(0);
+ String surfaceName = getString(ref);
+ if (surfaceName == null) {
+ return null;
+ }
+
+ Element surface = mDom.getElementById(surfaceName);
+ if (surface == null) {
+ return null;
+ }
+ nl = surface.getElementsByTagName("init_from");
+ if (nl != null && nl.getLength() == 1) {
+ ref = (Element)nl.item(0);
+ texName = getString(ref);
+ }
+ }
+ }
+
+ //Log.v(TAG, "Extracted texture name " + texName);
+ return mImages.get(texName);
+ }
+
+ void extractParams(Element fx, ArrayList<ShaderParam> params) {
+ Node paramNode = fx.getFirstChild();
+ while (paramNode != null) {
+ if (paramNode.getNodeType() == Node.ELEMENT_NODE) {
+ String name = paramNode.getNodeName();
+ // Now find what type it is
+ Node typeNode = paramNode.getFirstChild();
+ while (typeNode != null && typeNode.getNodeType() != Node.ELEMENT_NODE) {
+ typeNode = typeNode.getNextSibling();
+ }
+ String paramType = typeNode.getNodeName();
+ Element typeElem = (Element)typeNode;
+ ShaderParam sceneParam = null;
+ if (paramType.equals("color")) {
+ Float4Param f4p = new Float4Param(name);
+ Float4 value = getFloat4(typeElem);
+ f4p.setValue(value);
+ sceneParam = f4p;
+ //Log.v(TAG, "Extracted " + sceneParam.getParamName() + " value " + toString(value));
+ } else if (paramType.equals("float")) {
+ Float4Param f4p = new Float4Param(name);
+ float value = getFloat(typeElem);
+ f4p.setValue(new Float4(value, value, value, value));
+ sceneParam = f4p;
+ //Log.v(TAG, "Extracted " + sceneParam.getParamName() + " value " + value);
+ } else if (paramType.equals("texture")) {
+ String samplerName = typeElem.getAttribute("texture");
+ Texture2D tex = getTexture(samplerName);
+ TextureParam texP = new TextureParam(name);
+ texP.setTexture(tex);
+ sceneParam = texP;
+ //Log.v(TAG, "Extracted texture " + tex);
+ }
+ if (sceneParam != null) {
+ params.add(sceneParam);
+ }
+ }
+ paramNode = paramNode.getNextSibling();
+ }
+ }
+
+ private void convertMaterials(Element mat) {
+ String id = mat.getAttribute("id");
+ NodeList nl = mat.getElementsByTagName("instance_effect");
+ if (nl != null && nl.getLength() == 1) {
+ Element ref = (Element)nl.item(0);
+ String url = ref.getAttribute("url");
+ ArrayList<ShaderParam> params = mEffectsParams.get(url.substring(1));
+ mEffectsParams.put(id, params);
+ }
+ }
+
+ private void convertGeometries(Element geo) {
+ String id = geo.getAttribute("id");
+ String name = geo.getAttribute("name");
+ if (!id.equals(name)) {
+ mMeshIdNameMap.put(id, name);
+ }
+ }
+
+ private void convertEffects(Element fx) {
+ String id = fx.getAttribute("id");
+ ArrayList<ShaderParam> params = new ArrayList<ShaderParam>();
+
+ NodeList nl = fx.getElementsByTagName("newparam");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element field = (Element)nl.item(i);
+ field.setIdAttribute("sid", true);
+ }
+ }
+
+ nl = fx.getElementsByTagName("blinn");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element field = (Element)nl.item(i);
+ //Log.v(TAG, "blinn");
+ extractParams(field, params);
+ }
+ }
+ nl = fx.getElementsByTagName("lambert");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element field = (Element)nl.item(i);
+ //Log.v(TAG, "lambert");
+ extractParams(field, params);
+ }
+ }
+ nl = fx.getElementsByTagName("phong");
+ if (nl != null) {
+ for(int i = 0; i < nl.getLength(); i++) {
+ Element field = (Element)nl.item(i);
+ //Log.v(TAG, "phong");
+ extractParams(field, params);
+ }
+ }
+ mEffectsParams.put(id, params);
+ }
+
+ private void convertLight(Element light) {
+ String name = light.getAttribute("name");
+ String id = light.getAttribute("id");
+
+ // Determine type
+ String[] knownTypes = { "point", "spot", "directional" };
+ final int POINT_LIGHT = 0;
+ final int SPOT_LIGHT = 1;
+ final int DIR_LIGHT = 2;
+ int type = -1;
+ for (int i = 0; i < knownTypes.length; i ++) {
+ NodeList nl = light.getElementsByTagName(knownTypes[i]);
+ if (nl != null && nl.getLength() != 0) {
+ type = i;
+ break;
+ }
+ }
+
+ //Log.v(TAG, "Found Light Type " + type);
+
+ LightBase sceneLight = null;
+ switch (type) {
+ case POINT_LIGHT:
+ sceneLight = new PointLight();
+ break;
+ case SPOT_LIGHT: // TODO: finish light types
+ break;
+ case DIR_LIGHT: // TODO: finish light types
+ break;
+ }
+
+ if (sceneLight == null) {
+ return;
+ }
+
+ Float3 color = getFloat3(light, "color");
+ sceneLight.setColor(color.x, color.y, color.z);
+ sceneLight.setName(name);
+ mScene.appendLight(sceneLight);
+ mLights.put(id, sceneLight);
+
+ //Log.v(TAG, "Light " + name + " color " + toString(color));
+ }
+
+ private void convertCamera(Element camera) {
+ String name = camera.getAttribute("name");
+ String id = camera.getAttribute("id");
+ float fov = 30.0f;
+ if (getString(camera, "yfov") != null) {
+ fov = getFloat(camera, "yfov");
+ } else if(getString(camera, "xfov") != null) {
+ float aspect = getFloat(camera, "aspect_ratio");
+ fov = getFloat(camera, "xfov") / aspect;
+ }
+
+ float near = getFloat(camera, "znear");
+ float far = getFloat(camera, "zfar");
+
+ Camera sceneCamera = new Camera();
+ sceneCamera.setFOV(fov);
+ sceneCamera.setNear(near);
+ sceneCamera.setFar(far);
+ sceneCamera.setName(name);
+ mScene.appendCamera(sceneCamera);
+ mCameras.put(id, sceneCamera);
+ }
+
+ private void convertImage(Element img) {
+ String name = img.getAttribute("name");
+ String id = img.getAttribute("id");
+ String file = getString(img, "init_from");
+
+ Texture2D tex = new Texture2D();
+ tex.setFileName(file);
+ tex.setFileDir(mRootDir);
+ mScene.appendTextures(tex);
+ mImages.put(id, tex);
+ }
+
+ private void getScene(Element scene) {
+ String name = scene.getAttribute("name");
+ String id = scene.getAttribute("id");
+
+ Node childNode = scene.getFirstChild();
+ while (childNode != null) {
+ if (childNode.getNodeType() == Node.ELEMENT_NODE) {
+ String indent = "";
+ getNode((Element)childNode, null, indent);
+ }
+ childNode = childNode.getNextSibling();
+ }
+ }
+
+ private String getString(Element elem, String name) {
+ String text = null;
+ NodeList nl = elem.getElementsByTagName(name);
+ if (nl != null && nl.getLength() != 0) {
+ text = ((Element)nl.item(0)).getFirstChild().getNodeValue();
+ }
+ return text;
+ }
+
+ private String getString(Element elem) {
+ String text = null;
+ text = elem.getFirstChild().getNodeValue();
+ return text;
+ }
+
+ private int getInt(Element elem, String name) {
+ return Integer.parseInt(getString(elem, name));
+ }
+
+ private float getFloat(Element elem, String name) {
+ return Float.parseFloat(getString(elem, name));
+ }
+
+ private float getFloat(Element elem) {
+ return Float.parseFloat(getString(elem));
+ }
+
+ private Float3 parseFloat3(String valueString) {
+ StringTokenizer st = new StringTokenizer(valueString);
+ float x = Float.parseFloat(st.nextToken());
+ float y = Float.parseFloat(st.nextToken());
+ float z = Float.parseFloat(st.nextToken());
+ return new Float3(x, y, z);
+ }
+
+ private Float4 parseFloat4(String valueString) {
+ StringTokenizer st = new StringTokenizer(valueString);
+ float x = Float.parseFloat(st.nextToken());
+ float y = Float.parseFloat(st.nextToken());
+ float z = Float.parseFloat(st.nextToken());
+ float w = Float.parseFloat(st.nextToken());
+ return new Float4(x, y, z, w);
+ }
+
+ private Float3 getFloat3(Element elem, String name) {
+ String valueString = getString(elem, name);
+ return parseFloat3(valueString);
+ }
+
+ private Float4 getFloat4(Element elem, String name) {
+ String valueString = getString(elem, name);
+ return parseFloat4(valueString);
+ }
+
+ private Float3 getFloat3(Element elem) {
+ String valueString = getString(elem);
+ return parseFloat3(valueString);
+ }
+
+ private Float4 getFloat4(Element elem) {
+ String valueString = getString(elem);
+ return parseFloat4(valueString);
+ }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaScene.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaScene.java
new file mode 100644
index 000000000000..301075e52441
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaScene.java
@@ -0,0 +1,139 @@
+/*
+ * 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.scenegraph;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.FileInputStream;
+import java.io.BufferedInputStream;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.AsyncTask;
+import android.renderscript.*;
+import android.renderscript.Allocation.MipmapControl;
+import android.renderscript.Element.Builder;
+import android.renderscript.Font.Style;
+import android.renderscript.Program.TextureType;
+import android.renderscript.ProgramStore.DepthFunc;
+import android.util.Log;
+import com.android.scenegraph.SceneManager.SceneLoadedCallback;
+
+
+public class ColladaScene {
+
+ private String modelName;
+ private static String TAG = "ColladaScene";
+ private final int STATE_LAST_FOCUS = 1;
+ boolean mLoadFromSD = false;
+
+ SceneLoadedCallback mCallback;
+
+ public ColladaScene(String name, SceneLoadedCallback cb) {
+ modelName = name;
+ mCallback = cb;
+ }
+
+ public void init(RenderScriptGL rs, Resources res) {
+ mRS = rs;
+ mRes = res;
+
+ mLoadFromSD = SceneManager.isSDCardPath(modelName);
+
+ new ColladaLoaderTask().execute(modelName);
+ }
+
+ private Resources mRes;
+ private RenderScriptGL mRS;
+ Scene mActiveScene;
+
+ private class ColladaLoaderTask extends AsyncTask<String, Void, Boolean> {
+ ColladaParser sceneSource;
+ protected Boolean doInBackground(String... names) {
+ String rootDir = names[0].substring(0, names[0].lastIndexOf('/') + 1);
+ long start = System.currentTimeMillis();
+ sceneSource = new ColladaParser();
+ InputStream is = null;
+ try {
+ if (!mLoadFromSD) {
+ is = mRes.getAssets().open(names[0]);
+ } else {
+ File f = new File(names[0]);
+ is = new BufferedInputStream(new FileInputStream(f));
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Could not open collada file");
+ return new Boolean(false);
+ }
+ long end = System.currentTimeMillis();
+ Log.v("TIMER", "Stream load time: " + (end - start));
+
+ start = System.currentTimeMillis();
+ sceneSource.init(is, rootDir);
+ end = System.currentTimeMillis();
+ Log.v("TIMER", "Collada parse time: " + (end - start));
+ return new Boolean(true);
+ }
+
+ protected void onPostExecute(Boolean result) {
+ mActiveScene = sceneSource.getScene();
+ if (mCallback != null) {
+ mCallback.mLoadedScene = mActiveScene;
+ mCallback.run();
+ }
+
+ String shortName = modelName.substring(0, modelName.lastIndexOf('.'));
+ new A3DLoaderTask().execute(shortName + ".a3d");
+ }
+ }
+
+ private class A3DLoaderTask extends AsyncTask<String, Void, Boolean> {
+ protected Boolean doInBackground(String... names) {
+ long start = System.currentTimeMillis();
+ FileA3D model;
+ if (!mLoadFromSD) {
+ model = FileA3D.createFromAsset(mRS, mRes.getAssets(), names[0]);
+ } else {
+ model = FileA3D.createFromFile(mRS, names[0]);
+ }
+ int numModels = model.getIndexEntryCount();
+ for (int i = 0; i < numModels; i ++) {
+ FileA3D.IndexEntry entry = model.getIndexEntry(i);
+ if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) {
+ mActiveScene.meshLoaded(entry.getMesh());
+ }
+ }
+ long end = System.currentTimeMillis();
+ Log.v("TIMER", "A3D load time: " + (end - start));
+ return new Boolean(true);
+ }
+
+ protected void onPostExecute(Boolean result) {
+ }
+ }
+
+}
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/CompoundTransform.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/CompoundTransform.java
new file mode 100644
index 000000000000..d995dd00af3a
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/CompoundTransform.java
@@ -0,0 +1,197 @@
+/*
+ * 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.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import com.android.scenegraph.SceneManager;
+
+import android.renderscript.*;
+import android.renderscript.Float3;
+import android.renderscript.Matrix4f;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class CompoundTransform extends Transform {
+
+ public static abstract class Component {
+ String mName;
+ CompoundTransform mParent;
+ int mParentIndex;
+ protected ScriptField_TransformComponent_s.Item mData;
+
+ Component(int type, String name) {
+ mData = new ScriptField_TransformComponent_s.Item();
+ mData.type = type;
+ mName = name;
+ }
+
+ void setNameAlloc() {
+ RenderScriptGL rs = SceneManager.getRS();
+ if (mData.name != null) {
+ return;
+ }
+ mData.name = SceneManager.getCachedAlloc(getName());
+ if (mData.name == null) {
+ mData.name = SceneManager.getStringAsAllocation(rs, getName());
+ SceneManager.cacheAlloc(getName(), mData.name);
+ }
+ }
+
+ ScriptField_TransformComponent_s.Item getRSData() {
+ setNameAlloc();
+ return mData;
+ }
+
+ protected void update() {
+ if (mParent != null) {
+ mParent.updateRSComponent(this);
+ }
+ }
+
+ public String getName() {
+ return mName;
+ }
+ }
+
+ public static class TranslateComponent extends Component {
+ public TranslateComponent(String name, Float3 translate) {
+ super(ScriptC_export.const_Transform_TRANSLATE, name);
+ setValue(translate);
+ }
+ public Float3 getValue() {
+ return new Float3(mData.value.x, mData.value.y, mData.value.z);
+ }
+ public void setValue(Float3 val) {
+ mData.value.x = val.x;
+ mData.value.y = val.y;
+ mData.value.z = val.z;
+ update();
+ }
+ }
+
+ public static class RotateComponent extends Component {
+ public RotateComponent(String name, Float3 axis, float angle) {
+ super(ScriptC_export.const_Transform_ROTATE, name);
+ setAxis(axis);
+ setAngle(angle);
+ }
+ public Float3 getAxis() {
+ return new Float3(mData.value.x, mData.value.y, mData.value.z);
+ }
+ public float getAngle() {
+ return mData.value.w;
+ }
+ public void setAxis(Float3 val) {
+ mData.value.x = val.x;
+ mData.value.y = val.y;
+ mData.value.z = val.z;
+ update();
+ }
+ public void setAngle(float val) {
+ mData.value.w = val;
+ update();
+ }
+ }
+
+ public static class ScaleComponent extends Component {
+ public ScaleComponent(String name, Float3 scale) {
+ super(ScriptC_export.const_Transform_SCALE, name);
+ setValue(scale);
+ }
+ public Float3 getValue() {
+ return new Float3(mData.value.x, mData.value.y, mData.value.z);
+ }
+ public void setValue(Float3 val) {
+ mData.value.x = val.x;
+ mData.value.y = val.y;
+ mData.value.z = val.z;
+ update();
+ }
+ }
+
+ ScriptField_TransformComponent_s mComponentField;
+ public ArrayList<Component> mTransformComponents;
+
+ public CompoundTransform() {
+ mTransformComponents = new ArrayList<Component>();
+ }
+
+ public void addComponent(Component c) {
+ if (c.mParent != null) {
+ throw new IllegalArgumentException("Transform components may not be shared");
+ }
+ c.mParent = this;
+ c.mParentIndex = mTransformComponents.size();
+ mTransformComponents.add(c);
+ updateRSComponentAllocation();
+ }
+
+ public void setComponent(int index, Component c) {
+ if (c.mParent != null) {
+ throw new IllegalArgumentException("Transform components may not be shared");
+ }
+ if (index >= mTransformComponents.size()) {
+ throw new IllegalArgumentException("Invalid component index");
+ }
+ c.mParent = this;
+ c.mParentIndex = index;
+ mTransformComponents.set(index, c);
+ updateRSComponent(c);
+ }
+
+ void updateRSComponent(Component c) {
+ if (mField == null || mComponentField == null) {
+ return;
+ }
+ mComponentField.set(c.getRSData(), c.mParentIndex, true);
+ mField.set_isDirty(0, 1, true);
+ }
+
+ void updateRSComponentAllocation() {
+ if (mField == null) {
+ return;
+ }
+ initLocalData();
+
+ mField.set_components(0, mTransformData.components, false);
+ mField.set_isDirty(0, 1, true);
+ }
+
+ void initLocalData() {
+ RenderScriptGL rs = SceneManager.getRS();
+ int numComponenets = mTransformComponents.size();
+ if (numComponenets > 0) {
+ mComponentField = new ScriptField_TransformComponent_s(rs, numComponenets);
+ for (int i = 0; i < numComponenets; i ++) {
+ Component ith = mTransformComponents.get(i);
+ mComponentField.set(ith.getRSData(), i, false);
+ }
+ mComponentField.copyAll();
+
+ mTransformData.components = mComponentField.getAllocation();
+ }
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Float4Param.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Float4Param.java
new file mode 100644
index 000000000000..15024588cad9
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Float4Param.java
@@ -0,0 +1,146 @@
+/*
+ * 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.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import com.android.scenegraph.Scene;
+import com.android.scenegraph.SceneManager;
+
+import android.renderscript.Element;
+import android.renderscript.Float4;
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class Float4Param extends ShaderParam {
+ private static String TAG = "Float4Param";
+
+ LightBase mLight;
+
+ public Float4Param(String name) {
+ super(name);
+ }
+
+ public Float4Param(String name, float x) {
+ super(name);
+ set(x, 0, 0, 0);
+ }
+
+ public Float4Param(String name, float x, float y) {
+ super(name);
+ set(x, y, 0, 0);
+ }
+
+ public Float4Param(String name, float x, float y, float z) {
+ super(name);
+ set(x, y, z, 0);
+ }
+
+ public Float4Param(String name, float x, float y, float z, float w) {
+ super(name);
+ set(x, y, z, w);
+ }
+
+ void set(float x, float y, float z, float w) {
+ mData.float_value.x = x;
+ mData.float_value.y = y;
+ mData.float_value.z = z;
+ mData.float_value.w = w;
+ if (mField != null) {
+ mField.set_float_value(0, mData.float_value, true);
+ }
+ incTimestamp();
+ }
+
+ public void setValue(Float4 v) {
+ set(v.x, v.y, v.z, v.w);
+ }
+
+ public Float4 getValue() {
+ return mData.float_value;
+ }
+
+ public void setLight(LightBase l) {
+ mLight = l;
+ if (mField != null) {
+ mData.light = mLight.getRSData().getAllocation();
+ mField.set_light(0, mData.light, true);
+ }
+ incTimestamp();
+ }
+
+ boolean findLight(String property) {
+ String indexStr = mParamName.substring(property.length() + 1);
+ if (indexStr == null) {
+ Log.e(TAG, "Invalid light index.");
+ return false;
+ }
+ int index = Integer.parseInt(indexStr);
+ if (index == -1) {
+ return false;
+ }
+ Scene parentScene = SceneManager.getInstance().getActiveScene();
+ ArrayList<LightBase> allLights = parentScene.getLights();
+ if (index >= allLights.size()) {
+ return false;
+ }
+ mLight = allLights.get(index);
+ if (mLight == null) {
+ return false;
+ }
+ return true;
+ }
+
+ int getTypeFromName() {
+ int paramType = ScriptC_export.const_ShaderParam_FLOAT4_DATA;
+ if (mParamName.equalsIgnoreCase(cameraPos)) {
+ paramType = ScriptC_export.const_ShaderParam_FLOAT4_CAMERA_POS;
+ } else if(mParamName.equalsIgnoreCase(cameraDir)) {
+ paramType = ScriptC_export.const_ShaderParam_FLOAT4_CAMERA_DIR;
+ } else if(mParamName.startsWith(lightColor) && findLight(lightColor)) {
+ paramType = ScriptC_export.const_ShaderParam_FLOAT4_LIGHT_COLOR;
+ } else if(mParamName.startsWith(lightPos) && findLight(lightPos)) {
+ paramType = ScriptC_export.const_ShaderParam_FLOAT4_LIGHT_POS;
+ } else if(mParamName.startsWith(lightDir) && findLight(lightDir)) {
+ paramType = ScriptC_export.const_ShaderParam_FLOAT4_LIGHT_DIR;
+ }
+ return paramType;
+ }
+
+ void initLocalData() {
+ mData.type = getTypeFromName();
+ if (mCamera != null) {
+ mData.camera = mCamera.getRSData().getAllocation();
+ }
+ if (mLight != null) {
+ mData.light = mLight.getRSData().getAllocation();
+ }
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/FragmentShader.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/FragmentShader.java
new file mode 100644
index 000000000000..c8cc3ac5d890
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/FragmentShader.java
@@ -0,0 +1,167 @@
+/*
+ * 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.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import com.android.scenegraph.TextureBase;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.ProgramFragment.Builder;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class FragmentShader extends Shader {
+ ProgramFragment mProgram;
+ ScriptField_FragmentShader_s mField;
+
+ public static class Builder {
+
+ FragmentShader mShader;
+ ProgramFragment.Builder mBuilder;
+
+ public Builder(RenderScriptGL rs) {
+ mShader = new FragmentShader();
+ mBuilder = new ProgramFragment.Builder(rs);
+ }
+
+ public Builder setShader(Resources resources, int resourceID) {
+ mBuilder.setShader(resources, resourceID);
+ return this;
+ }
+
+ public Builder setObjectConst(Type type) {
+ mShader.mPerObjConstants = type;
+ return this;
+ }
+
+ public Builder setShaderConst(Type type) {
+ mShader.mPerShaderConstants = type;
+ return this;
+ }
+
+ public Builder addShaderTexture(Program.TextureType texType, String name) {
+ mShader.mShaderTextureNames.add(name);
+ mShader.mShaderTextureTypes.add(texType);
+ return this;
+ }
+
+ public Builder addTexture(Program.TextureType texType, String name) {
+ mShader.mTextureNames.add(name);
+ mShader.mTextureTypes.add(texType);
+ return this;
+ }
+
+ public FragmentShader create() {
+ if (mShader.mPerShaderConstants != null) {
+ mBuilder.addConstant(mShader.mPerShaderConstants);
+ }
+ if (mShader.mPerObjConstants != null) {
+ mBuilder.addConstant(mShader.mPerObjConstants);
+ }
+ for (int i = 0; i < mShader.mTextureTypes.size(); i ++) {
+ mBuilder.addTexture(mShader.mTextureTypes.get(i));
+ }
+ for (int i = 0; i < mShader.mShaderTextureTypes.size(); i ++) {
+ mBuilder.addTexture(mShader.mShaderTextureTypes.get(i));
+ }
+
+ mShader.mProgram = mBuilder.create();
+ return mShader;
+ }
+ }
+
+ public ProgramFragment getProgram() {
+ return mProgram;
+ }
+
+ ScriptField_ShaderParam_s getTextureParams() {
+ RenderScriptGL rs = SceneManager.getRS();
+ Resources res = SceneManager.getRes();
+ if (rs == null || res == null) {
+ return null;
+ }
+
+ ArrayList<ScriptField_ShaderParam_s.Item> paramList;
+ paramList = new ArrayList<ScriptField_ShaderParam_s.Item>();
+
+ int shaderTextureStart = mTextureTypes.size();
+ for (int i = 0; i < mShaderTextureNames.size(); i ++) {
+ ShaderParam sp = mSourceParams.get(mShaderTextureNames.get(i));
+ if (sp != null && sp instanceof TextureParam) {
+ TextureParam p = (TextureParam)sp;
+ ScriptField_ShaderParam_s.Item paramRS = new ScriptField_ShaderParam_s.Item();
+ paramRS.bufferOffset = shaderTextureStart + i;
+ paramRS.transformTimestamp = 0;
+ paramRS.dataTimestamp = 0;
+ paramRS.data = p.getRSData().getAllocation();
+ paramList.add(paramRS);
+ }
+ }
+
+ ScriptField_ShaderParam_s rsParams = null;
+ int paramCount = paramList.size();
+ if (paramCount != 0) {
+ rsParams = new ScriptField_ShaderParam_s(rs, paramCount);
+ for (int i = 0; i < paramCount; i++) {
+ rsParams.set(paramList.get(i), i, false);
+ }
+ rsParams.copyAll();
+ }
+ return rsParams;
+ }
+
+ ScriptField_FragmentShader_s getRSData() {
+ if (mField != null) {
+ return mField;
+ }
+
+ RenderScriptGL rs = SceneManager.getRS();
+ Resources res = SceneManager.getRes();
+ if (rs == null || res == null) {
+ return null;
+ }
+
+ ScriptField_FragmentShader_s.Item item = new ScriptField_FragmentShader_s.Item();
+ item.program = mProgram;
+
+ ScriptField_ShaderParam_s texParams = getTextureParams();
+ if (texParams != null) {
+ item.shaderTextureParams = texParams.getAllocation();
+ }
+
+ linkConstants(rs);
+ if (mPerShaderConstants != null) {
+ item.shaderConst = mConstantBuffer;
+ item.shaderConstParams = mConstantBufferParams.getAllocation();
+ mProgram.bindConstants(item.shaderConst, 0);
+ }
+
+ item.objectConstIndex = -1;
+ if (mPerObjConstants != null) {
+ item.objectConstIndex = mPerShaderConstants != null ? 1 : 0;
+ }
+
+ mField = new ScriptField_FragmentShader_s(rs, 1);
+ mField.set(item, 0, true);
+ return mField;
+ }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/LightBase.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/LightBase.java
new file mode 100644
index 000000000000..8f5e2e78c33f
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/LightBase.java
@@ -0,0 +1,111 @@
+/*
+ * 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.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.renderscript.Float3;
+import android.renderscript.Float4;
+import android.renderscript.Matrix4f;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public abstract class LightBase extends SceneGraphBase {
+ static final int RS_LIGHT_POINT = 0;
+ static final int RS_LIGHT_DIRECTIONAL = 1;
+
+ ScriptField_Light_s mField;
+ ScriptField_Light_s.Item mFieldData;
+ Transform mTransform;
+ Float4 mColor;
+ float mIntensity;
+ public LightBase() {
+ mColor = new Float4(0.0f, 0.0f, 0.0f, 0.0f);
+ mIntensity = 1.0f;
+ }
+
+ public void setTransform(Transform t) {
+ mTransform = t;
+ updateRSData();
+ }
+
+ public void setColor(float r, float g, float b) {
+ mColor.x = r;
+ mColor.y = g;
+ mColor.z = b;
+ updateRSData();
+ }
+
+ public void setColor(Float3 c) {
+ setColor(c.x, c.y, c.z);
+ }
+
+ public void setIntensity(float i) {
+ mIntensity = i;
+ updateRSData();
+ }
+
+ public void setName(String n) {
+ super.setName(n);
+ updateRSData();
+ }
+
+ protected void updateRSData() {
+ if (mField == null) {
+ return;
+ }
+ RenderScriptGL rs = SceneManager.getRS();
+ mFieldData.transformMatrix = mTransform.getRSData().getAllocation();
+ mFieldData.name = getNameAlloc(rs);
+ mFieldData.color = mColor;
+ mFieldData.intensity = mIntensity;
+
+ initLocalData();
+
+ mField.set(mFieldData, 0, true);
+ }
+
+ abstract void initLocalData();
+
+ ScriptField_Light_s getRSData() {
+ if (mField != null) {
+ return mField;
+ }
+
+ RenderScriptGL rs = SceneManager.getRS();
+ if (rs == null) {
+ return null;
+ }
+ if (mField == null) {
+ mField = new ScriptField_Light_s(rs, 1);
+ mFieldData = new ScriptField_Light_s.Item();
+ }
+
+ updateRSData();
+
+ return mField;
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/MatrixTransform.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/MatrixTransform.java
new file mode 100644
index 000000000000..6d70bc9e4cf4
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/MatrixTransform.java
@@ -0,0 +1,60 @@
+/*
+ * 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.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.renderscript.Matrix4f;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class MatrixTransform extends Transform {
+
+ Matrix4f mLocalMatrix;
+ public MatrixTransform() {
+ mLocalMatrix = new Matrix4f();
+ }
+
+ public void setMatrix(Matrix4f matrix) {
+ mLocalMatrix = matrix;
+ updateRSData();
+ }
+
+ public Matrix4f getMatrix() {
+ return new Matrix4f(mLocalMatrix.getArray());
+ }
+
+ void initLocalData() {
+ mTransformData.localMat = mLocalMatrix;
+ }
+
+ void updateRSData() {
+ if (mField == null) {
+ return;
+ }
+ mField.set_localMat(0, mLocalMatrix, false);
+ mField.set_isDirty(0, 1, true);
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/PointLight.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/PointLight.java
new file mode 100644
index 000000000000..574bafc4173c
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/PointLight.java
@@ -0,0 +1,43 @@
+/*
+ * 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.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class PointLight extends LightBase {
+ public PointLight() {
+ }
+
+ void initLocalData() {
+ mFieldData.type = RS_LIGHT_POINT;
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderPass.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderPass.java
new file mode 100644
index 000000000000..02fd69d20078
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderPass.java
@@ -0,0 +1,124 @@
+/*
+ * 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.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.util.Log;
+
+import android.renderscript.*;
+import android.content.res.Resources;
+
+/**
+ * @hide
+ */
+public class RenderPass extends SceneGraphBase {
+
+ TextureRenderTarget mColorTarget;
+ Float4 mClearColor;
+ boolean mShouldClearColor;
+
+ TextureRenderTarget mDepthTarget;
+ float mClearDepth;
+ boolean mShouldClearDepth;
+
+ ArrayList<RenderableBase> mObjectsToDraw;
+
+ Camera mCamera;
+
+ ScriptField_RenderPass_s.Item mRsField;
+
+ public RenderPass() {
+ mObjectsToDraw = new ArrayList<RenderableBase>();
+ mClearColor = new Float4(0.0f, 0.0f, 0.0f, 0.0f);
+ mShouldClearColor = true;
+ mClearDepth = 1.0f;
+ mShouldClearDepth = true;
+ }
+
+ public void appendRenderable(Renderable d) {
+ mObjectsToDraw.add(d);
+ }
+
+ public void setCamera(Camera c) {
+ mCamera = c;
+ }
+
+ public void setColorTarget(TextureRenderTarget colorTarget) {
+ mColorTarget = colorTarget;
+ }
+ public void setClearColor(Float4 clearColor) {
+ mClearColor = clearColor;
+ }
+ public void setShouldClearColor(boolean shouldClearColor) {
+ mShouldClearColor = shouldClearColor;
+ }
+
+ public void setDepthTarget(TextureRenderTarget depthTarget) {
+ mDepthTarget = depthTarget;
+ }
+ public void setClearDepth(float clearDepth) {
+ mClearDepth = clearDepth;
+ }
+ public void setShouldClearDepth(boolean shouldClearDepth) {
+ mShouldClearDepth = shouldClearDepth;
+ }
+
+ public ArrayList<RenderableBase> getRenderables() {
+ return mObjectsToDraw;
+ }
+
+ ScriptField_RenderPass_s.Item getRsField(RenderScriptGL rs, Resources res) {
+ if (mRsField != null) {
+ return mRsField;
+ }
+
+ mRsField = new ScriptField_RenderPass_s.Item();
+ if (mColorTarget != null) {
+ mRsField.color_target = mColorTarget.getRsData(true).get_texture(0);
+ }
+ if (mColorTarget != null) {
+ mRsField.depth_target = mDepthTarget.getRsData(true).get_texture(0);
+ }
+ mRsField.camera = mCamera != null ? mCamera.getRSData().getAllocation() : null;
+
+ if (mObjectsToDraw.size() != 0) {
+ Allocation drawableData = Allocation.createSized(rs,
+ Element.ALLOCATION(rs),
+ mObjectsToDraw.size());
+ Allocation[] drawableAllocs = new Allocation[mObjectsToDraw.size()];
+ for (int i = 0; i < mObjectsToDraw.size(); i ++) {
+ Renderable dI = (Renderable)mObjectsToDraw.get(i);
+ drawableAllocs[i] = dI.getRsField(rs, res).getAllocation();
+ }
+ drawableData.copyFrom(drawableAllocs);
+ mRsField.objects = drawableData;
+ }
+
+ mRsField.clear_color = mClearColor;
+ mRsField.clear_depth = mClearDepth;
+ mRsField.should_clear_color = mShouldClearColor;
+ mRsField.should_clear_depth = mShouldClearDepth;
+ return mRsField;
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderState.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderState.java
new file mode 100644
index 000000000000..c08a72283a9e
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderState.java
@@ -0,0 +1,111 @@
+/*
+ * 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.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+import android.content.res.Resources;
+
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramRaster;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.RSRuntimeException;
+import android.renderscript.RenderScript;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class RenderState extends SceneGraphBase {
+ VertexShader mVertex;
+ FragmentShader mFragment;
+ ProgramStore mStore;
+ ProgramRaster mRaster;
+
+ ScriptField_RenderState_s mField;
+
+ public RenderState(VertexShader pv,
+ FragmentShader pf,
+ ProgramStore ps,
+ ProgramRaster pr) {
+ mVertex = pv;
+ mFragment = pf;
+ mStore = ps;
+ mRaster = pr;
+ }
+
+ public RenderState(RenderState r) {
+ mVertex = r.mVertex;
+ mFragment = r.mFragment;
+ mStore = r.mStore;
+ mRaster = r.mRaster;
+ }
+
+ public void setProgramVertex(VertexShader pv) {
+ mVertex = pv;
+ updateRSData();
+ }
+
+ public void setProgramFragment(FragmentShader pf) {
+ mFragment = pf;
+ updateRSData();
+ }
+
+ public void setProgramStore(ProgramStore ps) {
+ mStore = ps;
+ updateRSData();
+ }
+
+ public void setProgramRaster(ProgramRaster pr) {
+ mRaster = pr;
+ updateRSData();
+ }
+
+ void updateRSData() {
+ if (mField == null) {
+ return;
+ }
+ ScriptField_RenderState_s.Item item = new ScriptField_RenderState_s.Item();
+ item.pv = mVertex.getRSData().getAllocation();
+ item.pf = mFragment.getRSData().getAllocation();
+ item.ps = mStore;
+ item.pr = mRaster;
+
+ mField.set(item, 0, true);
+ }
+
+ public ScriptField_RenderState_s getRSData() {
+ if (mField != null) {
+ return mField;
+ }
+
+ RenderScriptGL rs = SceneManager.getRS();
+ if (rs == null) {
+ return null;
+ }
+
+ mField = new ScriptField_RenderState_s(rs, 1);
+ updateRSData();
+
+ return mField;
+ }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Renderable.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Renderable.java
new file mode 100644
index 000000000000..9f7ab411c00d
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Renderable.java
@@ -0,0 +1,214 @@
+/*
+ * 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.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import com.android.scenegraph.Float4Param;
+import com.android.scenegraph.SceneManager;
+import com.android.scenegraph.ShaderParam;
+import com.android.scenegraph.TransformParam;
+
+import android.content.res.Resources;
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.Element.DataType;
+import android.renderscript.Matrix4f;
+import android.renderscript.Mesh;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class Renderable extends RenderableBase {
+ HashMap<String, ShaderParam> mSourceParams;
+
+ RenderState mRenderState;
+ Transform mTransform;
+
+ String mMeshName;
+ String mMeshIndexName;
+
+ public String mMaterialName;
+
+ ScriptField_Renderable_s mField;
+ ScriptField_Renderable_s.Item mData;
+
+ public Renderable() {
+ mSourceParams = new HashMap<String, ShaderParam>();
+ mData = new ScriptField_Renderable_s.Item();
+ }
+
+ public void setCullType(int cull) {
+ mData.cullType = cull;
+ }
+
+ public void setRenderState(RenderState renderState) {
+ mRenderState = renderState;
+ if (mField != null) {
+ RenderScriptGL rs = SceneManager.getRS();
+ updateFieldItem(rs);
+ mField.set(mData, 0, true);
+ }
+ }
+
+ public void setMesh(Mesh mesh) {
+ mData.mesh = mesh;
+ if (mField != null) {
+ mField.set_mesh(0, mData.mesh, true);
+ }
+ }
+
+ public void setMesh(String mesh, String indexName) {
+ mMeshName = mesh;
+ mMeshIndexName = indexName;
+ }
+
+ public void setMaterialName(String name) {
+ mMaterialName = name;
+ }
+
+ public void setTransform(Transform t) {
+ mTransform = t;
+ if (mField != null) {
+ RenderScriptGL rs = SceneManager.getRS();
+ updateFieldItem(rs);
+ mField.set(mData, 0, true);
+ }
+ }
+
+ public void appendSourceParams(ShaderParam p) {
+ mSourceParams.put(p.getParamName(), p);
+ // Possibly lift this restriction later
+ if (mField != null) {
+ throw new RuntimeException("Can't add source params to objects that are rendering");
+ }
+ }
+
+ public void resolveMeshData(Mesh mesh) {
+ mData.mesh = mesh;
+ if (mData.mesh == null) {
+ Log.v("DRAWABLE: ", "*** NO MESH *** " + mMeshName);
+ return;
+ }
+ int subIndexCount = mData.mesh.getPrimitiveCount();
+ if (subIndexCount == 1 || mMeshIndexName == null) {
+ mData.meshIndex = 0;
+ } else {
+ for (int i = 0; i < subIndexCount; i ++) {
+ if (mData.mesh.getIndexSetAllocation(i).getName().equals(mMeshIndexName)) {
+ mData.meshIndex = i;
+ break;
+ }
+ }
+ }
+ if (mField != null) {
+ mField.set(mData, 0, true);
+ }
+ }
+
+ void updateTextures(RenderScriptGL rs) {
+ Iterator<ShaderParam> allParamsIter = mSourceParams.values().iterator();
+ int paramIndex = 0;
+ while (allParamsIter.hasNext()) {
+ ShaderParam sp = allParamsIter.next();
+ if (sp instanceof TextureParam) {
+ TextureParam p = (TextureParam)sp;
+ TextureBase tex = p.getTexture();
+ if (tex != null) {
+ mData.pf_textures[paramIndex++] = tex.getRsData(false).getAllocation();
+ }
+ }
+ }
+ ProgramFragment pf = mRenderState.mFragment.mProgram;
+ mData.pf_num_textures = pf != null ? Math.min(pf.getTextureCount(), paramIndex) : 0;
+ if (mField != null) {
+ mField.set_pf_textures(0, mData.pf_textures, true);
+ mField.set_pf_num_textures(0, mData.pf_num_textures, true);
+ }
+ }
+
+ public void setVisible(boolean vis) {
+ mData.cullType = vis ? 0 : 2;
+ if (mField != null) {
+ mField.set_cullType(0, mData.cullType, true);
+ }
+ }
+
+ ScriptField_Renderable_s getRsField(RenderScriptGL rs, Resources res) {
+ if (mField != null) {
+ return mField;
+ }
+ updateFieldItem(rs);
+ updateTextures(rs);
+
+ mField = new ScriptField_Renderable_s(rs, 1);
+ mField.set(mData, 0, true);
+
+ return mField;
+ }
+
+ void updateVertexConstants(RenderScriptGL rs) {
+ Allocation pvParams = null, vertexConstants = null;
+ VertexShader pv = mRenderState.mVertex;
+ if (pv != null && pv.getObjectConstants() != null) {
+ vertexConstants = Allocation.createTyped(rs, pv.getObjectConstants());
+ Element vertexConst = vertexConstants.getType().getElement();
+ pvParams = ShaderParam.fillInParams(vertexConst, mSourceParams,
+ mTransform).getAllocation();
+ }
+ mData.pv_const = vertexConstants;
+ mData.pv_constParams = pvParams;
+ }
+
+ void updateFragmentConstants(RenderScriptGL rs) {
+ Allocation pfParams = null, fragmentConstants = null;
+ FragmentShader pf = mRenderState.mFragment;
+ if (pf != null && pf.getObjectConstants() != null) {
+ fragmentConstants = Allocation.createTyped(rs, pf.getObjectConstants());
+ Element fragmentConst = fragmentConstants.getType().getElement();
+ pfParams = ShaderParam.fillInParams(fragmentConst, mSourceParams,
+ mTransform).getAllocation();
+ }
+ mData.pf_const = fragmentConstants;
+ mData.pf_constParams = pfParams;
+ }
+
+ void updateFieldItem(RenderScriptGL rs) {
+ updateVertexConstants(rs);
+ updateFragmentConstants(rs);
+
+ if (mTransform != null) {
+ mData.transformMatrix = mTransform.getRSData().getAllocation();
+ }
+ mData.name = getNameAlloc(rs);
+ mData.render_state = mRenderState.getRSData().getAllocation();
+ mData.bVolInitialized = 0;
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableBase.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableBase.java
new file mode 100644
index 000000000000..74535dd94987
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableBase.java
@@ -0,0 +1,39 @@
+/*
+ * 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.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class RenderableBase extends SceneGraphBase {
+ public RenderableBase() {
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableGroup.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableGroup.java
new file mode 100644
index 000000000000..590bbab9c5f8
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableGroup.java
@@ -0,0 +1,47 @@
+/*
+ * 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.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class RenderableGroup extends RenderableBase {
+
+ ArrayList<RenderableBase> mChildren;
+
+ public RenderableGroup() {
+ mChildren = new ArrayList<RenderableBase>();
+ }
+
+ public void appendChildren(RenderableBase d) {
+ mChildren.add(d);
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Scene.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Scene.java
new file mode 100644
index 000000000000..8c09860c8b9e
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Scene.java
@@ -0,0 +1,308 @@
+/*
+ * 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.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.android.scenegraph.SceneManager;
+import com.android.scenegraph.TextureBase;
+
+import android.content.res.Resources;
+import android.os.AsyncTask;
+import android.renderscript.*;
+import android.renderscript.Mesh;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class Scene extends SceneGraphBase {
+ private static String TIMER_TAG = "TIMER";
+
+ CompoundTransform mRootTransforms;
+ HashMap<String, Transform> mTransformMap;
+ ArrayList<RenderPass> mRenderPasses;
+ ArrayList<LightBase> mLights;
+ ArrayList<Camera> mCameras;
+ ArrayList<FragmentShader> mFragmentShaders;
+ ArrayList<VertexShader> mVertexShaders;
+ ArrayList<RenderableBase> mRenderables;
+ HashMap<String, RenderableBase> mRenderableMap;
+ ArrayList<Texture2D> mTextures;
+
+ HashMap<String, ArrayList<Renderable> > mRenderableMeshMap;
+
+ // RS Specific stuff
+ ScriptField_SgTransform mTransformRSData;
+
+ RenderScriptGL mRS;
+ Resources mRes;
+
+ ScriptField_RenderPass_s mRenderPassAlloc;
+
+ public Scene() {
+ mRenderPasses = new ArrayList<RenderPass>();
+ mLights = new ArrayList<LightBase>();
+ mCameras = new ArrayList<Camera>();
+ mFragmentShaders = new ArrayList<FragmentShader>();
+ mVertexShaders = new ArrayList<VertexShader>();
+ mRenderables = new ArrayList<RenderableBase>();
+ mRenderableMap = new HashMap<String, RenderableBase>();
+ mRenderableMeshMap = new HashMap<String, ArrayList<Renderable> >();
+ mTextures = new ArrayList<Texture2D>();
+ mRootTransforms = new CompoundTransform();
+ mRootTransforms.setName("_scene_root_");
+ mTransformMap = new HashMap<String, Transform>();
+ }
+
+ public void appendTransform(Transform t) {
+ mRootTransforms.appendChild(t);
+ }
+
+ // temporary
+ public void addToTransformMap(Transform t) {
+ mTransformMap.put(t.getName(), t);
+ }
+
+ public Transform getTransformByName(String name) {
+ return mTransformMap.get(name);
+ }
+
+ public void appendRenderPass(RenderPass p) {
+ mRenderPasses.add(p);
+ }
+
+ public void clearRenderPasses() {
+ mRenderPasses.clear();
+ }
+
+ public void appendLight(LightBase l) {
+ mLights.add(l);
+ }
+
+ public void appendCamera(Camera c) {
+ mCameras.add(c);
+ }
+
+ public void appendShader(FragmentShader f) {
+ mFragmentShaders.add(f);
+ }
+
+ public void appendShader(VertexShader v) {
+ mVertexShaders.add(v);
+ }
+
+ public ArrayList<Camera> getCameras() {
+ return mCameras;
+ }
+
+ public ArrayList<LightBase> getLights() {
+ return mLights;
+ }
+
+ public void appendRenderable(RenderableBase d) {
+ mRenderables.add(d);
+ mRenderableMap.put(d.getName(), d);
+ }
+
+ public ArrayList<RenderableBase> getRenderables() {
+ return mRenderables;
+ }
+
+ public RenderableBase getRenderableByName(String name) {
+ return mRenderableMap.get(name);
+ }
+
+ public void appendTextures(Texture2D tex) {
+ mTextures.add(tex);
+ }
+
+ public void assignRenderStateToMaterial(RenderState renderState, String regex) {
+ Pattern pattern = Pattern.compile(regex);
+ int numRenderables = mRenderables.size();
+ for (int i = 0; i < numRenderables; i ++) {
+ Renderable shape = (Renderable)mRenderables.get(i);
+ Matcher m = pattern.matcher(shape.mMaterialName);
+ if (m.find()) {
+ shape.setRenderState(renderState);
+ }
+ }
+ }
+
+ public void assignRenderState(RenderState renderState) {
+ int numRenderables = mRenderables.size();
+ for (int i = 0; i < numRenderables; i ++) {
+ Renderable shape = (Renderable)mRenderables.get(i);
+ shape.setRenderState(renderState);
+ }
+ }
+
+ public void meshLoaded(Mesh m) {
+ ArrayList<Renderable> entries = mRenderableMeshMap.get(m.getName());
+ int numEntries = entries.size();
+ for (int i = 0; i < numEntries; i++) {
+ Renderable d = entries.get(i);
+ d.resolveMeshData(m);
+ }
+ }
+
+ void addToMeshMap(Renderable d) {
+ ArrayList<Renderable> entries = mRenderableMeshMap.get(d.mMeshName);
+ if (entries == null) {
+ entries = new ArrayList<Renderable>();
+ mRenderableMeshMap.put(d.mMeshName, entries);
+ }
+ entries.add(d);
+ }
+
+ public void destroyRS() {
+ SceneManager sceneManager = SceneManager.getInstance();
+ mTransformRSData = null;
+ sceneManager.mRenderLoop.bind_gRootNode(mTransformRSData);
+ sceneManager.mRenderLoop.set_gRenderableObjects(null);
+ mRenderPassAlloc = null;
+ sceneManager.mRenderLoop.set_gRenderPasses(null);
+ sceneManager.mRenderLoop.bind_gFrontToBack(null);
+ sceneManager.mRenderLoop.bind_gBackToFront(null);
+ sceneManager.mRenderLoop.set_gCameras(null);
+
+ mTransformMap = null;
+ mRenderPasses = null;
+ mLights = null;
+ mCameras = null;
+ mRenderables = null;
+ mRenderableMap = null;
+ mTextures = null;
+ mRenderableMeshMap = null;
+ mRootTransforms = null;
+ }
+
+ public void initRenderPassRS(RenderScriptGL rs, SceneManager sceneManager) {
+ if (mRenderPasses.size() != 0) {
+ mRenderPassAlloc = new ScriptField_RenderPass_s(mRS, mRenderPasses.size());
+ for (int i = 0; i < mRenderPasses.size(); i ++) {
+ mRenderPassAlloc.set(mRenderPasses.get(i).getRsField(mRS, mRes), i, false);
+ }
+ mRenderPassAlloc.copyAll();
+ sceneManager.mRenderLoop.set_gRenderPasses(mRenderPassAlloc.getAllocation());
+ }
+ }
+
+ private void addDrawables(RenderScriptGL rs, Resources res, SceneManager sceneManager) {
+ Allocation drawableData = Allocation.createSized(rs,
+ Element.ALLOCATION(rs),
+ mRenderables.size());
+ Allocation[] drawableAllocs = new Allocation[mRenderables.size()];
+ for (int i = 0; i < mRenderables.size(); i ++) {
+ Renderable dI = (Renderable)mRenderables.get(i);
+ addToMeshMap(dI);
+ drawableAllocs[i] = dI.getRsField(rs, res).getAllocation();
+ }
+ drawableData.copyFrom(drawableAllocs);
+ sceneManager.mRenderLoop.set_gRenderableObjects(drawableData);
+
+ initRenderPassRS(rs, sceneManager);
+ }
+
+ private void addShaders(RenderScriptGL rs, Resources res, SceneManager sceneManager) {
+ Allocation shaderData = Allocation.createSized(rs, Element.ALLOCATION(rs),
+ mVertexShaders.size());
+ Allocation[] shaderAllocs = new Allocation[mVertexShaders.size()];
+ for (int i = 0; i < mVertexShaders.size(); i ++) {
+ VertexShader sI = mVertexShaders.get(i);
+ shaderAllocs[i] = sI.getRSData().getAllocation();
+ }
+ shaderData.copyFrom(shaderAllocs);
+ sceneManager.mRenderLoop.set_gVertexShaders(shaderData);
+
+ shaderData = Allocation.createSized(rs, Element.ALLOCATION(rs), mFragmentShaders.size());
+ shaderAllocs = new Allocation[mFragmentShaders.size()];
+ for (int i = 0; i < mFragmentShaders.size(); i ++) {
+ FragmentShader sI = mFragmentShaders.get(i);
+ shaderAllocs[i] = sI.getRSData().getAllocation();
+ }
+ shaderData.copyFrom(shaderAllocs);
+ sceneManager.mRenderLoop.set_gFragmentShaders(shaderData);
+ }
+
+ public void initRS() {
+ SceneManager sceneManager = SceneManager.getInstance();
+ mRS = SceneManager.getRS();
+ mRes = SceneManager.getRes();
+ long start = System.currentTimeMillis();
+ mTransformRSData = mRootTransforms.getRSData();
+ long end = System.currentTimeMillis();
+ Log.v(TIMER_TAG, "Transform init time: " + (end - start));
+
+ start = System.currentTimeMillis();
+
+ sceneManager.mRenderLoop.bind_gRootNode(mTransformRSData);
+ end = System.currentTimeMillis();
+ Log.v(TIMER_TAG, "Script init time: " + (end - start));
+
+ start = System.currentTimeMillis();
+ addDrawables(mRS, mRes, sceneManager);
+ end = System.currentTimeMillis();
+ Log.v(TIMER_TAG, "Renderable init time: " + (end - start));
+
+ addShaders(mRS, mRes, sceneManager);
+
+ Allocation opaqueBuffer = null;
+ if (mRenderables.size() > 0) {
+ opaqueBuffer = Allocation.createSized(mRS, Element.U32(mRS), mRenderables.size());
+ }
+ Allocation transparentBuffer = null;
+ if (mRenderables.size() > 0) {
+ transparentBuffer = Allocation.createSized(mRS, Element.U32(mRS), mRenderables.size());
+ }
+
+ sceneManager.mRenderLoop.bind_gFrontToBack(opaqueBuffer);
+ sceneManager.mRenderLoop.bind_gBackToFront(transparentBuffer);
+
+ if (mCameras.size() > 0) {
+ Allocation cameraData;
+ cameraData = Allocation.createSized(mRS, Element.ALLOCATION(mRS), mCameras.size());
+ Allocation[] cameraAllocs = new Allocation[mCameras.size()];
+ for (int i = 0; i < mCameras.size(); i ++) {
+ cameraAllocs[i] = mCameras.get(i).getRSData().getAllocation();
+ }
+ cameraData.copyFrom(cameraAllocs);
+ sceneManager.mRenderLoop.set_gCameras(cameraData);
+ }
+
+ if (mLights.size() > 0) {
+ Allocation lightData = Allocation.createSized(mRS,
+ Element.ALLOCATION(mRS),
+ mLights.size());
+ Allocation[] lightAllocs = new Allocation[mLights.size()];
+ for (int i = 0; i < mLights.size(); i ++) {
+ lightAllocs[i] = mLights.get(i).getRSData().getAllocation();
+ }
+ lightData.copyFrom(lightAllocs);
+ sceneManager.mRenderLoop.set_gLights(lightData);
+ }
+ }
+}
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneGraphBase.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneGraphBase.java
new file mode 100644
index 000000000000..412ffbf77900
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneGraphBase.java
@@ -0,0 +1,61 @@
+/*
+ * 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.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import com.android.scenegraph.SceneManager;
+
+import android.renderscript.Allocation;
+import android.renderscript.Element;
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.RSRuntimeException;
+import android.renderscript.RenderScript;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public abstract class SceneGraphBase {
+ String mName;
+ Allocation mNameAlloc;
+ public void setName(String n) {
+ mName = n;
+ mNameAlloc = null;
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ Allocation getNameAlloc(RenderScriptGL rs) {
+ if (mNameAlloc == null) {
+ mNameAlloc = SceneManager.getStringAsAllocation(rs, getName());
+ }
+ return mNameAlloc;
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java
new file mode 100644
index 000000000000..f77f48323770
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java
@@ -0,0 +1,355 @@
+/*
+ * 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.scenegraph;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Writer;
+import java.lang.Math;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import com.android.scenegraph.Camera;
+import com.android.scenegraph.MatrixTransform;
+import com.android.scenegraph.Scene;
+import com.android.testapp.R;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.AsyncTask;
+import android.renderscript.*;
+import android.renderscript.Allocation.MipmapControl;
+import android.renderscript.Mesh;
+import android.renderscript.RenderScriptGL;
+import android.renderscript.Type.Builder;
+import android.util.Log;
+import android.view.SurfaceHolder;
+
+/**
+ * @hide
+ */
+public class SceneManager extends SceneGraphBase {
+
+ HashMap<String, Allocation> mAllocationMap;
+
+ ScriptC_render mRenderLoop;
+ ScriptC mCameraScript;
+ ScriptC mLightScript;
+ ScriptC mObjectParamsScript;
+ ScriptC mFragmentParamsScript;
+ ScriptC mVertexParamsScript;
+ ScriptC mCullScript;
+ ScriptC_transform mTransformScript;
+ ScriptC_export mExportScript;
+
+ RenderScriptGL mRS;
+ Resources mRes;
+ Mesh mQuad;
+ int mWidth;
+ int mHeight;
+
+ Scene mActiveScene;
+ private static SceneManager sSceneManager;
+
+ private Allocation sDefault2D;
+ private Allocation sDefaultCube;
+
+ private static Allocation getDefault(boolean isCube) {
+ final int dimension = 4;
+ final int bytesPerPixel = 4;
+ int arraySize = dimension * dimension * bytesPerPixel;
+
+ RenderScriptGL rs = sSceneManager.mRS;
+ Type.Builder b = new Type.Builder(rs, Element.RGBA_8888(rs));
+ b.setX(dimension).setY(dimension);
+ if (isCube) {
+ b.setFaces(true);
+ arraySize *= 6;
+ }
+ Type bitmapType = b.create();
+
+ Allocation.MipmapControl mip = Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE;
+ int usage = Allocation.USAGE_GRAPHICS_TEXTURE;
+ Allocation defaultImage = Allocation.createTyped(rs, bitmapType, mip, usage);
+
+ byte imageData[] = new byte[arraySize];
+ defaultImage.copyFrom(imageData);
+ return defaultImage;
+ }
+
+ static Allocation getDefaultTex2D() {
+ if (sSceneManager == null) {
+ return null;
+ }
+ if (sSceneManager.sDefault2D == null) {
+ sSceneManager.sDefault2D = getDefault(false);
+ }
+ return sSceneManager.sDefault2D;
+ }
+
+ static Allocation getDefaultTexCube() {
+ if (sSceneManager == null) {
+ return null;
+ }
+ if (sSceneManager.sDefaultCube == null) {
+ sSceneManager.sDefaultCube = getDefault(true);
+ }
+ return sSceneManager.sDefaultCube;
+ }
+
+ public static boolean isSDCardPath(String path) {
+ int sdCardIndex = path.indexOf("sdcard/");
+ // We are looking for /sdcard/ or sdcard/
+ if (sdCardIndex == 0 || sdCardIndex == 1) {
+ return true;
+ }
+ sdCardIndex = path.indexOf("mnt/sdcard/");
+ if (sdCardIndex == 0 || sdCardIndex == 1) {
+ return true;
+ }
+ return false;
+ }
+
+ static Bitmap loadBitmap(String name, Resources res) {
+ InputStream is = null;
+ boolean loadFromSD = isSDCardPath(name);
+ try {
+ if (!loadFromSD) {
+ is = res.getAssets().open(name);
+ } else {
+ File f = new File(name);
+ is = new BufferedInputStream(new FileInputStream(f));
+ }
+ } catch (IOException e) {
+ Log.e("ImageLoaderTask", " Message: " + e.getMessage());
+ return null;
+ }
+
+ Bitmap b = BitmapFactory.decodeStream(is);
+ try {
+ is.close();
+ } catch (IOException e) {
+ Log.e("ImageLoaderTask", " Message: " + e.getMessage());
+ }
+ return b;
+ }
+
+ public static Allocation loadCubemap(String name, RenderScriptGL rs, Resources res) {
+ Bitmap b = loadBitmap(name, res);
+ if (b == null) {
+ return null;
+ }
+ return Allocation.createCubemapFromBitmap(rs, b,
+ MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
+ Allocation.USAGE_GRAPHICS_TEXTURE);
+ }
+
+ public static Allocation loadTexture2D(String name, RenderScriptGL rs, Resources res) {
+ Bitmap b = loadBitmap(name, res);
+ if (b == null) {
+ return null;
+ }
+ return Allocation.createFromBitmap(rs, b,
+ Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
+ Allocation.USAGE_GRAPHICS_TEXTURE);
+ }
+
+ public static ProgramStore BLEND_ADD_DEPTH_NONE(RenderScript rs) {
+ ProgramStore.Builder builder = new ProgramStore.Builder(rs);
+ builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS);
+ builder.setBlendFunc(ProgramStore.BlendSrcFunc.ONE, ProgramStore.BlendDstFunc.ONE);
+ builder.setDitherEnabled(false);
+ builder.setDepthMaskEnabled(false);
+ return builder.create();
+ }
+
+ static Allocation getStringAsAllocation(RenderScript rs, String str) {
+ if (str == null) {
+ return null;
+ }
+ if (str.length() == 0) {
+ return null;
+ }
+ byte[] allocArray = null;
+ byte[] nullChar = new byte[1];
+ nullChar[0] = 0;
+ try {
+ allocArray = str.getBytes("UTF-8");
+ Allocation alloc = Allocation.createSized(rs, Element.U8(rs),
+ allocArray.length + 1,
+ Allocation.USAGE_SCRIPT);
+ alloc.copy1DRangeFrom(0, allocArray.length, allocArray);
+ alloc.copy1DRangeFrom(allocArray.length, 1, nullChar);
+ return alloc;
+ }
+ catch (Exception e) {
+ throw new RSRuntimeException("Could not convert string to utf-8.");
+ }
+ }
+
+ static Allocation getCachedAlloc(String str) {
+ if (sSceneManager == null) {
+ throw new RuntimeException("Scene manager not initialized");
+ }
+ return sSceneManager.mAllocationMap.get(str);
+ }
+
+ static void cacheAlloc(String str, Allocation alloc) {
+ if (sSceneManager == null) {
+ throw new RuntimeException("Scene manager not initialized");
+ }
+ sSceneManager.mAllocationMap.put(str, alloc);
+ }
+
+ public static class SceneLoadedCallback implements Runnable {
+ public Scene mLoadedScene;
+ public String mName;
+ public void run() {
+ }
+ }
+
+ public Scene getActiveScene() {
+ return mActiveScene;
+ }
+
+ public void setActiveScene(Scene s) {
+ mActiveScene = s;
+
+ // Do some sanity checking
+ if (mActiveScene.getCameras().size() == 0) {
+ Matrix4f camPos = new Matrix4f();
+ camPos.translate(0, 0, 10);
+ MatrixTransform cameraTransform = new MatrixTransform();
+ cameraTransform.setName("_DefaultCameraTransform");
+ cameraTransform.setMatrix(camPos);
+ mActiveScene.appendTransform(cameraTransform);
+ Camera cam = new Camera();
+ cam.setName("_DefaultCamera");
+ cam.setTransform(cameraTransform);
+ mActiveScene.appendCamera(cam);
+ }
+ }
+
+ static RenderScriptGL getRS() {
+ if (sSceneManager == null) {
+ return null;
+ }
+ return sSceneManager.mRS;
+ }
+
+ static Resources getRes() {
+ if (sSceneManager == null) {
+ return null;
+ }
+ return sSceneManager.mRes;
+ }
+
+ public static SceneManager getInstance() {
+ if (sSceneManager == null) {
+ sSceneManager = new SceneManager();
+ }
+ return sSceneManager;
+ }
+
+ protected SceneManager() {
+ }
+
+ public void loadModel(String name, SceneLoadedCallback cb) {
+ ColladaScene scene = new ColladaScene(name, cb);
+ scene.init(mRS, mRes);
+ }
+
+ public Mesh getScreenAlignedQuad() {
+ if (mQuad != null) {
+ return mQuad;
+ }
+
+ Mesh.TriangleMeshBuilder tmb = new Mesh.TriangleMeshBuilder(mRS,
+ 3, Mesh.TriangleMeshBuilder.TEXTURE_0);
+
+ tmb.setTexture(0.0f, 1.0f);
+ tmb.addVertex(-1.0f, 1.0f, 1.0f);
+
+ tmb.setTexture(0.0f, 0.0f);
+ tmb.addVertex(-1.0f, -1.0f, 1.0f);
+
+ tmb.setTexture(1.0f, 0.0f);
+ tmb.addVertex(1.0f, -1.0f, 1.0f);
+
+ tmb.setTexture(1.0f, 1.0f);
+ tmb.addVertex(1.0f, 1.0f, 1.0f);
+
+ tmb.addTriangle(0, 1, 2);
+ tmb.addTriangle(2, 3, 0);
+
+ mQuad = tmb.create(true);
+ return mQuad;
+ }
+
+ public Renderable getRenderableQuad(String name, RenderState state) {
+ Renderable quad = new Renderable();
+ quad.setTransform(new MatrixTransform());
+ quad.setMesh(getScreenAlignedQuad());
+ quad.setName(name);
+ quad.setRenderState(state);
+ quad.setCullType(1);
+ return quad;
+ }
+
+ public void initRS(RenderScriptGL rs, Resources res, int w, int h) {
+ mRS = rs;
+ mRes = res;
+ mAllocationMap = new HashMap<String, Allocation>();
+
+ mExportScript = new ScriptC_export(rs, res, R.raw.export);
+
+ mTransformScript = new ScriptC_transform(rs, res, R.raw.transform);
+ mTransformScript.set_gTransformScript(mTransformScript);
+
+ mCameraScript = new ScriptC_camera(rs, res, R.raw.camera);
+ mLightScript = new ScriptC_light(rs, res, R.raw.light);
+ mObjectParamsScript = new ScriptC_object_params(rs, res, R.raw.object_params);
+ mFragmentParamsScript = new ScriptC_object_params(rs, res, R.raw.fragment_params);
+ mVertexParamsScript = new ScriptC_object_params(rs, res, R.raw.vertex_params);
+ mCullScript = new ScriptC_cull(rs, res, R.raw.cull);
+
+ mRenderLoop = new ScriptC_render(rs, res, R.raw.render);
+ mRenderLoop.set_gTransformScript(mTransformScript);
+ mRenderLoop.set_gCameraScript(mCameraScript);
+ mRenderLoop.set_gLightScript(mLightScript);
+ mRenderLoop.set_gObjectParamsScript(mObjectParamsScript);
+ mRenderLoop.set_gFragmentParamsScript(mFragmentParamsScript);
+ mRenderLoop.set_gVertexParamsScript(mVertexParamsScript);
+ mRenderLoop.set_gCullScript(mCullScript);
+
+ mRenderLoop.set_gPFSBackground(ProgramStore.BLEND_NONE_DEPTH_TEST(mRS));
+ }
+
+ public ScriptC getRenderLoop() {
+ return mRenderLoop;
+ }
+}
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Shader.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Shader.java
new file mode 100644
index 000000000000..497511437115
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Shader.java
@@ -0,0 +1,76 @@
+/*
+ * 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.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import com.android.scenegraph.SceneGraphBase;
+import com.android.scenegraph.ShaderParam;
+
+import android.renderscript.*;
+import android.renderscript.ProgramFragment.Builder;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public abstract class Shader extends SceneGraphBase {
+ protected Type mPerObjConstants;
+ protected Type mPerShaderConstants;
+
+ protected HashMap<String, ShaderParam> mSourceParams;
+ protected ArrayList<String> mShaderTextureNames;
+ protected ArrayList<Program.TextureType > mShaderTextureTypes;
+ protected ArrayList<String> mTextureNames;
+ protected ArrayList<Program.TextureType > mTextureTypes;
+
+ protected Allocation mConstantBuffer;
+ protected ScriptField_ShaderParam_s mConstantBufferParams;
+
+ public Shader() {
+ mSourceParams = new HashMap<String, ShaderParam>();
+ mShaderTextureNames = new ArrayList<String>();
+ mShaderTextureTypes = new ArrayList<Program.TextureType>();
+ mTextureNames = new ArrayList<String>();
+ mTextureTypes = new ArrayList<Program.TextureType>();
+ }
+
+ public void appendSourceParams(ShaderParam p) {
+ mSourceParams.put(p.getParamName(), p);
+ }
+
+ public Type getObjectConstants() {
+ return mPerObjConstants;
+ }
+
+ public Type getShaderConstants() {
+ return mPerObjConstants;
+ }
+
+ void linkConstants(RenderScriptGL rs) {
+ if (mPerShaderConstants == null) {
+ return;
+ }
+
+ Element constElem = mPerShaderConstants.getElement();
+ mConstantBufferParams = ShaderParam.fillInParams(constElem, mSourceParams, null);
+
+ mConstantBuffer = Allocation.createTyped(rs, mPerShaderConstants);
+ }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java
new file mode 100644
index 000000000000..8dea53574a45
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java
@@ -0,0 +1,162 @@
+/*
+ * 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.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+import com.android.scenegraph.SceneManager;
+import com.android.scenegraph.Transform;
+
+import android.renderscript.Element;
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.RenderScriptGL;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public abstract class ShaderParam extends SceneGraphBase {
+
+ static final String cameraPos = "cameraPos";
+ static final String cameraDir = "cameraDir";
+
+ static final String lightColor = "lightColor";
+ static final String lightPos = "lightPos";
+ static final String lightDir = "lightDir";
+
+ static final String view = "view";
+ static final String proj = "proj";
+ static final String viewProj = "viewProj";
+ static final String model = "model";
+ static final String modelView = "modelView";
+ static final String modelViewProj = "modelViewProj";
+
+ static final long sMaxTimeStamp = 0xffffffffL;
+
+ ScriptField_ShaderParamData_s.Item mData;
+ ScriptField_ShaderParamData_s mField;
+
+ String mParamName;
+ Camera mCamera;
+
+ static ScriptField_ShaderParam_s fillInParams(Element constantElem,
+ HashMap<String, ShaderParam> sourceParams,
+ Transform transform) {
+ RenderScriptGL rs = SceneManager.getRS();
+ ArrayList<ScriptField_ShaderParam_s.Item> paramList;
+ paramList = new ArrayList<ScriptField_ShaderParam_s.Item>();
+
+ int subElemCount = constantElem.getSubElementCount();
+ for (int i = 0; i < subElemCount; i ++) {
+ String inputName = constantElem.getSubElementName(i);
+ int offset = constantElem.getSubElementOffsetBytes(i);
+
+ ShaderParam matchingParam = sourceParams.get(inputName);
+ Element subElem = constantElem.getSubElement(i);
+ // Make one if it's not there
+ if (matchingParam == null) {
+ if (subElem.getDataType() == Element.DataType.FLOAT_32) {
+ matchingParam = new Float4Param(inputName);
+ } else if (subElem.getDataType() == Element.DataType.MATRIX_4X4) {
+ TransformParam trParam = new TransformParam(inputName);
+ trParam.setTransform(transform);
+ matchingParam = trParam;
+ }
+ }
+ ScriptField_ShaderParam_s.Item paramRS = new ScriptField_ShaderParam_s.Item();
+ paramRS.bufferOffset = offset;
+ paramRS.transformTimestamp = 0;
+ paramRS.dataTimestamp = 0;
+ paramRS.data = matchingParam.getRSData().getAllocation();
+ if (subElem.getDataType() == Element.DataType.FLOAT_32) {
+ paramRS.float_vecSize = subElem.getVectorSize();
+ }
+
+ paramList.add(paramRS);
+ }
+
+ ScriptField_ShaderParam_s rsParams = null;
+ int paramCount = paramList.size();
+ if (paramCount != 0) {
+ rsParams = new ScriptField_ShaderParam_s(rs, paramCount);
+ for (int i = 0; i < paramCount; i++) {
+ rsParams.set(paramList.get(i), i, false);
+ }
+ rsParams.copyAll();
+ }
+ return rsParams;
+ }
+
+ public ShaderParam(String name) {
+ mParamName = name;
+ mData = new ScriptField_ShaderParamData_s.Item();
+ }
+
+ public String getParamName() {
+ return mParamName;
+ }
+
+ public void setCamera(Camera c) {
+ mCamera = c;
+ if (mField != null) {
+ mData.camera = mCamera.getRSData().getAllocation();
+ mField.set_camera(0, mData.camera, true);
+ }
+ }
+
+ protected void incTimestamp() {
+ if (mField != null) {
+ mData.timestamp ++;
+ mData.timestamp %= sMaxTimeStamp;
+ mField.set_timestamp(0, mData.timestamp, true);
+ }
+ }
+
+ abstract void initLocalData();
+
+ public ScriptField_ShaderParamData_s getRSData() {
+ if (mField != null) {
+ return mField;
+ }
+
+ RenderScriptGL rs = SceneManager.getRS();
+ mField = new ScriptField_ShaderParamData_s(rs, 1);
+
+ if (mParamName != null) {
+ mData.paramName = SceneManager.getCachedAlloc(mParamName);
+ if (mData.paramName == null) {
+ mData.paramName = SceneManager.getStringAsAllocation(rs, mParamName);
+ SceneManager.cacheAlloc(mParamName, mData.paramName);
+ }
+ }
+ initLocalData();
+ mData.timestamp = 1;
+
+ mField.set(mData, 0, true);
+ return mField;
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Texture2D.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Texture2D.java
new file mode 100644
index 000000000000..8fae9d931700
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Texture2D.java
@@ -0,0 +1,97 @@
+/*
+ * 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.scenegraph;
+
+import java.lang.Math;
+
+import com.android.scenegraph.SceneManager;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class Texture2D extends TextureBase {
+ String mFileName;
+ String mFileDir;
+
+ public Texture2D() {
+ super(ScriptC_export.const_TextureType_TEXTURE_2D);
+ }
+
+ public Texture2D(Allocation tex) {
+ super(ScriptC_export.const_TextureType_TEXTURE_2D);
+ setTexture(tex);
+ }
+
+ public void setFileDir(String dir) {
+ mFileDir = dir;
+ }
+
+ public void setFileName(String file) {
+ mFileName = file;
+ }
+
+ public String getFileName() {
+ return mFileName;
+ }
+
+ public void setTexture(Allocation tex) {
+ mData.texture = tex != null ? tex : SceneManager.getDefaultTex2D();
+ if (mField != null) {
+ mField.set_texture(0, mData.texture, true);
+ }
+ }
+
+ void load() {
+ RenderScriptGL rs = SceneManager.getRS();
+ Resources res = SceneManager.getRes();
+ String shortName = mFileName.substring(mFileName.lastIndexOf('/') + 1);
+ setTexture(SceneManager.loadTexture2D(mFileDir + shortName, rs, res));
+ }
+
+ ScriptField_Texture_s getRsData(boolean loadNow) {
+ if (mField != null) {
+ return mField;
+ }
+
+ RenderScriptGL rs = SceneManager.getRS();
+ Resources res = SceneManager.getRes();
+ if (rs == null || res == null) {
+ return null;
+ }
+
+ mField = new ScriptField_Texture_s(rs, 1);
+
+ if (loadNow) {
+ load();
+ } else {
+ mData.texture = SceneManager.getDefaultTex2D();
+ new SingleImageLoaderTask().execute(this);
+ }
+
+ mField.set(mData, 0, true);
+ return mField;
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureBase.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureBase.java
new file mode 100644
index 000000000000..ba49d4e2cc0e
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureBase.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012 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.scenegraph;
+
+import java.lang.Math;
+
+import com.android.scenegraph.SceneManager;
+import android.os.AsyncTask;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public abstract class TextureBase extends SceneGraphBase {
+
+ class SingleImageLoaderTask extends AsyncTask<TextureBase, Void, Boolean> {
+ protected Boolean doInBackground(TextureBase... objects) {
+ TextureBase tex = objects[0];
+ tex.load();
+ return new Boolean(true);
+ }
+ protected void onPostExecute(Boolean result) {
+ }
+ }
+
+ ScriptField_Texture_s.Item mData;
+ ScriptField_Texture_s mField;
+ TextureBase(int type) {
+ mData = new ScriptField_Texture_s.Item();
+ mData.type = type;
+ }
+
+ protected Allocation mRsTexture;
+ abstract ScriptField_Texture_s getRsData(boolean loadNow);
+ abstract void load();
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureCube.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureCube.java
new file mode 100644
index 000000000000..12c81c20dd11
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureCube.java
@@ -0,0 +1,104 @@
+/*
+ * 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.scenegraph;
+
+import java.lang.Math;
+
+import com.android.scenegraph.SceneManager;
+import com.android.scenegraph.TextureBase;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class TextureCube extends TextureBase {
+ String mFileName;
+ String mFileDir;
+
+ public TextureCube() {
+ super(ScriptC_export.const_TextureType_TEXTURE_CUBE);
+ }
+
+ public TextureCube(Allocation tex) {
+ super(ScriptC_export.const_TextureType_TEXTURE_CUBE);
+ setTexture(tex);
+ }
+
+ public TextureCube(String dir, String file) {
+ super(ScriptC_export.const_TextureType_TEXTURE_CUBE);
+ setFileDir(dir);
+ setFileName(file);
+ }
+
+ public void setFileDir(String dir) {
+ mFileDir = dir;
+ }
+
+ public void setFileName(String file) {
+ mFileName = file;
+ }
+
+ public String getFileName() {
+ return mFileName;
+ }
+
+ public void setTexture(Allocation tex) {
+ mData.texture = tex != null ? tex : SceneManager.getDefaultTexCube();
+ if (mField != null) {
+ mField.set_texture(0, mData.texture, true);
+ }
+ }
+
+ void load() {
+ RenderScriptGL rs = SceneManager.getRS();
+ Resources res = SceneManager.getRes();
+ String shortName = mFileName.substring(mFileName.lastIndexOf('/') + 1);
+ setTexture(SceneManager.loadCubemap(mFileDir + shortName, rs, res));
+ }
+
+ ScriptField_Texture_s getRsData(boolean loadNow) {
+ if (mField != null) {
+ return mField;
+ }
+
+ RenderScriptGL rs = SceneManager.getRS();
+ Resources res = SceneManager.getRes();
+ if (rs == null || res == null) {
+ return null;
+ }
+
+ mField = new ScriptField_Texture_s(rs, 1);
+
+ if (loadNow) {
+ load();
+ } else {
+ mData.texture = SceneManager.getDefaultTexCube();
+ new SingleImageLoaderTask().execute(this);
+ }
+
+ mField.set(mData, 0, true);
+ return mField;
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureParam.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureParam.java
new file mode 100644
index 000000000000..e656ed264409
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureParam.java
@@ -0,0 +1,67 @@
+/*
+ * 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.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.graphics.Camera;
+import android.renderscript.RenderScriptGL;
+import android.renderscript.Float4;
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.Element;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class TextureParam extends ShaderParam {
+
+ TextureBase mTexture;
+
+ public TextureParam(String name) {
+ super(name);
+ }
+
+ public TextureParam(String name, TextureBase t) {
+ super(name);
+ setTexture(t);
+ }
+
+ public void setTexture(TextureBase t) {
+ mTexture = t;
+ }
+
+ public TextureBase getTexture() {
+ return mTexture;
+ }
+
+ void initLocalData() {
+ mData.type = ScriptC_export.const_ShaderParam_TEXTURE;
+ if (mTexture != null) {
+ mData.texture = mTexture.getRsData(false).getAllocation();
+ }
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureRenderTarget.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureRenderTarget.java
new file mode 100644
index 000000000000..6aa29a53ecc4
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureRenderTarget.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2012 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.scenegraph;
+
+import java.lang.Math;
+
+import com.android.scenegraph.SceneManager;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class TextureRenderTarget extends TextureBase {
+ public TextureRenderTarget() {
+ super(ScriptC_export.const_TextureType_TEXTURE_RENDER_TARGET);
+ }
+
+ public TextureRenderTarget(Allocation tex) {
+ super(ScriptC_export.const_TextureType_TEXTURE_RENDER_TARGET);
+ setTexture(tex);
+ }
+
+ public void setTexture(Allocation tex) {
+ mData.texture = tex;
+ if (mField != null) {
+ mField.set_texture(0, mData.texture, true);
+ }
+ }
+
+ void load() {
+ }
+
+ ScriptField_Texture_s getRsData(boolean loadNow) {
+ if (mField != null) {
+ return mField;
+ }
+
+ RenderScriptGL rs = SceneManager.getRS();
+ if (rs == null) {
+ return null;
+ }
+
+ mField = new ScriptField_Texture_s(rs, 1);
+ mField.set(mData, 0, true);
+ return mField;
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Transform.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Transform.java
new file mode 100644
index 000000000000..8180bd071636
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Transform.java
@@ -0,0 +1,98 @@
+/*
+ * 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.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.renderscript.*;
+import android.renderscript.Matrix4f;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public abstract class Transform extends SceneGraphBase {
+ Transform mParent;
+ ArrayList<Transform> mChildren;
+
+ ScriptField_SgTransform mField;
+ ScriptField_SgTransform.Item mTransformData;
+
+ public Transform() {
+ mChildren = new ArrayList<Transform>();
+ mParent = null;
+ }
+
+ public void appendChild(Transform t) {
+ mChildren.add(t);
+ t.mParent = this;
+ updateRSChildData(true);
+ }
+
+ abstract void initLocalData();
+
+ void updateRSChildData(boolean copyData) {
+ if (mField == null) {
+ return;
+ }
+ RenderScriptGL rs = SceneManager.getRS();
+ if (mChildren.size() != 0) {
+ Allocation childRSData = Allocation.createSized(rs, Element.ALLOCATION(rs),
+ mChildren.size());
+ mTransformData.children = childRSData;
+
+ Allocation[] childrenAllocs = new Allocation[mChildren.size()];
+ for (int i = 0; i < mChildren.size(); i ++) {
+ Transform child = mChildren.get(i);
+ childrenAllocs[i] = child.getRSData().getAllocation();
+ }
+ childRSData.copyFrom(childrenAllocs);
+ }
+ if (copyData) {
+ mField.set(mTransformData, 0, true);
+ }
+ }
+
+ ScriptField_SgTransform getRSData() {
+ if (mField != null) {
+ return mField;
+ }
+
+ RenderScriptGL rs = SceneManager.getRS();
+ if (rs == null) {
+ return null;
+ }
+ mField = new ScriptField_SgTransform(rs, 1);
+
+ mTransformData = new ScriptField_SgTransform.Item();
+ mTransformData.name = getNameAlloc(rs);
+ mTransformData.isDirty = 1;
+ mTransformData.timestamp = 1;
+
+ initLocalData();
+ updateRSChildData(false);
+
+ mField.set(mTransformData, 0, true);
+ return mField;
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TransformParam.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TransformParam.java
new file mode 100644
index 000000000000..d120d5d9b97d
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TransformParam.java
@@ -0,0 +1,85 @@
+/*
+ * 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.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.renderscript.RenderScriptGL;
+import android.renderscript.Matrix4f;
+import android.renderscript.ProgramFragment;
+import android.renderscript.ProgramStore;
+import android.renderscript.ProgramVertex;
+import android.renderscript.Element;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class TransformParam extends ShaderParam {
+
+ Transform mTransform;
+ LightBase mLight;
+
+ public TransformParam(String name) {
+ super(name);
+ }
+
+ public void setTransform(Transform t) {
+ mTransform = t;
+ if (mField != null && mTransform != null) {
+ mData.transform = mTransform.getRSData().getAllocation();
+ }
+ incTimestamp();
+ }
+
+ int getTypeFromName() {
+ int paramType = ScriptC_export.const_ShaderParam_TRANSFORM_DATA;
+ if (mParamName.equalsIgnoreCase(view)) {
+ paramType = ScriptC_export.const_ShaderParam_TRANSFORM_VIEW;
+ } else if(mParamName.equalsIgnoreCase(proj)) {
+ paramType = ScriptC_export.const_ShaderParam_TRANSFORM_PROJ;
+ } else if(mParamName.equalsIgnoreCase(viewProj)) {
+ paramType = ScriptC_export.const_ShaderParam_TRANSFORM_VIEW_PROJ;
+ } else if(mParamName.equalsIgnoreCase(model)) {
+ paramType = ScriptC_export.const_ShaderParam_TRANSFORM_MODEL;
+ } else if(mParamName.equalsIgnoreCase(modelView)) {
+ paramType = ScriptC_export.const_ShaderParam_TRANSFORM_MODEL_VIEW;
+ } else if(mParamName.equalsIgnoreCase(modelViewProj)) {
+ paramType = ScriptC_export.const_ShaderParam_TRANSFORM_MODEL_VIEW_PROJ;
+ }
+ return paramType;
+ }
+
+ void initLocalData() {
+ mData.type = getTypeFromName();
+ if (mTransform != null) {
+ mData.transform = mTransform.getRSData().getAllocation();
+ }
+ if (mCamera != null) {
+ mData.camera = mCamera.getRSData().getAllocation();
+ }
+ if (mLight != null) {
+ mData.light = mLight.getRSData().getAllocation();
+ }
+ }
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/VertexShader.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/VertexShader.java
new file mode 100644
index 000000000000..f7d0e6d8a48a
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/VertexShader.java
@@ -0,0 +1,108 @@
+/*
+ * 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.scenegraph;
+
+import java.lang.Math;
+import java.util.ArrayList;
+
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.util.Log;
+
+/**
+ * @hide
+ */
+public class VertexShader extends Shader {
+ ProgramVertex mProgram;
+ ScriptField_VertexShader_s mField;
+
+ public static class Builder {
+ VertexShader mShader;
+ ProgramVertex.Builder mBuilder;
+
+ public Builder(RenderScriptGL rs) {
+ mShader = new VertexShader();
+ mBuilder = new ProgramVertex.Builder(rs);
+ }
+
+ public Builder setShader(Resources resources, int resourceID) {
+ mBuilder.setShader(resources, resourceID);
+ return this;
+ }
+
+ public Builder setObjectConst(Type type) {
+ mShader.mPerObjConstants = type;
+ return this;
+ }
+
+ public Builder setShaderConst(Type type) {
+ mShader.mPerShaderConstants = type;
+ return this;
+ }
+
+ public Builder addInput(Element e) {
+ mBuilder.addInput(e);
+ return this;
+ }
+
+ public VertexShader create() {
+ if (mShader.mPerShaderConstants != null) {
+ mBuilder.addConstant(mShader.mPerShaderConstants);
+ }
+ if (mShader.mPerObjConstants != null) {
+ mBuilder.addConstant(mShader.mPerObjConstants);
+ }
+ mShader.mProgram = mBuilder.create();
+ return mShader;
+ }
+ }
+
+ public ProgramVertex getProgram() {
+ return mProgram;
+ }
+
+ ScriptField_VertexShader_s getRSData() {
+ if (mField != null) {
+ return mField;
+ }
+
+ RenderScriptGL rs = SceneManager.getRS();
+ Resources res = SceneManager.getRes();
+ if (rs == null || res == null) {
+ return null;
+ }
+
+ ScriptField_VertexShader_s.Item item = new ScriptField_VertexShader_s.Item();
+ item.program = mProgram;
+
+ linkConstants(rs);
+ if (mPerShaderConstants != null) {
+ item.shaderConst = mConstantBuffer;
+ item.shaderConstParams = mConstantBufferParams.getAllocation();
+ mProgram.bindConstants(item.shaderConst, 0);
+ }
+
+ item.objectConstIndex = -1;
+ if (mPerObjConstants != null) {
+ item.objectConstIndex = mPerShaderConstants != null ? 1 : 0;
+ }
+
+ mField = new ScriptField_VertexShader_s(rs, 1);
+ mField.set(item, 0, true);
+ return mField;
+ }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/camera.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/camera.rs
new file mode 100644
index 000000000000..dc0a885a685d
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/camera.rs
@@ -0,0 +1,66 @@
+// 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.scenegraph)
+
+//#define DEBUG_CAMERA
+#include "scenegraph_objects.rsh"
+
+void root(const rs_allocation *v_in, rs_allocation *v_out, const float *usrData) {
+
+ SgCamera *cam = (SgCamera *)rsGetElementAt(*v_in, 0);
+ float aspect = *usrData;
+ if (cam->aspect != aspect) {
+ cam->isDirty = 1;
+ cam->aspect = aspect;
+ }
+ if (cam->isDirty) {
+ rsMatrixLoadPerspective(&cam->proj, cam->horizontalFOV, cam->aspect, cam->near, cam->far);
+ }
+
+ const SgTransform *camTransform = (const SgTransform *)rsGetElementAt(cam->transformMatrix, 0);
+ //rsDebug("Camera stamp", cam->transformTimestamp);
+ //rsDebug("Transform stamp", camTransform->timestamp);
+ if (camTransform->timestamp != cam->transformTimestamp || cam->isDirty) {
+ cam->isDirty = 1;
+ rs_matrix4x4 camPosMatrix;
+ rsMatrixLoad(&camPosMatrix, &camTransform->globalMat);
+ float4 zero = {0.0f, 0.0f, 0.0f, 1.0f};
+ cam->position = rsMatrixMultiply(&camPosMatrix, zero);
+
+ rsMatrixInverse(&camPosMatrix);
+ rsMatrixLoad(&cam->view, &camPosMatrix);
+
+ rsMatrixLoad(&cam->viewProj, &cam->proj);
+ rsMatrixMultiply(&cam->viewProj, &cam->view);
+
+ rsExtractFrustumPlanes(&cam->viewProj,
+ &cam->frustumPlanes[0], &cam->frustumPlanes[1],
+ &cam->frustumPlanes[2], &cam->frustumPlanes[3],
+ &cam->frustumPlanes[3], &cam->frustumPlanes[4]);
+ }
+
+ if (cam->isDirty) {
+ cam->timestamp ++;
+ }
+
+ cam->isDirty = 0;
+ cam->transformTimestamp = camTransform->timestamp;
+
+#ifdef DEBUG_CAMERA
+ printCameraInfo(cam);
+#endif //DEBUG_CAMERA
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/cull.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/cull.rs
new file mode 100644
index 000000000000..024e026b69df
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/cull.rs
@@ -0,0 +1,86 @@
+// Copyright (C) 2012 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.scenegraph)
+
+#include "scenegraph_objects.rsh"
+
+static void getTransformedSphere(SgRenderable *obj) {
+ obj->worldBoundingSphere = obj->boundingSphere;
+ obj->worldBoundingSphere.w = 1.0f;
+ const SgTransform *objTransform = (const SgTransform *)rsGetElementAt(obj->transformMatrix, 0);
+ obj->worldBoundingSphere = rsMatrixMultiply(&objTransform->globalMat, obj->worldBoundingSphere);
+
+ const float4 unitVec = {0.57735f, 0.57735f, 0.57735f, 0.0f};
+ float4 scaledVec = rsMatrixMultiply(&objTransform->globalMat, unitVec);
+ scaledVec.w = 0.0f;
+ obj->worldBoundingSphere.w = obj->boundingSphere.w * length(scaledVec);
+}
+
+static bool frustumCulled(SgRenderable *obj, SgCamera *cam) {
+ if (!obj->bVolInitialized) {
+ float minX, minY, minZ, maxX, maxY, maxZ;
+ rsgMeshComputeBoundingBox(obj->mesh,
+ &minX, &minY, &minZ,
+ &maxX, &maxY, &maxZ);
+ //rsDebug("min", minX, minY, minZ);
+ //rsDebug("max", maxX, maxY, maxZ);
+ float4 sphere;
+ sphere.x = (maxX + minX) * 0.5f;
+ sphere.y = (maxY + minY) * 0.5f;
+ sphere.z = (maxZ + minZ) * 0.5f;
+ float3 radius;
+ radius.x = (maxX - sphere.x);
+ radius.y = (maxY - sphere.y);
+ radius.z = (maxZ - sphere.z);
+
+ sphere.w = length(radius);
+ obj->boundingSphere = sphere;
+ obj->bVolInitialized = 1;
+ //rsDebug("Sphere", sphere);
+ }
+
+ getTransformedSphere(obj);
+
+ return !rsIsSphereInFrustum(&obj->worldBoundingSphere,
+ &cam->frustumPlanes[0], &cam->frustumPlanes[1],
+ &cam->frustumPlanes[2], &cam->frustumPlanes[3],
+ &cam->frustumPlanes[4], &cam->frustumPlanes[5]);
+}
+
+
+void root(rs_allocation *v_out, const void *usrData) {
+
+ SgRenderable *drawable = (SgRenderable *)rsGetElementAt(*v_out, 0);
+ const SgCamera *camera = (const SgCamera*)usrData;
+
+ drawable->isVisible = 0;
+ // Not loaded yet
+ if (!rsIsObject(drawable->mesh) || drawable->cullType == CULL_ALWAYS) {
+ return;
+ }
+
+ // check to see if we are culling this object and if it's
+ // outside the frustum
+ if (drawable->cullType == CULL_FRUSTUM && frustumCulled(drawable, (SgCamera*)camera)) {
+#ifdef DEBUG_RENDERABLES
+ rsDebug("Culled", drawable);
+ printName(drawable->name);
+#endif // DEBUG_RENDERABLES
+ return;
+ }
+ drawable->isVisible = 1;
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/export.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/export.rs
new file mode 100644
index 000000000000..b438a43abaab
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/export.rs
@@ -0,0 +1,61 @@
+// 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.scenegraph)
+
+// The sole purpose of this script is to have various structs exposed
+// so that java reflected classes are generated
+#include "scenegraph_objects.rsh"
+
+// Export our native constants to java so that we don't have parallel definitions
+const int ShaderParam_FLOAT4_DATA = SHADER_PARAM_FLOAT4_DATA;
+const int ShaderParam_TRANSFORM_DATA = SHADER_PARAM_TRANSFORM_DATA;
+const int ShaderParam_TRANSFORM_MODEL = SHADER_PARAM_TRANSFORM_MODEL;
+
+const int ShaderParam_FLOAT4_CAMERA_POS = SHADER_PARAM_FLOAT4_CAMERA_POS;
+const int ShaderParam_FLOAT4_CAMERA_DIR = SHADER_PARAM_FLOAT4_CAMERA_DIR;
+const int ShaderParam_TRANSFORM_VIEW = SHADER_PARAM_TRANSFORM_VIEW;
+const int ShaderParam_TRANSFORM_PROJ = SHADER_PARAM_TRANSFORM_PROJ;
+const int ShaderParam_TRANSFORM_VIEW_PROJ = SHADER_PARAM_TRANSFORM_VIEW_PROJ;
+const int ShaderParam_TRANSFORM_MODEL_VIEW = SHADER_PARAM_TRANSFORM_MODEL_VIEW;
+const int ShaderParam_TRANSFORM_MODEL_VIEW_PROJ = SHADER_PARAM_TRANSFORM_MODEL_VIEW_PROJ;
+
+const int ShaderParam_FLOAT4_LIGHT_COLOR = SHADER_PARAM_FLOAT4_LIGHT_COLOR;
+const int ShaderParam_FLOAT4_LIGHT_POS = SHADER_PARAM_FLOAT4_LIGHT_POS;
+const int ShaderParam_FLOAT4_LIGHT_DIR = SHADER_PARAM_FLOAT4_LIGHT_DIR;
+
+const int ShaderParam_TEXTURE = SHADER_PARAM_TEXTURE;
+
+const int Transform_TRANSLATE = TRANSFORM_TRANSLATE;
+const int Transform_ROTATE = TRANSFORM_ROTATE;
+const int Transform_SCALE = TRANSFORM_SCALE;
+
+const int TextureType_TEXTURE_2D = TEXTURE_2D;
+const int TextureType_TEXTURE_CUBE = TEXTURE_CUBE;
+const int TextureType_TEXTURE_RENDER_TARGET = TEXTURE_RENDER_TARGET;
+
+SgTransform *exportPtr;
+SgTransformComponent *componentPtr;
+SgRenderState *sExport;
+SgRenderable *drExport;
+SgRenderPass *pExport;
+SgCamera *exportPtrCam;
+SgLight *exportPtrLight;
+SgShaderParam *spExport;
+SgShaderParamData *spDataExport;
+SgVertexShader *pvExport;
+SgFragmentShader *pfExport;
+SgTexture *texExport;
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/fragment_params.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/fragment_params.rs
new file mode 100644
index 000000000000..7202285c247e
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/fragment_params.rs
@@ -0,0 +1,30 @@
+// Copyright (C) 2012 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.scenegraph)
+
+#include "scenegraph_objects.rsh"
+
+//#define DEBUG_PARAMS
+
+#include "params.rsh"
+
+void root(rs_allocation *v_out, const void *usrData) {
+ SgFragmentShader *shader = (SgFragmentShader *)rsGetElementAt(*v_out, 0);
+ const SgCamera *camera = (const SgCamera*)usrData;
+ processAllParams(shader->shaderConst, shader->shaderConstParams, camera);
+ processTextureParams(shader);
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/light.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/light.rs
new file mode 100644
index 000000000000..e11979f27ff8
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/light.rs
@@ -0,0 +1,33 @@
+// 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.scenegraph)
+
+//#define DEBUG_LIGHT
+#include "scenegraph_objects.rsh"
+
+void root(const rs_allocation *v_in, rs_allocation *v_out) {
+
+ SgLight *light = (SgLight *)rsGetElementAt(*v_in, 0);
+ const SgTransform *lTransform = (const SgTransform *)rsGetElementAt(light->transformMatrix, 0);
+
+ float4 zero = {0.0f, 0.0f, 0.0f, 1.0f};
+ light->position = rsMatrixMultiply(&lTransform->globalMat, zero);
+
+#ifdef DEBUG_LIGHT
+ printLightInfo(light);
+#endif //DEBUG_LIGHT
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/object_params.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/object_params.rs
new file mode 100644
index 000000000000..0d524a663150
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/object_params.rs
@@ -0,0 +1,36 @@
+// Copyright (C) 2012 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.scenegraph)
+
+#include "scenegraph_objects.rsh"
+
+//#define DEBUG_PARAMS
+
+#include "params.rsh"
+
+void root(rs_allocation *v_out, const void *usrData) {
+
+ SgRenderable *drawable = (SgRenderable *)rsGetElementAt(*v_out, 0);
+ // Visibility flag was set earlier in the cull stage
+ if (!drawable->isVisible) {
+ return;
+ }
+
+ const SgCamera *camera = (const SgCamera*)usrData;
+ processAllParams(drawable->pf_const, drawable->pf_constParams, camera);
+ processAllParams(drawable->pv_const, drawable->pv_constParams, camera);
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh
new file mode 100644
index 000000000000..575794bff452
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh
@@ -0,0 +1,193 @@
+// Copyright (C) 2012 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.scenegraph)
+
+#include "scenegraph_objects.rsh"
+
+//#define DEBUG_PARAMS
+static void debugParam(SgShaderParam *p, SgShaderParamData *pData) {
+ rsDebug("____________ Param ____________", p);
+ printName(pData->paramName);
+ rsDebug("bufferOffset", p->bufferOffset);
+ rsDebug("type ", pData->type);
+ rsDebug("data timestamp ", pData->timestamp);
+ rsDebug("param timestamp", p->dataTimestamp);
+
+ const SgTransform *pTransform = NULL;
+ if (rsIsObject(pData->transform)) {
+ pTransform = (const SgTransform *)rsGetElementAt(pData->transform, 0);
+
+ rsDebug("transform", pTransform);
+ printName(pTransform->name);
+ rsDebug("timestamp", pTransform->timestamp);
+ rsDebug("param timestamp", p->transformTimestamp);
+ }
+
+ const SgLight *pLight = NULL;
+ if (rsIsObject(pData->light)) {
+ pLight = (const SgLight *)rsGetElementAt(pData->light, 0);
+ printLightInfo(pLight);
+ }
+}
+
+
+static void writeFloatData(float *ptr, const float4 *input, uint32_t vecSize) {
+#ifdef DEBUG_PARAMS
+ rsDebug("Writing value ", *input);
+ rsDebug("Writing vec size ", vecSize);
+#endif // DEBUG_PARAMS
+
+ switch (vecSize) {
+ case 1:
+ *ptr = input->x;
+ break;
+ case 2:
+ *((float2*)ptr) = (*input).xy;
+ break;
+ case 3:
+ *((float3*)ptr) = (*input).xyz;
+ break;
+ case 4:
+ *((float4*)ptr) = *input;
+ break;
+ }
+}
+
+static bool processParam(SgShaderParam *p, SgShaderParamData *pData,
+ uint8_t *constantBuffer,
+ const SgCamera *currentCam,
+ SgFragmentShader *shader) {
+ bool isDataOnly = (pData->type > SHADER_PARAM_DATA_ONLY);
+ const SgTransform *pTransform = NULL;
+ if (rsIsObject(pData->transform)) {
+ pTransform = (const SgTransform *)rsGetElementAt(pData->transform, 0);
+ }
+
+ if (isDataOnly) {
+ // If we are a transform param and our transform is unchanged, nothing to do
+ if (pTransform) {
+ if (p->transformTimestamp == pTransform->timestamp) {
+ return false;
+ }
+ p->transformTimestamp = pTransform->timestamp;
+ } else {
+ if (p->dataTimestamp == pData->timestamp) {
+ return false;
+ }
+ p->dataTimestamp = pData->timestamp;
+ }
+ }
+
+ const SgLight *pLight = NULL;
+ if (rsIsObject(pData->light)) {
+ pLight = (const SgLight *)rsGetElementAt(pData->light, 0);
+ }
+
+ uint8_t *dataPtr = NULL;
+ const SgTexture *tex = NULL;
+ if (pData->type == SHADER_PARAM_TEXTURE) {
+ tex = rsGetElementAt(pData->texture, 0);
+ } else {
+ dataPtr = constantBuffer + p->bufferOffset;
+ }
+
+ switch (pData->type) {
+ case SHADER_PARAM_TEXTURE:
+ rsgBindTexture(shader->program, p->bufferOffset, tex->texture);
+ break;
+ case SHADER_PARAM_FLOAT4_DATA:
+ writeFloatData((float*)dataPtr, &pData->float_value, p->float_vecSize);
+ break;
+ case SHADER_PARAM_FLOAT4_CAMERA_POS:
+ writeFloatData((float*)dataPtr, &currentCam->position, p->float_vecSize);
+ break;
+ case SHADER_PARAM_FLOAT4_CAMERA_DIR: break;
+ case SHADER_PARAM_FLOAT4_LIGHT_COLOR:
+ writeFloatData((float*)dataPtr, &pLight->color, p->float_vecSize);
+ break;
+ case SHADER_PARAM_FLOAT4_LIGHT_POS:
+ writeFloatData((float*)dataPtr, &pLight->position, p->float_vecSize);
+ break;
+ case SHADER_PARAM_FLOAT4_LIGHT_DIR: break;
+
+ case SHADER_PARAM_TRANSFORM_DATA:
+ rsMatrixLoad((rs_matrix4x4*)dataPtr, &pTransform->globalMat);
+ break;
+ case SHADER_PARAM_TRANSFORM_VIEW:
+ rsMatrixLoad((rs_matrix4x4*)dataPtr, &currentCam->view);
+ break;
+ case SHADER_PARAM_TRANSFORM_PROJ:
+ rsMatrixLoad((rs_matrix4x4*)dataPtr, &currentCam->proj);
+ break;
+ case SHADER_PARAM_TRANSFORM_VIEW_PROJ:
+ rsMatrixLoad((rs_matrix4x4*)dataPtr, &currentCam->viewProj);
+ break;
+ case SHADER_PARAM_TRANSFORM_MODEL:
+ rsMatrixLoad((rs_matrix4x4*)dataPtr, &pTransform->globalMat);
+ break;
+ case SHADER_PARAM_TRANSFORM_MODEL_VIEW:
+ rsMatrixLoad((rs_matrix4x4*)dataPtr, &currentCam->view);
+ rsMatrixLoadMultiply((rs_matrix4x4*)dataPtr,
+ (rs_matrix4x4*)dataPtr,
+ &pTransform->globalMat);
+ break;
+ case SHADER_PARAM_TRANSFORM_MODEL_VIEW_PROJ:
+ rsMatrixLoad((rs_matrix4x4*)dataPtr, &currentCam->viewProj);
+ rsMatrixLoadMultiply((rs_matrix4x4*)dataPtr,
+ (rs_matrix4x4*)dataPtr,
+ &pTransform->globalMat);
+ break;
+ }
+ return true;
+}
+
+static void processAllParams(rs_allocation shaderConst,
+ rs_allocation allParams,
+ const SgCamera *camera) {
+ if (rsIsObject(shaderConst)) {
+ uint8_t *constantBuffer = (uint8_t*)rsGetElementAt(shaderConst, 0);
+
+ int numParams = 0;
+ if (rsIsObject(allParams)) {
+ numParams = rsAllocationGetDimX(allParams);
+ }
+ bool updated = false;
+ for (int i = 0; i < numParams; i ++) {
+ SgShaderParam *current = (SgShaderParam*)rsGetElementAt(allParams, i);
+ SgShaderParamData *currentData = (SgShaderParamData*)rsGetElementAt(current->data, 0);
+#ifdef DEBUG_PARAMS
+ debugParam(current, currentData);
+#endif // DEBUG_PARAMS
+ updated = processParam(current, currentData, constantBuffer, camera, NULL) || updated;
+ }
+ }
+}
+
+static void processTextureParams(SgFragmentShader *shader) {
+ int numParams = 0;
+ if (rsIsObject(shader->shaderTextureParams)) {
+ numParams = rsAllocationGetDimX(shader->shaderTextureParams);
+ }
+ for (int i = 0; i < numParams; i ++) {
+ SgShaderParam *current = (SgShaderParam*)rsGetElementAt(shader->shaderTextureParams, i);
+ SgShaderParamData *currentData = (SgShaderParamData*)rsGetElementAt(current->data, 0);
+#ifdef DEBUG_PARAMS
+ debugParam(current, currentData);
+#endif // DEBUG_PARAMS
+ processParam(current, currentData, NULL, NULL, shader);
+ }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs
new file mode 100644
index 000000000000..d8d48b3da25c
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs
@@ -0,0 +1,240 @@
+// Copyright (C) 2011-2012 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.scenegraph)
+
+#include "rs_graphics.rsh"
+#include "scenegraph_objects.rsh"
+
+rs_script gTransformScript;
+rs_script gCameraScript;
+rs_script gLightScript;
+rs_script gObjectParamsScript;
+rs_script gFragmentParamsScript;
+rs_script gVertexParamsScript;
+rs_script gCullScript;
+
+SgTransform *gRootNode;
+rs_allocation gCameras;
+rs_allocation gLights;
+rs_allocation gFragmentShaders;
+rs_allocation gVertexShaders;
+rs_allocation gRenderableObjects;
+
+rs_allocation gRenderPasses;
+
+// Temporary shaders
+rs_program_store gPFSBackground;
+
+uint32_t *gFrontToBack;
+static uint32_t gFrontToBackCount = 0;
+uint32_t *gBackToFront;
+static uint32_t gBackToFrontCount = 0;
+
+static SgCamera *gActiveCamera = NULL;
+
+static rs_allocation nullAlloc;
+
+// #define DEBUG_RENDERABLES
+static void draw(SgRenderable *obj) {
+#ifdef DEBUG_RENDERABLES
+ const SgTransform *objTransform = (const SgTransform *)rsGetElementAt(obj->transformMatrix, 0);
+ rsDebug("**** Drawing object with transform", obj);
+ printName(objTransform->name);
+ rsDebug("Model matrix: ", &objTransform->globalMat);
+ printName(obj->name);
+#endif //DEBUG_RENDERABLES
+
+ const SgRenderState *renderState = (const SgRenderState *)rsGetElementAt(obj->render_state, 0);
+ const SgVertexShader *pv = (const SgVertexShader *)rsGetElementAt(renderState->pv, 0);
+ const SgFragmentShader *pf = (const SgFragmentShader *)rsGetElementAt(renderState->pf, 0);
+
+ if (pv->objectConstIndex != -1) {
+ rsgBindConstant(pv->program, pv->objectConstIndex, obj->pv_const);
+ }
+ if (pf->objectConstIndex != -1) {
+ rsgBindConstant(pf->program, pf->objectConstIndex, obj->pf_const);
+ }
+
+ if (rsIsObject(renderState->ps)) {
+ rsgBindProgramStore(renderState->ps);
+ } else {
+ rsgBindProgramStore(gPFSBackground);
+ }
+
+ if (rsIsObject(renderState->pr)) {
+ rsgBindProgramRaster(renderState->pr);
+ } else {
+ rs_program_raster pr;
+ rsgBindProgramRaster(pr);
+ }
+
+ rsgBindProgramVertex(pv->program);
+ rsgBindProgramFragment(pf->program);
+
+ for (uint32_t i = 0; i < obj->pf_num_textures; i ++) {
+ const SgTexture *tex = rsGetElementAt(obj->pf_textures[i], 0);
+ rsgBindTexture(pf->program, i, tex->texture);
+ }
+
+ rsgDrawMesh(obj->mesh, obj->meshIndex);
+}
+
+static void sortToBucket(SgRenderable *obj) {
+ const SgRenderState *renderState = (const SgRenderState *)rsGetElementAt(obj->render_state, 0);
+ if (rsIsObject(renderState->ps)) {
+ bool isOpaque = false;
+ if (isOpaque) {
+ gFrontToBack[gFrontToBackCount++] = (uint32_t)obj;
+ } else {
+ gBackToFront[gBackToFrontCount++] = (uint32_t)obj;
+ }
+ } else {
+ gFrontToBack[gFrontToBackCount++] = (uint32_t)obj;
+ }
+}
+
+static void updateActiveCamera(rs_allocation cam) {
+ gActiveCamera = (SgCamera *)rsGetElementAt(cam, 0);
+}
+
+static void prepareCameras() {
+ // now compute all the camera matrices
+ if (rsIsObject(gCameras)) {
+ float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
+ rsForEach(gCameraScript, gCameras, nullAlloc, &aspect, sizeof(aspect));
+ }
+}
+
+static void prepareLights() {
+ if (rsIsObject(gLights)) {
+ rsForEach(gLightScript, gLights, nullAlloc);
+ }
+}
+
+static void drawSorted() {
+ for (int i = 0; i < gFrontToBackCount; i ++) {
+ SgRenderable *current = (SgRenderable*)gFrontToBack[i];
+ draw(current);
+ }
+
+ for (int i = 0; i < gBackToFrontCount; i ++) {
+ SgRenderable *current = (SgRenderable*)gBackToFront[i];
+ draw(current);
+ }
+}
+
+static void drawAllObjects(rs_allocation allObj) {
+ if (!rsIsObject(allObj)) {
+ return;
+ }
+
+ rsForEach(gVertexParamsScript, nullAlloc, gVertexShaders,
+ gActiveCamera, sizeof(gActiveCamera));
+ rsForEach(gFragmentParamsScript, nullAlloc, gFragmentShaders,
+ gActiveCamera, sizeof(gActiveCamera));
+
+ // Run the params and cull script
+ rsForEach(gCullScript, nullAlloc, allObj, gActiveCamera, sizeof(gActiveCamera));
+ rsForEach(gObjectParamsScript, nullAlloc, allObj, gActiveCamera, sizeof(gActiveCamera));
+
+ int numRenderables = rsAllocationGetDimX(allObj);
+ for (int i = 0; i < numRenderables; i ++) {
+ rs_allocation *drawAlloc = (rs_allocation*)rsGetElementAt(allObj, i);
+ SgRenderable *current = (SgRenderable*)rsGetElementAt(*drawAlloc, 0);
+ if (current->isVisible) {
+ sortToBucket(current);
+ }
+ }
+ drawSorted();
+}
+
+int root(void) {
+#ifdef DEBUG_RENDERABLES
+ rsDebug("=============================================================================", 0);
+#endif // DEBUG_RENDERABLES
+
+ // first step is to update the transform hierachy
+ if (gRootNode && rsIsObject(gRootNode->children)) {
+ rsForEach(gTransformScript, gRootNode->children, nullAlloc, 0, 0);
+ }
+
+ prepareCameras();
+ prepareLights();
+
+ if (rsIsObject(gRenderPasses)) {
+ rsgClearDepth(1.0f);
+ int numPasses = rsAllocationGetDimX(gRenderPasses);
+ for (uint i = 0; i < numPasses; i ++) {
+ gFrontToBackCount = 0;
+ gBackToFrontCount = 0;
+ SgRenderPass *pass = (SgRenderPass*)rsGetElementAt(gRenderPasses, i);
+ if (rsIsObject(pass->color_target)) {
+ rsgBindColorTarget(pass->color_target, 0);
+ }
+ if (rsIsObject(pass->depth_target)) {
+ rsgBindDepthTarget(pass->depth_target);
+ }
+ if (!rsIsObject(pass->color_target) &&
+ !rsIsObject(pass->depth_target)) {
+ rsgClearAllRenderTargets();
+ }
+ updateActiveCamera(pass->camera);
+ if (pass->should_clear_color) {
+ rsgClearColor(pass->clear_color.x, pass->clear_color.y,
+ pass->clear_color.z, pass->clear_color.w);
+ }
+ if (pass->should_clear_depth) {
+ rsgClearDepth(pass->clear_depth);
+ }
+ drawAllObjects(pass->objects);
+ }
+ } else {
+ gFrontToBackCount = 0;
+ gBackToFrontCount = 0;
+ rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+ rsgClearDepth(1.0f);
+
+ if (rsIsObject(gCameras)) {
+ rs_allocation *camAlloc = (rs_allocation*)rsGetElementAt(gCameras, 0);
+ updateActiveCamera(*camAlloc);
+ }
+ drawAllObjects(gRenderableObjects);
+ }
+ return 10;
+}
+
+// Search through sorted and culled objects
+void pick(int screenX, int screenY) {
+ float3 pnt, vec;
+ getCameraRay(gActiveCamera, screenX, screenY, &pnt, &vec);
+
+ for (int i = 0; i < gFrontToBackCount; i ++) {
+ SgRenderable *current = (SgRenderable*)gFrontToBack[i];
+ bool isPicked = intersect(current, pnt, vec);
+ if (isPicked) {
+ current->cullType = CULL_ALWAYS;
+ }
+ }
+
+ for (int i = 0; i < gBackToFrontCount; i ++) {
+ SgRenderable *current = (SgRenderable*)gBackToFront[i];
+ bool isPicked = intersect(current, pnt, vec);
+ if (isPicked) {
+ current->cullType = CULL_ALWAYS;
+ }
+ }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh
new file mode 100644
index 000000000000..bdca3ab1995b
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh
@@ -0,0 +1,323 @@
+// Copyright (C) 2011-2012 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.scenegraph)
+
+#ifndef _TRANSFORM_DEF_
+#define _TRANSFORM_DEF_
+
+#include "rs_graphics.rsh"
+
+#define TRANSFORM_NONE 0
+#define TRANSFORM_TRANSLATE 1
+#define TRANSFORM_ROTATE 2
+#define TRANSFORM_SCALE 3
+
+#define CULL_FRUSTUM 0
+#define CULL_ALWAYS 2
+
+#define LIGHT_POINT 0
+#define LIGHT_DIRECTIONAL 1
+
+// Shader params that involve only data
+#define SHADER_PARAM_DATA_ONLY 10000
+#define SHADER_PARAM_FLOAT4_DATA 10001
+#define SHADER_PARAM_TRANSFORM_DATA 10002
+#define SHADER_PARAM_TRANSFORM_MODEL 10003
+
+// Shader params that involve camera
+#define SHADER_PARAM_CAMERA 1000
+#define SHADER_PARAM_FLOAT4_CAMERA_POS 1001
+#define SHADER_PARAM_FLOAT4_CAMERA_DIR 1002
+#define SHADER_PARAM_TRANSFORM_VIEW 1003
+#define SHADER_PARAM_TRANSFORM_PROJ 1004
+#define SHADER_PARAM_TRANSFORM_VIEW_PROJ 1005
+#define SHADER_PARAM_TRANSFORM_MODEL_VIEW 1006
+#define SHADER_PARAM_TRANSFORM_MODEL_VIEW_PROJ 1007
+
+// Shader Params that only involve lights
+#define SHADER_PARAM_LIGHT 100
+#define SHADER_PARAM_FLOAT4_LIGHT_COLOR 103
+#define SHADER_PARAM_FLOAT4_LIGHT_POS 104
+#define SHADER_PARAM_FLOAT4_LIGHT_DIR 105
+
+#define SHADER_PARAM_TEXTURE 10
+
+#define TEXTURE_NONE 0
+#define TEXTURE_2D 1
+#define TEXTURE_CUBE 2
+#define TEXTURE_RENDER_TARGET 3
+
+typedef struct TransformComponent_s {
+ float4 value;
+ int type;
+ rs_allocation name;
+} SgTransformComponent;
+
+typedef struct __attribute__((packed, aligned(4))) SgTransform {
+ rs_matrix4x4 globalMat;
+ rs_matrix4x4 localMat;
+
+ rs_allocation components;
+ int isDirty;
+
+ rs_allocation children;
+ rs_allocation name;
+
+ // Used to check whether transform params need to be updated
+ uint32_t timestamp;
+} SgTransform;
+
+typedef struct VertexShader_s {
+ rs_program_vertex program;
+ // Buffer with vertex constant data
+ rs_allocation shaderConst;
+ // ShaderParam's that populate data
+ rs_allocation shaderConstParams;
+ // location of the per object constants on the buffer
+ int objectConstIndex;
+} SgVertexShader;
+
+typedef struct FragmentShader_s {
+ rs_program_fragment program;
+ // Buffer with vertex constant data
+ rs_allocation shaderConst;
+ // ShaderParam's that populate data
+ rs_allocation shaderConstParams;
+ // ShaderParam's that set textures
+ rs_allocation shaderTextureParams;
+ // location of the per object constants on the buffer
+ int objectConstIndex;
+} SgFragmentShader;
+
+typedef struct RenderState_s {
+ rs_allocation pv; // VertexShader struct
+ rs_allocation pf; // FragmentShader struct
+ rs_program_store ps;
+ rs_program_raster pr;
+} SgRenderState;
+
+typedef struct Renderable_s {
+ rs_allocation render_state;
+ // Buffer with vertex constant data
+ rs_allocation pv_const;
+ // ShaderParam's that populate data
+ rs_allocation pv_constParams;
+ // Buffer with fragment constant data
+ rs_allocation pf_const;
+ // ShaderParam's that populate data
+ rs_allocation pf_constParams;
+ rs_allocation pf_textures[8];
+ int pf_num_textures;
+ rs_mesh mesh;
+ int meshIndex;
+ rs_allocation transformMatrix;
+ rs_allocation name;
+ float4 boundingSphere;
+ float4 worldBoundingSphere;
+ int bVolInitialized;
+ int cullType; // specifies whether to frustum cull
+ int isVisible;
+} SgRenderable;
+
+typedef struct RenderPass_s {
+ rs_allocation color_target;
+ rs_allocation depth_target;
+ rs_allocation camera;
+ rs_allocation objects;
+
+ float4 clear_color;
+ float clear_depth;
+ bool should_clear_color;
+ bool should_clear_depth;
+} SgRenderPass;
+
+typedef struct Camera_s {
+ rs_matrix4x4 proj;
+ rs_matrix4x4 view;
+ rs_matrix4x4 viewProj;
+ float4 position;
+ float near;
+ float far;
+ float horizontalFOV;
+ float aspect;
+ rs_allocation name;
+ rs_allocation transformMatrix;
+ float4 frustumPlanes[6];
+
+ int isDirty;
+ // Timestamp of the camera itself to signal params if anything changes
+ uint32_t timestamp;
+ // Timestamp of our transform
+ uint32_t transformTimestamp;
+} SgCamera;
+
+typedef struct Light_s {
+ float4 position;
+ float4 color;
+ float intensity;
+ int type;
+ rs_allocation name;
+ rs_allocation transformMatrix;
+} SgLight;
+
+// This represents the shader parameter data needed to set a float or transform data
+typedef struct ShaderParamData_s {
+ int type;
+ float4 float_value;
+ uint32_t timestamp;
+ rs_allocation paramName;
+ rs_allocation camera;
+ rs_allocation light;
+ rs_allocation transform;
+ rs_allocation texture;
+} SgShaderParamData;
+
+// This represents a shader parameter that knows how to update itself for a given
+// renderable or shader and contains a timestamp for the last time this buffer was updated
+typedef struct ShaderParam_s {
+ // Used to check whether transform params need to be updated
+ uint32_t transformTimestamp;
+ // Used to check whether data params need to be updated
+ // These are used when somebody set the matrix of float value directly in java
+ uint32_t dataTimestamp;
+ // Specifies where in the constant buffer data gets written to
+ int bufferOffset;
+ // An instance of SgShaderParamData that could be shared by multiple objects
+ rs_allocation data;
+ // How many components of the vector we need to write
+ int float_vecSize;
+} SgShaderParam;
+
+// This represents a texture object
+typedef struct Texture_s {
+ uint32_t type;
+ rs_allocation texture;
+} SgTexture;
+
+static void printName(rs_allocation name) {
+ if (!rsIsObject(name)) {
+ rsDebug("no name", 0);
+ return;
+ }
+
+ rsDebug((const char*)rsGetElementAt(name, 0), 0);
+}
+
+static void printCameraInfo(const SgCamera *cam) {
+ rsDebug("***** Camera information. ptr:", cam);
+ printName(cam->name);
+ const SgTransform *camTransform = (const SgTransform *)rsGetElementAt(cam->transformMatrix, 0);
+ rsDebug("Transform name:", camTransform);
+ printName(camTransform->name);
+
+ rsDebug("Aspect: ", cam->aspect);
+ rsDebug("Near: ", cam->near);
+ rsDebug("Far: ", cam->far);
+ rsDebug("Fov: ", cam->horizontalFOV);
+ rsDebug("Position: ", cam->position);
+ rsDebug("Proj: ", &cam->proj);
+ rsDebug("View: ", &cam->view);
+}
+
+static void printLightInfo(const SgLight *light) {
+ rsDebug("***** Light information. ptr:", light);
+ printName(light->name);
+ const SgTransform *lTransform = (const SgTransform *)rsGetElementAt(light->transformMatrix, 0);
+ rsDebug("Transform name:", lTransform);
+ printName(lTransform->name);
+
+ rsDebug("Position: ", light->position);
+ rsDebug("Color : ", light->color);
+ rsDebug("Intensity: ", light->intensity);
+ rsDebug("Type: ", light->type);
+}
+
+static void getCameraRay(const SgCamera *cam, int screenX, int screenY, float3 *pnt, float3 *vec) {
+ rsDebug("=================================", screenX);
+ rsDebug("Point X", screenX);
+ rsDebug("Point Y", screenY);
+
+ rs_matrix4x4 mvpInv;
+ rsMatrixLoad(&mvpInv, &cam->viewProj);
+ rsMatrixInverse(&mvpInv);
+
+ float width = (float)rsgGetWidth();
+ float height = (float)rsgGetHeight();
+
+ float4 pos = {(float)screenX, height - (float)screenY, 0.0f, 1.0f};
+
+ pos.x /= width;
+ pos.y /= height;
+
+ rsDebug("Pre Norm X", pos.x);
+ rsDebug("Pre Norm Y", pos.y);
+
+ pos.xy = pos.xy * 2.0f - 1.0f;
+
+ rsDebug("Norm X", pos.x);
+ rsDebug("Norm Y", pos.y);
+
+ pos = rsMatrixMultiply(&mvpInv, pos);
+ float oneOverW = 1.0f / pos.w;
+ pos.xyz *= oneOverW;
+
+ rsDebug("World X", pos.x);
+ rsDebug("World Y", pos.y);
+ rsDebug("World Z", pos.z);
+
+ rsDebug("Cam X", cam->position.x);
+ rsDebug("Cam Y", cam->position.y);
+ rsDebug("Cam Z", cam->position.z);
+
+ *vec = normalize(pos.xyz - cam->position.xyz);
+ rsDebug("Vec X", vec->x);
+ rsDebug("Vec Y", vec->y);
+ rsDebug("Vec Z", vec->z);
+ *pnt = cam->position.xyz;
+}
+
+static bool intersect(const SgRenderable *obj, float3 pnt, float3 vec) {
+ // Solving for t^2 + Bt + C = 0
+ float3 originMinusCenter = pnt - obj->worldBoundingSphere.xyz;
+ float B = dot(originMinusCenter, vec) * 2.0f;
+ float C = dot(originMinusCenter, originMinusCenter) -
+ obj->worldBoundingSphere.w * obj->worldBoundingSphere.w;
+
+ float discriminant = B * B - 4.0f * C;
+ if (discriminant < 0.0f) {
+ return false;
+ }
+ discriminant = sqrt(discriminant);
+
+ float t0 = (-B - discriminant) * 0.5f;
+ float t1 = (-B + discriminant) * 0.5f;
+
+ if (t0 > t1) {
+ float temp = t0;
+ t0 = t1;
+ t1 = temp;
+ }
+
+ // The sphere is behind us
+ if (t1 < 0.0f) {
+ return false;
+ }
+ return true;
+}
+
+
+#endif // _TRANSFORM_DEF_
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs
new file mode 100644
index 000000000000..941b5a8c292a
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs
@@ -0,0 +1,127 @@
+// 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.modelviewer)
+
+#include "scenegraph_objects.rsh"
+
+rs_script gTransformScript;
+
+typedef struct {
+ int changed;
+ rs_matrix4x4 *mat;
+} ParentData;
+
+//#define DEBUG_TRANSFORMS
+static void debugTransform(SgTransform *data, const ParentData *parent) {
+ rsDebug("****** <Transform> ******", (int)data);
+ printName(data->name);
+ rsDebug("isDirty", data->isDirty);
+ rsDebug("parent", (int)parent);
+ rsDebug("child ", rsIsObject(data->children));
+
+ // Refresh matrices if dirty
+ if (data->isDirty && rsIsObject(data->components)) {
+ uint32_t numComponenets = rsAllocationGetDimX(data->components);
+ for (int i = 0; i < numComponenets; i ++) {
+ const SgTransformComponent *comp = NULL;
+ comp = (const SgTransformComponent *)rsGetElementAt(data->components, i);
+
+ if (rsIsObject(comp->name)) {
+ rsDebug((const char*)rsGetElementAt(comp->name, 0), comp->value);
+ rsDebug("Type", comp->type);
+ } else {
+ rsDebug("no name", comp->value);
+ rsDebug("Type", comp->type);
+ }
+ }
+ }
+
+ rsDebug("timestamp", data->timestamp);
+ rsDebug("****** </Transform> ******", (int)data);
+}
+
+static void appendTransformation(int type, float4 data, rs_matrix4x4 *mat) {
+ rs_matrix4x4 temp;
+
+ switch (type) {
+ case TRANSFORM_TRANSLATE:
+ rsMatrixLoadTranslate(&temp, data.x, data.y, data.z);
+ break;
+ case TRANSFORM_ROTATE:
+ rsMatrixLoadRotate(&temp, data.w, data.x, data.y, data.z);
+ break;
+ case TRANSFORM_SCALE:
+ rsMatrixLoadScale(&temp, data.x, data.y, data.z);
+ break;
+ }
+ rsMatrixMultiply(mat, &temp);
+}
+
+void root(const rs_allocation *v_in, rs_allocation *v_out, const void *usrData) {
+
+ SgTransform *data = (SgTransform *)rsGetElementAt(*v_in, 0);
+ const ParentData *parent = (const ParentData *)usrData;
+
+#ifdef DEBUG_TRANSFORMS
+ debugTransform(data, parent);
+#endif //DEBUG_TRANSFORMS
+
+ rs_matrix4x4 *localMat = &data->localMat;
+ rs_matrix4x4 *globalMat = &data->globalMat;
+
+ // Refresh matrices if dirty
+ if (data->isDirty && rsIsObject(data->components)) {
+ bool resetLocal = false;
+ uint32_t numComponenets = rsAllocationGetDimX(data->components);
+ for (int i = 0; i < numComponenets; i ++) {
+ if (!resetLocal) {
+ // Reset our local matrix only for component transforms
+ rsMatrixLoadIdentity(localMat);
+ resetLocal = true;
+ }
+ const SgTransformComponent *comp = NULL;
+ comp = (const SgTransformComponent *)rsGetElementAt(data->components, i);
+ appendTransformation(comp->type, comp->value, localMat);
+ }
+ }
+
+ if (parent) {
+ data->isDirty = (parent->changed || data->isDirty) ? 1 : 0;
+ if (data->isDirty) {
+ rsMatrixLoad(globalMat, parent->mat);
+ rsMatrixMultiply(globalMat, localMat);
+ }
+ } else if (data->isDirty) {
+ rsMatrixLoad(globalMat, localMat);
+ }
+
+ ParentData toChild;
+ toChild.changed = 0;
+ toChild.mat = globalMat;
+
+ if (data->isDirty) {
+ toChild.changed = 1;
+ data->timestamp ++;
+ }
+
+ if (rsIsObject(data->children)) {
+ rs_allocation nullAlloc;
+ rsForEach(gTransformScript, data->children, nullAlloc, &toChild, sizeof(toChild));
+ }
+
+ data->isDirty = 0;
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/vertex_params.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/vertex_params.rs
new file mode 100644
index 000000000000..88955a88ffdd
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/vertex_params.rs
@@ -0,0 +1,29 @@
+// Copyright (C) 2012 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.scenegraph)
+
+#include "scenegraph_objects.rsh"
+
+//#define DEBUG_PARAMS
+
+#include "params.rsh"
+
+void root(rs_allocation *v_out, const void *usrData) {
+ SgVertexShader *shader = (SgVertexShader *)rsGetElementAt(*v_out, 0);
+ const SgCamera *camera = (const SgCamera*)usrData;
+ processAllParams(shader->shaderConst, shader->shaderConstParams, camera);
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FileSelector.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FileSelector.java
new file mode 100644
index 000000000000..420e1330d88a
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FileSelector.java
@@ -0,0 +1,110 @@
+/*
+ * 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.testapp;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.util.ArrayList;
+import java.util.List;
+
+import android.app.ListActivity;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+/**
+ * A list view where the last item the user clicked is placed in
+ * the "activated" state, causing its background to highlight.
+ */
+public class FileSelector extends ListActivity {
+
+ File[] mCurrentSubList;
+ File mCurrentFile;
+
+ class DAEFilter implements FileFilter {
+ public boolean accept(File file) {
+ if (file.isDirectory()) {
+ return true;
+ }
+ return file.getName().endsWith(".dae");
+ }
+ }
+
+ private void populateList(File file) {
+
+ mCurrentFile = file;
+ setTitle(mCurrentFile.getAbsolutePath() + "/*.dae");
+ List<String> names = new ArrayList<String>();
+ names.add("..");
+
+ mCurrentSubList = mCurrentFile.listFiles(new DAEFilter());
+
+ if (mCurrentSubList != null) {
+ for (int i = 0; i < mCurrentSubList.length; i ++) {
+ String fileName = mCurrentSubList[i].getName();
+ if (mCurrentSubList[i].isDirectory()) {
+ fileName = "/" + fileName;
+ }
+ names.add(fileName);
+ }
+ }
+
+ // Use the built-in layout for showing a list item with a single
+ // line of text whose background is changes when activated.
+ setListAdapter(new ArrayAdapter<String>(this,
+ android.R.layout.simple_list_item_activated_1, names));
+ getListView().setTextFilterEnabled(true);
+
+ // Tell the list view to show one checked/activated item at a time.
+ getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ populateList(new File("/sdcard/"));
+ }
+
+ @Override
+ protected void onListItemClick(ListView l, View v, int position, long id) {
+ if (position == 0) {
+ File parent = mCurrentFile.getParentFile();
+ if (parent == null) {
+ return;
+ }
+ populateList(parent);
+ return;
+ }
+
+ // the first thing in list is parent directory
+ File selectedFile = mCurrentSubList[position - 1];
+ if (selectedFile.isDirectory()) {
+ populateList(selectedFile);
+ return;
+ }
+
+ Intent resultIntent = new Intent();
+ resultIntent.setData(Uri.fromFile(selectedFile));
+ setResult(RESULT_OK, resultIntent);
+ finish();
+ }
+
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FullscreenBlur.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FullscreenBlur.java
new file mode 100644
index 000000000000..28f916c864c7
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FullscreenBlur.java
@@ -0,0 +1,192 @@
+/*
+ * 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.testapp;
+
+import java.util.ArrayList;
+
+import com.android.scenegraph.*;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.AsyncTask;
+import android.renderscript.*;
+import android.renderscript.Allocation.MipmapControl;
+import android.renderscript.Element.Builder;
+import android.renderscript.Font.Style;
+import android.renderscript.Program.TextureType;
+import android.renderscript.ProgramStore.DepthFunc;
+import android.util.Log;
+
+class FullscreenBlur {
+
+ static TextureRenderTarget sRenderTargetBlur0Color;
+ static TextureRenderTarget sRenderTargetBlur0Depth;
+ static TextureRenderTarget sRenderTargetBlur1Color;
+ static TextureRenderTarget sRenderTargetBlur1Depth;
+ static TextureRenderTarget sRenderTargetBlur2Color;
+ static TextureRenderTarget sRenderTargetBlur2Depth;
+
+ static FragmentShader mPF_BlurH;
+ static FragmentShader mPF_BlurV;
+ static FragmentShader mPF_SelectColor;
+ static FragmentShader mPF_Texture;
+ static VertexShader mPV_Paint;
+ static VertexShader mPV_Blur;
+
+ static int targetWidth;
+ static int targetHeight;
+
+ // This is only used when full screen blur is enabled
+ // Basically, it's the offscreen render targets
+ static void createRenderTargets(RenderScriptGL rs, int w, int h) {
+ targetWidth = w/8;
+ targetHeight = h/8;
+ Type.Builder b = new Type.Builder(rs, Element.RGBA_8888(rs));
+ Type renderType = b.setX(targetWidth).setY(targetHeight).create();
+ int usage = Allocation.USAGE_GRAPHICS_TEXTURE | Allocation.USAGE_GRAPHICS_RENDER_TARGET;
+ sRenderTargetBlur0Color = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));
+ sRenderTargetBlur1Color = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));
+ sRenderTargetBlur2Color = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));
+
+ b = new Type.Builder(rs, Element.createPixel(rs, Element.DataType.UNSIGNED_16,
+ Element.DataKind.PIXEL_DEPTH));
+ renderType = b.setX(targetWidth).setY(targetHeight).create();
+ usage = Allocation.USAGE_GRAPHICS_RENDER_TARGET;
+ sRenderTargetBlur0Depth = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));
+ sRenderTargetBlur1Depth = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));
+ sRenderTargetBlur2Depth = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));
+ }
+
+ static void addOffsets(Renderable quad, float advance) {
+ quad.appendSourceParams(new Float4Param("blurOffset0", - advance * 2.5f));
+ quad.appendSourceParams(new Float4Param("blurOffset1", - advance * 0.5f));
+ quad.appendSourceParams(new Float4Param("blurOffset2", advance * 1.5f));
+ quad.appendSourceParams(new Float4Param("blurOffset3", advance * 3.5f));
+ }
+
+ static RenderPass addPass(Scene scene, Camera cam, TextureRenderTarget color, TextureRenderTarget depth) {
+ RenderPass pass = new RenderPass();
+ pass.setColorTarget(color);
+ pass.setDepthTarget(depth);
+ pass.setShouldClearColor(false);
+ pass.setShouldClearDepth(false);
+ pass.setCamera(cam);
+ scene.appendRenderPass(pass);
+ return pass;
+ }
+
+ static void addBlurPasses(Scene scene, RenderScriptGL rs, Camera cam) {
+ SceneManager sceneManager = SceneManager.getInstance();
+ ArrayList<RenderableBase> allDraw = scene.getRenderables();
+ int numDraw = allDraw.size();
+
+ ProgramRaster cullNone = ProgramRaster.CULL_NONE(rs);
+ ProgramStore blendAdd = SceneManager.BLEND_ADD_DEPTH_NONE(rs);
+ ProgramStore blendNone = ProgramStore.BLEND_NONE_DEPTH_NONE(rs);
+
+ RenderState drawTex = new RenderState(mPV_Blur, mPF_Texture, blendAdd, cullNone);
+ RenderState selectCol = new RenderState(mPV_Blur, mPF_SelectColor, blendNone, cullNone);
+ RenderState hBlur = new RenderState(mPV_Blur, mPF_BlurH, blendNone, cullNone);
+ RenderState vBlur = new RenderState(mPV_Blur, mPF_BlurV, blendNone, cullNone);
+
+ // Renders the scene off screen
+ RenderPass blurSourcePass = addPass(scene, cam,
+ sRenderTargetBlur0Color,
+ sRenderTargetBlur0Depth);
+ blurSourcePass.setClearColor(new Float4(1.0f, 1.0f, 1.0f, 1.0f));
+ blurSourcePass.setShouldClearColor(true);
+ blurSourcePass.setClearDepth(1.0f);
+ blurSourcePass.setShouldClearDepth(true);
+ for (int i = 0; i < numDraw; i ++) {
+ blurSourcePass.appendRenderable((Renderable)allDraw.get(i));
+ }
+
+ // Pass for selecting bright colors
+ RenderPass selectColorPass = addPass(scene, cam,
+ sRenderTargetBlur2Color,
+ sRenderTargetBlur2Depth);
+ Renderable quad = sceneManager.getRenderableQuad("ScreenAlignedQuadS", selectCol);
+ quad.appendSourceParams(new TextureParam("color", sRenderTargetBlur0Color));
+ selectColorPass.appendRenderable(quad);
+
+ // Horizontal blur
+ RenderPass horizontalBlurPass = addPass(scene, cam,
+ sRenderTargetBlur1Color,
+ sRenderTargetBlur1Depth);
+ quad = sceneManager.getRenderableQuad("ScreenAlignedQuadH", hBlur);
+ quad.appendSourceParams(new TextureParam("color", sRenderTargetBlur2Color));
+ addOffsets(quad, 1.0f / (float)targetWidth);
+ horizontalBlurPass.appendRenderable(quad);
+
+ // Vertical Blur
+ RenderPass verticalBlurPass = addPass(scene, cam,
+ sRenderTargetBlur2Color,
+ sRenderTargetBlur2Depth);
+ quad = sceneManager.getRenderableQuad("ScreenAlignedQuadV", vBlur);
+ quad.appendSourceParams(new TextureParam("color", sRenderTargetBlur1Color));
+ addOffsets(quad, 1.0f / (float)targetHeight);
+ verticalBlurPass.appendRenderable(quad);
+ }
+
+ // Additively renders the blurred colors on top of the scene
+ static void addCompositePass(Scene scene, RenderScriptGL rs, Camera cam) {
+ SceneManager sceneManager = SceneManager.getInstance();
+ RenderState drawTex = new RenderState(mPV_Blur, mPF_Texture,
+ SceneManager.BLEND_ADD_DEPTH_NONE(rs),
+ ProgramRaster.CULL_NONE(rs));
+
+ RenderPass compositePass = addPass(scene, cam, null, null);
+ Renderable quad = sceneManager.getRenderableQuad("ScreenAlignedQuadComposite", drawTex);
+ quad.appendSourceParams(new TextureParam("color", sRenderTargetBlur2Color));
+ compositePass.appendRenderable(quad);
+ }
+
+ static private FragmentShader getShader(Resources res, RenderScriptGL rs,
+ int resID, Type constants) {
+ FragmentShader.Builder fb = new FragmentShader.Builder(rs);
+ fb.setShader(res, resID);
+ fb.addTexture(TextureType.TEXTURE_2D, "color");
+ if (constants != null) {
+ fb.setObjectConst(constants);
+ }
+ FragmentShader prog = fb.create();
+ prog.getProgram().bindSampler(Sampler.CLAMP_LINEAR(rs), 0);
+ return prog;
+ }
+
+ static void initShaders(Resources res, RenderScriptGL rs) {
+ ScriptField_BlurOffsets blurConst = new ScriptField_BlurOffsets(rs, 1);
+ VertexShader.Builder vb = new VertexShader.Builder(rs);
+ vb.addInput(ScriptField_VertexShaderInputs.createElement(rs));
+ vb.setShader(res, R.raw.blur_vertex);
+ mPV_Blur = vb.create();
+
+ mPF_Texture = getShader(res, rs, R.raw.texture, null);
+ mPF_Texture.getProgram().bindSampler(Sampler.WRAP_LINEAR_MIP_LINEAR(rs), 0);
+ mPF_BlurH = getShader(res, rs, R.raw.blur_h, blurConst.getAllocation().getType());
+ mPF_BlurV = getShader(res, rs, R.raw.blur_v, blurConst.getAllocation().getType());
+ mPF_SelectColor = getShader(res, rs, R.raw.select_color, null);
+ }
+
+}
+
+
+
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestApp.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestApp.java
new file mode 100644
index 000000000000..385a7ab37d11
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestApp.java
@@ -0,0 +1,115 @@
+/*
+ * 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.testapp;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+
+import android.app.Activity;
+import android.content.res.Configuration;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings.System;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.ListView;
+import android.view.MenuInflater;
+import android.view.Window;
+import android.net.Uri;
+
+import java.lang.Runtime;
+
+public class TestApp extends Activity {
+
+ private TestAppView mView;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ // Create our Preview view and set it as the content of our
+ // Activity
+ mView = new TestAppView(this);
+ setContentView(mView);
+ }
+
+ @Override
+ protected void onResume() {
+ // Ideally a game should implement onResume() and onPause()
+ // to take appropriate action when the activity looses focus
+ super.onResume();
+ mView.resume();
+ }
+
+ @Override
+ protected void onPause() {
+ // Ideally a game should implement onResume() and onPause()
+ // to take appropriate action when the activity looses focus
+ 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.load_model:
+ loadModel();
+ return true;
+ case R.id.use_blur:
+ mView.mRender.toggleBlur();
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ private static final int FIND_DAE_MODEL = 10;
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (resultCode == RESULT_OK) {
+ if (requestCode == FIND_DAE_MODEL) {
+ Uri selectedImageUri = data.getData();
+ Log.e("Selected Path: ", selectedImageUri.getPath());
+ mView.mRender.loadModel(selectedImageUri.getPath());
+ }
+ }
+ }
+
+ public void loadModel() {
+ Intent intent = new Intent();
+ intent.setAction(Intent.ACTION_PICK);
+ intent.setClassName("com.android.testapp",
+ "com.android.testapp.FileSelector");
+ startActivityForResult(intent, FIND_DAE_MODEL);
+ }
+
+}
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppLoadingScreen.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppLoadingScreen.java
new file mode 100644
index 000000000000..5bd8f0bccf16
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppLoadingScreen.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2012 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.testapp;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+import com.android.scenegraph.SceneManager;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.AsyncTask;
+import android.renderscript.*;
+import android.renderscript.Allocation.MipmapControl;
+import android.renderscript.Element.Builder;
+import android.renderscript.Font.Style;
+import android.renderscript.Program.TextureType;
+import android.renderscript.ProgramStore.DepthFunc;
+import android.util.Log;
+
+// This is where the scenegraph and the rendered objects are initialized and used
+public class TestAppLoadingScreen {
+
+ private static String TAG = "TestAppLoadingScreen";
+
+ private Resources mRes;
+ private RenderScriptGL mRS;
+ private ScriptC_test_app mScript;
+
+ public TestAppLoadingScreen(RenderScriptGL rs, Resources res) {
+ mRS = rs;
+ mRes = res;
+ // Shows the loading screen with some text
+ renderLoading();
+ // Adds a little 3D bugdroid model to the laoding screen asynchronously.
+ new LoadingScreenLoaderTask().execute();
+ }
+
+ public void showLoadingScreen(boolean show) {
+ if (show) {
+ mRS.bindRootScript(mScript);
+ } else {
+ mRS.bindRootScript(SceneManager.getInstance().getRenderLoop());
+ }
+ }
+
+ // The loading screen has some elements that shouldn't be loaded on the UI thread
+ private class LoadingScreenLoaderTask extends AsyncTask<String, Void, Boolean> {
+ Allocation robotTex;
+ Mesh robotMesh;
+ protected Boolean doInBackground(String... names) {
+ long start = System.currentTimeMillis();
+ robotTex = Allocation.createFromBitmapResource(mRS, mRes, R.drawable.robot,
+ MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE,
+ Allocation.USAGE_GRAPHICS_TEXTURE);
+
+ FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.robot);
+ FileA3D.IndexEntry entry = model.getIndexEntry(0);
+ if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) {
+ robotMesh = entry.getMesh();
+ }
+
+ mScript.set_gPFSBackground(ProgramStore.BLEND_NONE_DEPTH_TEST(mRS));
+
+ ProgramFragmentFixedFunction.Builder b = new ProgramFragmentFixedFunction.Builder(mRS);
+ b.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
+ ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
+ ProgramFragment pfDefault = b.create();
+ pfDefault.bindSampler(Sampler.CLAMP_LINEAR(mRS), 0);
+ mScript.set_gPFBackground(pfDefault);
+
+ ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS);
+ ProgramVertexFixedFunction pvDefault = pvb.create();
+ ProgramVertexFixedFunction.Constants va = new ProgramVertexFixedFunction.Constants(mRS);
+ ((ProgramVertexFixedFunction)pvDefault).bindConstants(va);
+ mScript.set_gPVBackground(pvDefault);
+
+ long end = System.currentTimeMillis();
+ Log.v("TIMER", "Loading load time: " + (end - start));
+ return new Boolean(true);
+ }
+
+ protected void onPostExecute(Boolean result) {
+ mScript.set_gRobotTex(robotTex);
+ mScript.set_gRobotMesh(robotMesh);
+ }
+ }
+
+ // Creates a simple script to show a loding screen until everything is initialized
+ // Could also be used to do some custom renderscript work before handing things over
+ // to the scenegraph
+ void renderLoading() {
+ mScript = new ScriptC_test_app(mRS, mRes, R.raw.test_app);
+ mRS.bindRootScript(mScript);
+ }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppRS.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppRS.java
new file mode 100644
index 000000000000..7bf781287f73
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppRS.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2011-2012 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.testapp;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+import com.android.scenegraph.*;
+import com.android.scenegraph.SceneManager.SceneLoadedCallback;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.AsyncTask;
+import android.renderscript.*;
+import android.renderscript.Program.TextureType;
+import android.util.Log;
+
+// This is where the scenegraph and the rendered objects are initialized and used
+public class TestAppRS {
+
+ private static String modelName = "orientation_test.dae";
+ private static String TAG = "TestAppRS";
+ private static String mFilePath = "";
+
+ int mWidth;
+ int mHeight;
+
+ boolean mUseBlur;
+
+ TestAppLoadingScreen mLoadingScreen;
+
+ // Used to asynchronously load scene elements like meshes and transform hierarchies
+ SceneLoadedCallback mLoadedCallback = new SceneLoadedCallback() {
+ public void run() {
+ prepareToRender(mLoadedScene);
+ }
+ };
+
+ // Top level class that initializes all the elements needed to use the scene graph
+ SceneManager mSceneManager;
+
+ // Used to move the camera around in the 3D world
+ TouchHandler mTouchHandler;
+
+ private Resources mRes;
+ private RenderScriptGL mRS;
+
+ // Shaders
+ private FragmentShader mPaintF;
+ private FragmentShader mLightsF;
+ private FragmentShader mAluminumF;
+ private FragmentShader mPlasticF;
+ private FragmentShader mDiffuseF;
+ private FragmentShader mTextureF;
+ private VertexShader mGenericV;
+
+ Scene mActiveScene;
+
+ // This is a part of the test app, it's used to tests multiple render passes and is toggled
+ // on and off in the menu, off by default
+ void toggleBlur() {
+ mUseBlur = !mUseBlur;
+
+ mActiveScene.clearRenderPasses();
+ initRenderPasses();
+ mActiveScene.initRenderPassRS(mRS, mSceneManager);
+
+ // This is just a hardcoded object in the scene that gets turned on and off for the demo
+ // to make things look a bit better. This could be deleted in the cleanup
+ Renderable plane = (Renderable)mActiveScene.getRenderableByName("pPlaneShape1");
+ if (plane != null) {
+ plane.setVisible(!mUseBlur);
+ }
+ }
+
+ public void init(RenderScriptGL rs, Resources res, int width, int height) {
+ mUseBlur = false;
+ mRS = rs;
+ mRes = res;
+ mWidth = width;
+ mHeight = height;
+
+ mTouchHandler = new TouchHandler();
+
+ mSceneManager = SceneManager.getInstance();
+ // Initializes all the RS specific scenegraph elements
+ mSceneManager.initRS(mRS, mRes, mWidth, mHeight);
+
+ mLoadingScreen = new TestAppLoadingScreen(mRS, mRes);
+
+ // Initi renderscript stuff specific to the app. This will need to be abstracted out later.
+ FullscreenBlur.createRenderTargets(mRS, mWidth, mHeight);
+ initPaintShaders();
+
+ // Load a scene to render
+ mSceneManager.loadModel(mFilePath + modelName, mLoadedCallback);
+ }
+
+ // When a new model file is selected from the UI, this function gets called to init everything
+ void loadModel(String path) {
+ mLoadingScreen.showLoadingScreen(true);
+ mActiveScene.destroyRS();
+ mSceneManager.loadModel(path, mLoadedCallback);
+ }
+
+ public void onActionDown(float x, float y) {
+ mTouchHandler.onActionDown(x, y);
+ }
+
+ public void onActionScale(float scale) {
+ mTouchHandler.onActionScale(scale);
+ }
+
+ public void onActionMove(float x, float y) {
+ mTouchHandler.onActionMove(x, y);
+ }
+
+ FragmentShader createFromResource(int id, boolean addCubemap, Type constType) {
+ FragmentShader.Builder fb = new FragmentShader.Builder(mRS);
+ fb.setShaderConst(constType);
+ fb.setShader(mRes, id);
+ fb.addTexture(TextureType.TEXTURE_2D, "diffuse");
+ if (addCubemap) {
+ fb.addShaderTexture(TextureType.TEXTURE_CUBE, "reflection");
+ }
+ FragmentShader pf = fb.create();
+ pf.getProgram().bindSampler(Sampler.WRAP_LINEAR_MIP_LINEAR(mRS), 0);
+ if (addCubemap) {
+ pf.getProgram().bindSampler(Sampler.CLAMP_LINEAR_MIP_LINEAR(mRS), 1);
+ }
+ return pf;
+ }
+
+ private void initPaintShaders() {
+ ScriptField_ModelParams objConst = new ScriptField_ModelParams(mRS, 1);
+ ScriptField_ViewProjParams shaderConst = new ScriptField_ViewProjParams(mRS, 1);
+
+ VertexShader.Builder vb = new VertexShader.Builder(mRS);
+ vb.addInput(ScriptField_VertexShaderInputs.createElement(mRS));
+ vb.setShader(mRes, R.raw.shader2v);
+ vb.setObjectConst(objConst.getAllocation().getType());
+ vb.setShaderConst(shaderConst.getAllocation().getType());
+ mGenericV = vb.create();
+
+ ScriptField_CameraParams fsConst = new ScriptField_CameraParams(mRS, 1);
+ ScriptField_LightParams fsConst2 = new ScriptField_LightParams(mRS, 1);
+
+ mPaintF = createFromResource(R.raw.paintf, true, fsConst.getAllocation().getType());
+ // Assign a reflection map
+ TextureCube envCube = new TextureCube("sdcard/scenegraph/", "cube_env.png");
+ mPaintF.appendSourceParams(new TextureParam("reflection", envCube));
+
+ mAluminumF = createFromResource(R.raw.metal, true, fsConst.getAllocation().getType());
+ TextureCube diffCube = new TextureCube("sdcard/scenegraph/", "cube_spec.png");
+ mAluminumF.appendSourceParams(new TextureParam("reflection", diffCube));
+
+ mPlasticF = createFromResource(R.raw.plastic, false, fsConst.getAllocation().getType());
+ mDiffuseF = createFromResource(R.raw.diffuse, false, fsConst.getAllocation().getType());
+ mTextureF = createFromResource(R.raw.texture, false, fsConst.getAllocation().getType());
+
+ FragmentShader.Builder fb = new FragmentShader.Builder(mRS);
+ fb.setObjectConst(fsConst2.getAllocation().getType());
+ fb.setShader(mRes, R.raw.plastic_lights);
+ mLightsF = fb.create();
+
+ FullscreenBlur.initShaders(mRes, mRS);
+ }
+
+ void initRenderPasses() {
+ ArrayList<RenderableBase> allDraw = mActiveScene.getRenderables();
+ int numDraw = allDraw.size();
+
+ if (mUseBlur) {
+ FullscreenBlur.addBlurPasses(mActiveScene, mRS, mTouchHandler.getCamera());
+ }
+
+ RenderPass mainPass = new RenderPass();
+ mainPass.setClearColor(new Float4(1.0f, 1.0f, 1.0f, 1.0f));
+ mainPass.setShouldClearColor(true);
+ mainPass.setClearDepth(1.0f);
+ mainPass.setShouldClearDepth(true);
+ mainPass.setCamera(mTouchHandler.getCamera());
+ for (int i = 0; i < numDraw; i ++) {
+ mainPass.appendRenderable((Renderable)allDraw.get(i));
+ }
+ mActiveScene.appendRenderPass(mainPass);
+
+ if (mUseBlur) {
+ FullscreenBlur.addCompositePass(mActiveScene, mRS, mTouchHandler.getCamera());
+ }
+ }
+
+ private void addShadersToScene() {
+ mActiveScene.appendShader(mPaintF);
+ mActiveScene.appendShader(mLightsF);
+ mActiveScene.appendShader(mAluminumF);
+ mActiveScene.appendShader(mPlasticF);
+ mActiveScene.appendShader(mDiffuseF);
+ mActiveScene.appendShader(mTextureF);
+ mActiveScene.appendShader(mGenericV);
+ }
+
+ public void prepareToRender(Scene s) {
+ mSceneManager.setActiveScene(s);
+ mActiveScene = s;
+ mTouchHandler.init(mActiveScene);
+ addShadersToScene();
+ RenderState plastic = new RenderState(mGenericV, mPlasticF, null, null);
+ RenderState diffuse = new RenderState(mGenericV, mDiffuseF, null, null);
+ RenderState paint = new RenderState(mGenericV, mPaintF, null, null);
+ RenderState aluminum = new RenderState(mGenericV, mAluminumF, null, null);
+ RenderState lights = new RenderState(mGenericV, mLightsF, null, null);
+ RenderState glassTransp = new RenderState(mGenericV, mPaintF,
+ ProgramStore.BLEND_ALPHA_DEPTH_TEST(mRS), null);
+
+ initRenderPasses();
+
+ mActiveScene.assignRenderState(plastic);
+
+ mActiveScene.assignRenderStateToMaterial(diffuse, "lambert2$");
+
+ mActiveScene.assignRenderStateToMaterial(paint, "^Paint");
+ mActiveScene.assignRenderStateToMaterial(paint, "^Carbon");
+ mActiveScene.assignRenderStateToMaterial(paint, "^Glass");
+ mActiveScene.assignRenderStateToMaterial(paint, "^MainGlass");
+
+ mActiveScene.assignRenderStateToMaterial(aluminum, "^Metal");
+ mActiveScene.assignRenderStateToMaterial(aluminum, "^Brake");
+
+ mActiveScene.assignRenderStateToMaterial(glassTransp, "^GlassLight");
+
+ mActiveScene.assignRenderStateToMaterial(lights, "^LightBlinn");
+
+ Renderable plane = (Renderable)mActiveScene.getRenderableByName("pPlaneShape1");
+ if (plane != null) {
+ RenderState texState = new RenderState(mGenericV, mTextureF, null, null);
+ plane.setRenderState(texState);
+ plane.setVisible(!mUseBlur);
+ }
+
+ long start = System.currentTimeMillis();
+ mActiveScene.initRS();
+ long end = System.currentTimeMillis();
+ Log.v("TIMER", "Scene init time: " + (end - start));
+
+ mLoadingScreen.showLoadingScreen(false);
+ }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppView.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppView.java
new file mode 100644
index 000000000000..687f35b3ec7d
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppView.java
@@ -0,0 +1,152 @@
+/*
+ * 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.testapp;
+
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.concurrent.Semaphore;
+
+import android.renderscript.RSSurfaceView;
+import android.renderscript.RenderScript;
+import android.renderscript.RenderScriptGL;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.ScaleGestureDetector;
+
+public class TestAppView extends RSSurfaceView {
+
+ public TestAppView(Context context) {
+ super(context);
+ mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
+ }
+
+ private RenderScriptGL mRS;
+ TestAppRS mRender;
+
+ private ScaleGestureDetector mScaleDetector;
+ private static final int INVALID_POINTER_ID = -1;
+ private int mActivePointerId = INVALID_POINTER_ID;
+
+ public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
+ super.surfaceChanged(holder, format, w, h);
+ if (mRS == null) {
+ RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
+ sc.setDepth(16, 24);
+ mRS = createRenderScriptGL(sc);
+ mRS.setSurface(holder, w, h);
+ mRender = new TestAppRS();
+ mRender.init(mRS, getResources(), w, h);
+ }
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ if (mRS != null) {
+ mRender = null;
+ mRS = null;
+ destroyRenderScriptGL();
+ }
+ }
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event)
+ {
+ // break point at here
+ // this method doesn't work when 'extends View' include 'extends ScrollView'.
+ return super.onKeyDown(keyCode, event);
+ }
+
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ mScaleDetector.onTouchEvent(ev);
+
+ boolean ret = false;
+ float x = ev.getX();
+ float y = ev.getY();
+
+ final int action = ev.getAction();
+
+ switch (action & MotionEvent.ACTION_MASK) {
+ case MotionEvent.ACTION_DOWN: {
+ mRender.onActionDown(x, y);
+ mActivePointerId = ev.getPointerId(0);
+ ret = true;
+ break;
+ }
+ case MotionEvent.ACTION_MOVE: {
+ if (!mScaleDetector.isInProgress()) {
+ mRender.onActionMove(x, y);
+ }
+ mRender.onActionDown(x, y);
+ ret = true;
+ break;
+ }
+
+ case MotionEvent.ACTION_UP: {
+ mActivePointerId = INVALID_POINTER_ID;
+ break;
+ }
+
+ case MotionEvent.ACTION_CANCEL: {
+ mActivePointerId = INVALID_POINTER_ID;
+ break;
+ }
+
+ case MotionEvent.ACTION_POINTER_UP: {
+ final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
+ >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+ final int pointerId = ev.getPointerId(pointerIndex);
+ if (pointerId == mActivePointerId) {
+ // This was our active pointer going up. Choose a new
+ // active pointer and adjust accordingly.
+ final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
+ x = ev.getX(newPointerIndex);
+ y = ev.getY(newPointerIndex);
+ mRender.onActionDown(x, y);
+ mActivePointerId = ev.getPointerId(newPointerIndex);
+ }
+ break;
+ }
+ }
+
+ return ret;
+ }
+
+ private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
+ @Override
+ public boolean onScale(ScaleGestureDetector detector) {
+ mRender.onActionScale(detector.getScaleFactor());
+ return true;
+ }
+ }
+}
+
+
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TouchHandler.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TouchHandler.java
new file mode 100644
index 000000000000..d8e48e80161a
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TouchHandler.java
@@ -0,0 +1,114 @@
+/*
+ * 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.testapp;
+
+import android.util.Log;
+import android.renderscript.Float3;
+import com.android.scenegraph.*;
+import com.android.scenegraph.CompoundTransform.RotateComponent;
+import com.android.scenegraph.CompoundTransform.TranslateComponent;
+
+public class TouchHandler {
+ private static String TAG = "TouchHandler";
+
+ float mLastX;
+ float mLastY;
+
+ float mRotateXValue;
+ float mRotateYValue;
+ Float3 mDistValue;
+ Float3 mPosValue;
+
+ CompoundTransform mCameraRig;
+ RotateComponent mRotateX;
+ RotateComponent mRotateY;
+ TranslateComponent mDist;
+ TranslateComponent mPosition;
+ Camera mCamera;
+
+ public void init(Scene scene) {
+ // Some initial values for camera position
+ mRotateXValue = -20;
+ mRotateYValue = 45;
+ mDistValue = new Float3(0, 0, 45);
+ mPosValue = new Float3(0, 4, 0);
+
+ mRotateX = new RotateComponent("RotateX", new Float3(1, 0, 0), mRotateXValue);
+ mRotateY = new RotateComponent("RotateY", new Float3(0, 1, 0), mRotateYValue);
+ mDist = new TranslateComponent("Distance", mDistValue);
+ mPosition = new TranslateComponent("Distance", mPosValue);
+
+ // Make a camera transform we can manipulate
+ mCameraRig = new CompoundTransform();
+ mCameraRig.setName("CameraRig");
+ mCameraRig.addComponent(mPosition);
+ mCameraRig.addComponent(mRotateY);
+ mCameraRig.addComponent(mRotateX);
+ mCameraRig.addComponent(mDist);
+ scene.appendTransform(mCameraRig);
+ mCamera = new Camera();
+ mCamera.setTransform(mCameraRig);
+ scene.appendCamera(mCamera);
+ }
+
+ public Camera getCamera() {
+ return mCamera;
+ }
+
+ public void onActionDown(float x, float y) {
+ mLastX = x;
+ mLastY = y;
+ }
+
+ public void onActionScale(float scale) {
+ if (mDist == null) {
+ return;
+ }
+ mDistValue.z *= 1.0f / scale;
+ mDistValue.z = Math.max(10.0f, Math.min(mDistValue.z, 150.0f));
+ mDist.setValue(mDistValue);
+ }
+
+ public void onActionMove(float x, float y) {
+ if (mRotateX == null) {
+ return;
+ }
+
+ float dx = mLastX - x;
+ float dy = mLastY - y;
+
+ if (Math.abs(dy) <= 2.0f) {
+ dy = 0.0f;
+ }
+ if (Math.abs(dx) <= 2.0f) {
+ dx = 0.0f;
+ }
+
+ mRotateYValue += dx * 0.25f;
+ mRotateYValue %= 360.0f;
+
+ mRotateXValue += dy * 0.25f;
+ mRotateXValue = Math.max(mRotateXValue , -80.0f);
+ mRotateXValue = Math.min(mRotateXValue , 0.0f);
+
+ mRotateX.setAngle(mRotateXValue);
+ mRotateY.setAngle(mRotateYValue);
+
+ mLastX = x;
+ mLastY = y;
+ }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs
new file mode 100644
index 000000000000..997a1a748628
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs
@@ -0,0 +1,86 @@
+// 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.testapp)
+
+#include "rs_graphics.rsh"
+#include "test_app.rsh"
+
+// Making sure these get reflected
+FBlurOffsets *blurExport;
+VShaderInputs *iExport;
+FShaderParams *fConst;
+FShaderLightParams *fConts2;
+VSParams *vConst2;
+VObjectParams *vConst3;
+
+rs_program_vertex gPVBackground;
+rs_program_fragment gPFBackground;
+
+rs_allocation gRobotTex;
+rs_mesh gRobotMesh;
+
+rs_program_store gPFSBackground;
+
+float gRotate;
+
+void init() {
+ gRotate = 0.0f;
+}
+
+static int pos = 50;
+static float gRotateY = 120.0f;
+static float3 gLookAt = 0;
+static float gZoom = 50.0f;
+static void displayLoading() {
+ if (rsIsObject(gRobotTex) && rsIsObject(gRobotMesh)) {
+ rsgBindProgramVertex(gPVBackground);
+ rs_matrix4x4 proj;
+ float aspect = (float)rsgGetWidth() / (float)rsgGetHeight();
+ rsMatrixLoadPerspective(&proj, 30.0f, aspect, 1.0f, 100.0f);
+ rsgProgramVertexLoadProjectionMatrix(&proj);
+
+ rsgBindProgramFragment(gPFBackground);
+ rsgBindProgramStore(gPFSBackground);
+ rsgBindTexture(gPFBackground, 0, gRobotTex);
+
+ rs_matrix4x4 matrix;
+ rsMatrixLoadIdentity(&matrix);
+ // Position our models on the screen
+ gRotateY += rsGetDt()*100;
+ rsMatrixTranslate(&matrix, 0, 0, -gZoom);
+ rsMatrixRotate(&matrix, 20.0f, 1.0f, 0.0f, 0.0f);
+ rsMatrixRotate(&matrix, gRotateY, 0.0f, 1.0f, 0.0f);
+ rsMatrixScale(&matrix, 0.2f, 0.2f, 0.2f);
+ rsgProgramVertexLoadModelMatrix(&matrix);
+ rsgDrawMesh(gRobotMesh);
+ }
+
+ uint width = rsgGetWidth();
+ uint height = rsgGetHeight();
+ int left = 0, right = 0, top = 0, bottom = 0;
+ const char* text = "Initializing...";
+ rsgMeasureText(text, &left, &right, &top, &bottom);
+ int centeredPos = width / 2 - (right - left) / 2;
+ rsgDrawText(text, centeredPos, height / 2 + height / 10);
+}
+
+int root(void) {
+ rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+ rsgClearDepth(1.0f);
+ displayLoading();
+ return 30;
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rsh b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rsh
new file mode 100644
index 000000000000..5fbcbb2ebb69
--- /dev/null
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rsh
@@ -0,0 +1,52 @@
+// Copyright (C) 2012 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.testapp)
+
+// Helpers
+typedef struct ViewProjParams {
+ rs_matrix4x4 viewProj;
+} VSParams;
+
+typedef struct ModelParams {
+ rs_matrix4x4 model;
+} VObjectParams;
+
+typedef struct CameraParams {
+ float4 cameraPos;
+} FShaderParams;
+
+typedef struct LightParams {
+ float4 lightPos_0;
+ float4 lightColor_0;
+ float4 lightPos_1;
+ float4 lightColor_1;
+ float4 cameraPos;
+ float4 diffuse;
+} FShaderLightParams;
+
+typedef struct BlurOffsets {
+ float blurOffset0;
+ float blurOffset1;
+ float blurOffset2;
+ float blurOffset3;
+} FBlurOffsets;
+
+typedef struct VertexShaderInputs {
+ float4 position;
+ float3 normal;
+ float2 texture0;
+} VShaderInputs;
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
index 22936786c9ac..c7bd80994603 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/RSTestCore.java
@@ -64,9 +64,15 @@ public class RSTestCore {
unitTests = new ArrayList<UnitTest>();
+ unitTests.add(new UT_mesh(this, mRes, mCtx));
+ unitTests.add(new UT_element(this, mRes, mCtx));
+ unitTests.add(new UT_sampler(this, mRes, mCtx));
+ unitTests.add(new UT_program_store(this, mRes, mCtx));
+ unitTests.add(new UT_program_raster(this, mRes, mCtx));
unitTests.add(new UT_primitives(this, mRes, mCtx));
unitTests.add(new UT_constant(this, mRes, mCtx));
unitTests.add(new UT_vector(this, mRes, mCtx));
+ unitTests.add(new UT_array_init(this, mRes, mCtx));
unitTests.add(new UT_rsdebug(this, mRes, mCtx));
unitTests.add(new UT_rstime(this, mRes, mCtx));
unitTests.add(new UT_rstypes(this, mRes, mCtx));
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_array_init.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_array_init.java
new file mode 100644
index 000000000000..b98b7533dd48
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_array_init.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2012 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.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+
+public class UT_array_init extends UnitTest {
+ private Resources mRes;
+
+ protected UT_array_init(RSTestCore rstc, Resources res, Context ctx) {
+ super(rstc, "Array Init", ctx);
+ mRes = res;
+ }
+
+ private void checkInit(ScriptC_array_init s) {
+ float[] fa = s.get_fa();
+ _RS_ASSERT("fa[0] == 1.0", fa[0] == 1.0);
+ _RS_ASSERT("fa[1] == 9.9999f", fa[1] == 9.9999f);
+ _RS_ASSERT("fa[2] == 0", fa[2] == 0);
+ _RS_ASSERT("fa[3] == 0", fa[3] == 0);
+ _RS_ASSERT("fa.length == 4", fa.length == 4);
+
+ double[] da = s.get_da();
+ _RS_ASSERT("da[0] == 7.0", da[0] == 7.0);
+ _RS_ASSERT("da[1] == 8.88888", da[1] == 8.88888);
+ _RS_ASSERT("da.length == 2", da.length == 2);
+
+ byte[] ca = s.get_ca();
+ _RS_ASSERT("ca[0] == 'a'", ca[0] == 'a');
+ _RS_ASSERT("ca[1] == 7", ca[1] == 7);
+ _RS_ASSERT("ca[2] == 'b'", ca[2] == 'b');
+ _RS_ASSERT("ca[3] == 'c'", ca[3] == 'c');
+ _RS_ASSERT("ca.length == 4", ca.length == 4);
+
+ short[] sa = s.get_sa();
+ _RS_ASSERT("sa[0] == 1", sa[0] == 1);
+ _RS_ASSERT("sa[1] == 1", sa[1] == 1);
+ _RS_ASSERT("sa[2] == 2", sa[2] == 2);
+ _RS_ASSERT("sa[3] == 3", sa[3] == 3);
+ _RS_ASSERT("sa.length == 4", sa.length == 4);
+
+ int[] ia = s.get_ia();
+ _RS_ASSERT("ia[0] == 5", ia[0] == 5);
+ _RS_ASSERT("ia[1] == 8", ia[1] == 8);
+ _RS_ASSERT("ia[2] == 0", ia[2] == 0);
+ _RS_ASSERT("ia[3] == 0", ia[3] == 0);
+ _RS_ASSERT("ia.length == 4", ia.length == 4);
+
+ long[] la = s.get_la();
+ _RS_ASSERT("la[0] == 13", la[0] == 13);
+ _RS_ASSERT("la[1] == 21", la[1] == 21);
+ _RS_ASSERT("la.length == 4", la.length == 2);
+
+ long[] lla = s.get_lla();
+ _RS_ASSERT("lla[0] == 34", lla[0] == 34);
+ _RS_ASSERT("lla[1] == 0", lla[1] == 0);
+ _RS_ASSERT("lla[2] == 0", lla[2] == 0);
+ _RS_ASSERT("lla[3] == 0", lla[3] == 0);
+ _RS_ASSERT("lla.length == 4", lla.length == 4);
+
+ boolean[] ba = s.get_ba();
+ _RS_ASSERT("ba[0] == true", ba[0] == true);
+ _RS_ASSERT("ba[1] == false", ba[1] == false);
+ _RS_ASSERT("ba[2] == false", ba[2] == false);
+ _RS_ASSERT("ba.length == 3", ba.length == 3);
+ }
+
+ public void run() {
+ RenderScript pRS = RenderScript.create(mCtx);
+ ScriptC_array_init s = new ScriptC_array_init(pRS, mRes, R.raw.array_init);
+ pRS.setMessageHandler(mRsMessage);
+ checkInit(s);
+ s.invoke_array_init_test();
+ pRS.finish();
+ waitForMessage();
+ pRS.destroy();
+ passTest();
+ }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_element.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_element.java
new file mode 100644
index 000000000000..3e2a2ca2195e
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_element.java
@@ -0,0 +1,132 @@
+/*
+ * 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.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.Element.*;
+import android.renderscript.Element.DataKind.*;
+import android.renderscript.Element.DataType.*;
+
+public class UT_element extends UnitTest {
+ private Resources mRes;
+
+ Element simpleElem;
+ Element complexElem;
+
+ final String subElemNames[] = {
+ "subElem0",
+ "subElem1",
+ "subElem2",
+ "arrayElem0",
+ "arrayElem1",
+ "subElem3",
+ "subElem4",
+ "subElem5",
+ "subElem6",
+ "subElem_7",
+ };
+
+ final int subElemArraySizes[] = {
+ 1,
+ 1,
+ 1,
+ 2,
+ 5,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ };
+
+ final int subElemOffsets[] = {
+ 0,
+ 4,
+ 8,
+ 12,
+ 20,
+ 40,
+ 44,
+ 48,
+ 64,
+ 80,
+ };
+
+ protected UT_element(RSTestCore rstc, Resources res, Context ctx) {
+ super(rstc, "Element", ctx);
+ mRes = res;
+ }
+
+ private void initializeGlobals(RenderScript RS, ScriptC_element s) {
+ simpleElem = Element.F32_3(RS);
+ complexElem = ScriptField_ComplexStruct.createElement(RS);
+ s.set_simpleElem(simpleElem);
+ s.set_complexElem(complexElem);
+
+ ScriptField_ComplexStruct data = new ScriptField_ComplexStruct(RS, 1);
+ s.bind_complexStruct(data);
+ }
+
+ private void testScriptSide(RenderScript pRS) {
+ ScriptC_element s = new ScriptC_element(pRS, mRes, R.raw.element);
+ pRS.setMessageHandler(mRsMessage);
+ initializeGlobals(pRS, s);
+ s.invoke_element_test();
+ pRS.finish();
+ waitForMessage();
+ }
+
+ private void testJavaSide(RenderScript RS) {
+
+ int subElemCount = simpleElem.getSubElementCount();
+ _RS_ASSERT("subElemCount == 0", subElemCount == 0);
+ _RS_ASSERT("simpleElem.getDataKind() == USER",
+ simpleElem.getDataKind() == DataKind.USER);
+ _RS_ASSERT("simpleElem.getDataType() == FLOAT_32",
+ simpleElem.getDataType() == DataType.FLOAT_32);
+
+ subElemCount = complexElem.getSubElementCount();
+ _RS_ASSERT("subElemCount == 10", subElemCount == 10);
+ _RS_ASSERT("complexElem.getDataKind() == USER",
+ complexElem.getDataKind() == DataKind.USER);
+ _RS_ASSERT("complexElemsimpleElem.getDataType() == NONE",
+ complexElem.getDataType() == DataType.NONE);
+ _RS_ASSERT("complexElem.getSizeBytes() == ScriptField_ComplexStruct.Item.sizeof",
+ complexElem.getSizeBytes() == ScriptField_ComplexStruct.Item.sizeof);
+
+ for (int i = 0; i < subElemCount; i ++) {
+ _RS_ASSERT("complexElem.getSubElement(i) != null",
+ complexElem.getSubElement(i) != null);
+ _RS_ASSERT("complexElem.getSubElementName(i).equals(subElemNames[i])",
+ complexElem.getSubElementName(i).equals(subElemNames[i]));
+ _RS_ASSERT("complexElem.getSubElementArraySize(i) == subElemArraySizes[i]",
+ complexElem.getSubElementArraySize(i) == subElemArraySizes[i]);
+ _RS_ASSERT("complexElem.getSubElementOffsetBytes(i) == subElemOffsets[i]",
+ complexElem.getSubElementOffsetBytes(i) == subElemOffsets[i]);
+ }
+ }
+
+ public void run() {
+ RenderScript pRS = RenderScript.create(mCtx);
+ testScriptSide(pRS);
+ testJavaSide(pRS);
+ passTest();
+ pRS.destroy();
+ }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_mesh.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_mesh.java
new file mode 100644
index 000000000000..0c93702e0b07
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_mesh.java
@@ -0,0 +1,75 @@
+/*
+ * 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.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.Mesh.*;
+
+public class UT_mesh extends UnitTest {
+ private Resources mRes;
+
+ Mesh mesh;
+
+ protected UT_mesh(RSTestCore rstc, Resources res, Context ctx) {
+ super(rstc, "Mesh", ctx);
+ mRes = res;
+ }
+
+ private void initializeGlobals(RenderScript RS, ScriptC_mesh s) {
+ Allocation vAlloc0 = Allocation.createSized(RS, Element.F32(RS), 10);
+ Allocation vAlloc1 = Allocation.createSized(RS, Element.F32_2(RS), 10);
+
+ Allocation iAlloc0 = Allocation.createSized(RS, Element.I16(RS), 10);
+ Allocation iAlloc2 = Allocation.createSized(RS, Element.I16(RS), 10);
+
+ Mesh.AllocationBuilder mBuilder = new Mesh.AllocationBuilder(RS);
+ mBuilder.addVertexAllocation(vAlloc0);
+ mBuilder.addVertexAllocation(vAlloc1);
+
+ mBuilder.addIndexSetAllocation(iAlloc0, Primitive.POINT);
+ mBuilder.addIndexSetType(Primitive.LINE);
+ mBuilder.addIndexSetAllocation(iAlloc2, Primitive.TRIANGLE);
+
+ s.set_mesh(mBuilder.create());
+ s.set_vertexAlloc0(vAlloc0);
+ s.set_vertexAlloc1(vAlloc1);
+ s.set_indexAlloc0(iAlloc0);
+ s.set_indexAlloc2(iAlloc2);
+ }
+
+ private void testScriptSide(RenderScript pRS) {
+ ScriptC_mesh s = new ScriptC_mesh(pRS, mRes, R.raw.mesh);
+ pRS.setMessageHandler(mRsMessage);
+ initializeGlobals(pRS, s);
+ s.invoke_mesh_test();
+ pRS.finish();
+ waitForMessage();
+ }
+
+ private void testJavaSide(RenderScript RS) {
+ }
+
+ public void run() {
+ RenderScript pRS = RenderScript.create(mCtx);
+ testScriptSide(pRS);
+ testJavaSide(pRS);
+ passTest();
+ pRS.destroy();
+ }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_raster.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_raster.java
new file mode 100644
index 000000000000..1de4d717f582
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_raster.java
@@ -0,0 +1,81 @@
+/*
+ * 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.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.ProgramRaster;
+import android.renderscript.ProgramRaster.CullMode;
+
+public class UT_program_raster extends UnitTest {
+ private Resources mRes;
+
+ ProgramRaster pointSpriteEnabled;
+ ProgramRaster cullMode;
+
+ protected UT_program_raster(RSTestCore rstc, Resources res, Context ctx) {
+ super(rstc, "ProgramRaster", ctx);
+ mRes = res;
+ }
+
+ private ProgramRaster.Builder getDefaultBuilder(RenderScript RS) {
+ ProgramRaster.Builder b = new ProgramRaster.Builder(RS);
+ b.setCullMode(CullMode.BACK);
+ b.setPointSpriteEnabled(false);
+ return b;
+ }
+
+ private void initializeGlobals(RenderScript RS, ScriptC_program_raster s) {
+ ProgramRaster.Builder b = getDefaultBuilder(RS);
+ pointSpriteEnabled = b.setPointSpriteEnabled(true).create();
+ b = getDefaultBuilder(RS);
+ cullMode = b.setCullMode(CullMode.FRONT).create();
+
+ s.set_pointSpriteEnabled(pointSpriteEnabled);
+ s.set_cullMode(cullMode);
+ }
+
+ private void testScriptSide(RenderScript pRS) {
+ ScriptC_program_raster s = new ScriptC_program_raster(pRS, mRes, R.raw.program_raster);
+ pRS.setMessageHandler(mRsMessage);
+ initializeGlobals(pRS, s);
+ s.invoke_program_raster_test();
+ pRS.finish();
+ waitForMessage();
+ }
+
+ private void testJavaSide(RenderScript RS) {
+ _RS_ASSERT("pointSpriteEnabled.getPointSpriteEnabled() == true",
+ pointSpriteEnabled.getPointSpriteEnabled() == true);
+ _RS_ASSERT("pointSpriteEnabled.getCullMode() == ProgramRaster.CullMode.BACK",
+ pointSpriteEnabled.getCullMode() == ProgramRaster.CullMode.BACK);
+
+ _RS_ASSERT("cullMode.getPointSpriteEnabled() == false",
+ cullMode.getPointSpriteEnabled() == false);
+ _RS_ASSERT("cullMode.getCullMode() == ProgramRaster.CullMode.FRONT",
+ cullMode.getCullMode() == ProgramRaster.CullMode.FRONT);
+ }
+
+ public void run() {
+ RenderScript pRS = RenderScript.create(mCtx);
+ testScriptSide(pRS);
+ testJavaSide(pRS);
+ passTest();
+ pRS.destroy();
+ }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_store.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_store.java
new file mode 100644
index 000000000000..72a401dfd249
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_program_store.java
@@ -0,0 +1,175 @@
+/*
+ * 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.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.ProgramStore.BlendDstFunc;
+import android.renderscript.ProgramStore.BlendSrcFunc;
+import android.renderscript.ProgramStore.Builder;
+import android.renderscript.ProgramStore.DepthFunc;
+
+public class UT_program_store extends UnitTest {
+ private Resources mRes;
+
+ ProgramStore ditherEnable;
+ ProgramStore colorRWriteEnable;
+ ProgramStore colorGWriteEnable;
+ ProgramStore colorBWriteEnable;
+ ProgramStore colorAWriteEnable;
+ ProgramStore blendSrc;
+ ProgramStore blendDst;
+ ProgramStore depthWriteEnable;
+ ProgramStore depthFunc;
+
+ protected UT_program_store(RSTestCore rstc, Resources res, Context ctx) {
+ super(rstc, "ProgramStore", ctx);
+ mRes = res;
+ }
+
+ private ProgramStore.Builder getDefaultBuilder(RenderScript RS) {
+ ProgramStore.Builder b = new ProgramStore.Builder(RS);
+ b.setBlendFunc(ProgramStore.BlendSrcFunc.ZERO, ProgramStore.BlendDstFunc.ZERO);
+ b.setColorMaskEnabled(false, false, false, false);
+ b.setDepthFunc(ProgramStore.DepthFunc.ALWAYS);
+ b.setDepthMaskEnabled(false);
+ b.setDitherEnabled(false);
+ return b;
+ }
+
+ private void initializeGlobals(RenderScript RS, ScriptC_program_store s) {
+ ProgramStore.Builder b = getDefaultBuilder(RS);
+ ditherEnable = b.setDitherEnabled(true).create();
+
+ b = getDefaultBuilder(RS);
+ colorRWriteEnable = b.setColorMaskEnabled(true, false, false, false).create();
+
+ b = getDefaultBuilder(RS);
+ colorGWriteEnable = b.setColorMaskEnabled(false, true, false, false).create();
+
+ b = getDefaultBuilder(RS);
+ colorBWriteEnable = b.setColorMaskEnabled(false, false, true, false).create();
+
+ b = getDefaultBuilder(RS);
+ colorAWriteEnable = b.setColorMaskEnabled(false, false, false, true).create();
+
+ b = getDefaultBuilder(RS);
+ blendSrc = b.setBlendFunc(ProgramStore.BlendSrcFunc.DST_COLOR,
+ ProgramStore.BlendDstFunc.ZERO).create();
+
+ b = getDefaultBuilder(RS);
+ blendDst = b.setBlendFunc(ProgramStore.BlendSrcFunc.ZERO,
+ ProgramStore.BlendDstFunc.DST_ALPHA).create();
+
+ b = getDefaultBuilder(RS);
+ depthWriteEnable = b.setDepthMaskEnabled(true).create();
+
+ b = getDefaultBuilder(RS);
+ depthFunc = b.setDepthFunc(ProgramStore.DepthFunc.GREATER).create();
+
+ s.set_ditherEnable(ditherEnable);
+ s.set_colorRWriteEnable(colorRWriteEnable);
+ s.set_colorGWriteEnable(colorGWriteEnable);
+ s.set_colorBWriteEnable(colorBWriteEnable);
+ s.set_colorAWriteEnable(colorAWriteEnable);
+ s.set_blendSrc(blendSrc);
+ s.set_blendDst(blendDst);
+ s.set_depthWriteEnable(depthWriteEnable);
+ s.set_depthFunc(depthFunc);
+ }
+
+ private void testScriptSide(RenderScript pRS) {
+ ScriptC_program_store s = new ScriptC_program_store(pRS, mRes, R.raw.program_store);
+ pRS.setMessageHandler(mRsMessage);
+ initializeGlobals(pRS, s);
+ s.invoke_program_store_test();
+ pRS.finish();
+ waitForMessage();
+ }
+
+ void checkObject(ProgramStore ps,
+ boolean depthMask,
+ DepthFunc df,
+ BlendSrcFunc bsf,
+ BlendDstFunc bdf,
+ boolean R,
+ boolean G,
+ boolean B,
+ boolean A,
+ boolean dither) {
+ _RS_ASSERT("ps.getDepthMaskEnabled() == depthMask", ps.getDepthMaskEnabled() == depthMask);
+ _RS_ASSERT("ps.getDepthFunc() == df", ps.getDepthFunc() == df);
+ _RS_ASSERT("ps.getBlendSrcFunc() == bsf", ps.getBlendSrcFunc() == bsf);
+ _RS_ASSERT("ps.getBlendDstFunc() == bdf", ps.getBlendDstFunc() == bdf);
+ _RS_ASSERT("ps.getColorMaskREnabled() == R", ps.getColorMaskREnabled() == R);
+ _RS_ASSERT("ps.getColorMaskGEnabled() == G", ps.getColorMaskGEnabled() == G);
+ _RS_ASSERT("ps.getColorMaskBEnabled() == B", ps.getColorMaskBEnabled() == B);
+ _RS_ASSERT("ps.getColorMaskAEnabled() == A", ps.getColorMaskAEnabled() == A);
+ _RS_ASSERT("ps.getDitherEnabled() == dither", ps.getDitherEnabled() == dither);
+ }
+
+ void varyBuilderColorAndDither(ProgramStore.Builder pb,
+ boolean depthMask,
+ DepthFunc df,
+ BlendSrcFunc bsf,
+ BlendDstFunc bdf) {
+ for (int r = 0; r <= 1; r++) {
+ boolean isR = (r == 1);
+ for (int g = 0; g <= 1; g++) {
+ boolean isG = (g == 1);
+ for (int b = 0; b <= 1; b++) {
+ boolean isB = (b == 1);
+ for (int a = 0; a <= 1; a++) {
+ boolean isA = (a == 1);
+ for (int dither = 0; dither <= 1; dither++) {
+ boolean isDither = (dither == 1);
+ pb.setDitherEnabled(isDither);
+ pb.setColorMaskEnabled(isR, isG, isB, isA);
+ ProgramStore ps = pb.create();
+ checkObject(ps, depthMask, df, bsf, bdf, isR, isG, isB, isA, isDither);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public void testJavaSide(RenderScript RS) {
+ for (int depth = 0; depth <= 1; depth++) {
+ boolean depthMask = (depth == 1);
+ for (DepthFunc df : DepthFunc.values()) {
+ for (BlendSrcFunc bsf : BlendSrcFunc.values()) {
+ for (BlendDstFunc bdf : BlendDstFunc.values()) {
+ ProgramStore.Builder b = new ProgramStore.Builder(RS);
+ b.setDepthFunc(df);
+ b.setDepthMaskEnabled(depthMask);
+ b.setBlendFunc(bsf, bdf);
+ varyBuilderColorAndDither(b, depthMask, df, bsf, bdf);
+ }
+ }
+ }
+ }
+ }
+
+ public void run() {
+ RenderScript pRS = RenderScript.create(mCtx);
+ testJavaSide(pRS);
+ testScriptSide(pRS);
+ pRS.destroy();
+ }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_sampler.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_sampler.java
new file mode 100644
index 000000000000..c328cf6a392b
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UT_sampler.java
@@ -0,0 +1,150 @@
+/*
+ * 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.rs.test;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.renderscript.*;
+import android.renderscript.Sampler;
+import android.renderscript.Sampler.Value;
+
+public class UT_sampler extends UnitTest {
+ private Resources mRes;
+
+ Sampler minification;
+ Sampler magnification;
+ Sampler wrapS;
+ Sampler wrapT;
+ Sampler anisotropy;
+
+ protected UT_sampler(RSTestCore rstc, Resources res, Context ctx) {
+ super(rstc, "Sampler", ctx);
+ mRes = res;
+ }
+
+ private Sampler.Builder getDefaultBuilder(RenderScript RS) {
+ Sampler.Builder b = new Sampler.Builder(RS);
+ b.setMinification(Value.NEAREST);
+ b.setMagnification(Value.NEAREST);
+ b.setWrapS(Value.CLAMP);
+ b.setWrapT(Value.CLAMP);
+ b.setAnisotropy(1.0f);
+ return b;
+ }
+
+ private void initializeGlobals(RenderScript RS, ScriptC_sampler s) {
+ Sampler.Builder b = getDefaultBuilder(RS);
+ b.setMinification(Value.LINEAR_MIP_LINEAR);
+ minification = b.create();
+
+ b = getDefaultBuilder(RS);
+ b.setMagnification(Value.LINEAR);
+ magnification = b.create();
+
+ b = getDefaultBuilder(RS);
+ b.setWrapS(Value.WRAP);
+ wrapS = b.create();
+
+ b = getDefaultBuilder(RS);
+ b.setWrapT(Value.WRAP);
+ wrapT = b.create();
+
+ b = getDefaultBuilder(RS);
+ b.setAnisotropy(8.0f);
+ anisotropy = b.create();
+
+ s.set_minification(minification);
+ s.set_magnification(magnification);
+ s.set_wrapS(wrapS);
+ s.set_wrapT(wrapT);
+ s.set_anisotropy(anisotropy);
+ }
+
+ private void testScriptSide(RenderScript pRS) {
+ ScriptC_sampler s = new ScriptC_sampler(pRS, mRes, R.raw.sampler);
+ pRS.setMessageHandler(mRsMessage);
+ initializeGlobals(pRS, s);
+ s.invoke_sampler_test();
+ pRS.finish();
+ waitForMessage();
+ }
+
+ private void testJavaSide(RenderScript RS) {
+ _RS_ASSERT("minification.getMagnification() == Sampler.Value.NEAREST",
+ minification.getMagnification() == Sampler.Value.NEAREST);
+ _RS_ASSERT("minification.getMinification() == Sampler.Value.LINEAR_MIP_LINEAR",
+ minification.getMinification() == Sampler.Value.LINEAR_MIP_LINEAR);
+ _RS_ASSERT("minification.getWrapS() == Sampler.Value.CLAMP",
+ minification.getWrapS() == Sampler.Value.CLAMP);
+ _RS_ASSERT("minification.getWrapT() == Sampler.Value.CLAMP",
+ minification.getWrapT() == Sampler.Value.CLAMP);
+ _RS_ASSERT("minification.getAnisotropy() == 1.0f",
+ minification.getAnisotropy() == 1.0f);
+
+ _RS_ASSERT("magnification.getMagnification() == Sampler.Value.LINEAR",
+ magnification.getMagnification() == Sampler.Value.LINEAR);
+ _RS_ASSERT("magnification.getMinification() == Sampler.Value.NEAREST",
+ magnification.getMinification() == Sampler.Value.NEAREST);
+ _RS_ASSERT("magnification.getWrapS() == Sampler.Value.CLAMP",
+ magnification.getWrapS() == Sampler.Value.CLAMP);
+ _RS_ASSERT("magnification.getWrapT() == Sampler.Value.CLAMP",
+ magnification.getWrapT() == Sampler.Value.CLAMP);
+ _RS_ASSERT("magnification.getAnisotropy() == 1.0f",
+ magnification.getAnisotropy() == 1.0f);
+
+ _RS_ASSERT("wrapS.getMagnification() == Sampler.Value.NEAREST",
+ wrapS.getMagnification() == Sampler.Value.NEAREST);
+ _RS_ASSERT("wrapS.getMinification() == Sampler.Value.NEAREST",
+ wrapS.getMinification() == Sampler.Value.NEAREST);
+ _RS_ASSERT("wrapS.getWrapS() == Sampler.Value.WRAP",
+ wrapS.getWrapS() == Sampler.Value.WRAP);
+ _RS_ASSERT("wrapS.getWrapT() == Sampler.Value.CLAMP",
+ wrapS.getWrapT() == Sampler.Value.CLAMP);
+ _RS_ASSERT("wrapS.getAnisotropy() == 1.0f",
+ wrapS.getAnisotropy() == 1.0f);
+
+ _RS_ASSERT("wrapT.getMagnification() == Sampler.Value.NEAREST",
+ wrapT.getMagnification() == Sampler.Value.NEAREST);
+ _RS_ASSERT("wrapT.getMinification() == Sampler.Value.NEAREST",
+ wrapT.getMinification() == Sampler.Value.NEAREST);
+ _RS_ASSERT("wrapT.getWrapS() == Sampler.Value.CLAMP",
+ wrapT.getWrapS() == Sampler.Value.CLAMP);
+ _RS_ASSERT("wrapT.getWrapT() == Sampler.Value.WRAP",
+ wrapT.getWrapT() == Sampler.Value.WRAP);
+ _RS_ASSERT("wrapT.getAnisotropy() == 1.0f",
+ wrapT.getAnisotropy() == 1.0f);
+
+ _RS_ASSERT("anisotropy.getMagnification() == Sampler.Value.NEAREST",
+ anisotropy.getMagnification() == Sampler.Value.NEAREST);
+ _RS_ASSERT("anisotropy.getMinification() == Sampler.Value.NEAREST",
+ anisotropy.getMinification() == Sampler.Value.NEAREST);
+ _RS_ASSERT("anisotropy.getWrapS() == Sampler.Value.CLAMP",
+ anisotropy.getWrapS() == Sampler.Value.CLAMP);
+ _RS_ASSERT("anisotropy.getWrapT() == Sampler.Value.CLAMP",
+ anisotropy.getWrapT() == Sampler.Value.CLAMP);
+ _RS_ASSERT("anisotropy.getAnisotropy() == 1.0f",
+ anisotropy.getAnisotropy() == 8.0f);
+ }
+
+ public void run() {
+ RenderScript pRS = RenderScript.create(mCtx);
+ testScriptSide(pRS);
+ testJavaSide(pRS);
+ passTest();
+ pRS.destroy();
+ }
+}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java b/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java
index edff83f2756b..fbac124b896b 100644
--- a/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/UnitTest.java
@@ -58,8 +58,8 @@ public class UnitTest extends Thread {
protected void _RS_ASSERT(String message, boolean b) {
if(b == false) {
- result = -1;
Log.e(name, message + " FAILED");
+ failTest();
}
}
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/array_init.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/array_init.rs
new file mode 100644
index 000000000000..842249af2c55
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/array_init.rs
@@ -0,0 +1,58 @@
+#include "shared.rsh"
+
+// Testing constant array initialization
+float fa[4] = {1.0, 9.9999f};
+double da[2] = {7.0, 8.88888};
+char ca[4] = {'a', 7, 'b', 'c'};
+short sa[4] = {1, 1, 2, 3};
+int ia[4] = {5, 8};
+long la[2] = {13, 21};
+long long lla[4] = {34};
+bool ba[3] = {true, false};
+
+void array_init_test() {
+ bool failed = false;
+
+ _RS_ASSERT(fa[0] == 1.0);
+ _RS_ASSERT(fa[1] == 9.9999f);
+ _RS_ASSERT(fa[2] == 0);
+ _RS_ASSERT(fa[3] == 0);
+
+ _RS_ASSERT(da[0] == 7.0);
+ _RS_ASSERT(da[1] == 8.88888);
+
+ _RS_ASSERT(ca[0] == 'a');
+ _RS_ASSERT(ca[1] == 7);
+ _RS_ASSERT(ca[2] == 'b');
+ _RS_ASSERT(ca[3] == 'c');
+
+ _RS_ASSERT(sa[0] == 1);
+ _RS_ASSERT(sa[1] == 1);
+ _RS_ASSERT(sa[2] == 2);
+ _RS_ASSERT(sa[3] == 3);
+
+ _RS_ASSERT(ia[0] == 5);
+ _RS_ASSERT(ia[1] == 8);
+ _RS_ASSERT(ia[2] == 0);
+ _RS_ASSERT(ia[3] == 0);
+
+ _RS_ASSERT(la[0] == 13);
+ _RS_ASSERT(la[1] == 21);
+
+ _RS_ASSERT(lla[0] == 34);
+ _RS_ASSERT(lla[1] == 0);
+ _RS_ASSERT(lla[2] == 0);
+ _RS_ASSERT(lla[3] == 0);
+
+ _RS_ASSERT(ba[0] == true);
+ _RS_ASSERT(ba[1] == false);
+ _RS_ASSERT(ba[2] == false);
+
+ if (failed) {
+ rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+ }
+ else {
+ rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+ }
+}
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/element.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/element.rs
new file mode 100644
index 000000000000..0c42d84e1481
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/element.rs
@@ -0,0 +1,158 @@
+#include "shared.rsh"
+#include "rs_graphics.rsh"
+
+rs_element simpleElem;
+rs_element complexElem;
+typedef struct ComplexStruct {
+ float subElem0;
+ float subElem1;
+ int subElem2;
+ float arrayElem0[2];
+ int arrayElem1[5];
+ char subElem3;
+ float subElem4;
+ float2 subElem5;
+ float3 subElem6;
+ float4 subElem_7;
+} ComplexStruct_t;
+
+ComplexStruct_t *complexStruct;
+
+static const char *subElemNames[] = {
+ "subElem0",
+ "subElem1",
+ "subElem2",
+ "arrayElem0",
+ "arrayElem1",
+ "subElem3",
+ "subElem4",
+ "subElem5",
+ "subElem6",
+ "subElem_7",
+};
+
+static uint32_t subElemNamesSizes[] = {
+ 8,
+ 8,
+ 8,
+ 10,
+ 10,
+ 8,
+ 8,
+ 8,
+ 8,
+ 9,
+};
+
+static uint32_t subElemArraySizes[] = {
+ 1,
+ 1,
+ 1,
+ 2,
+ 5,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+};
+
+static void resetStruct() {
+ uint8_t *bytePtr = (uint8_t*)complexStruct;
+ uint32_t sizeOfStruct = sizeof(*complexStruct);
+ for(uint32_t i = 0; i < sizeOfStruct; i ++) {
+ bytePtr[i] = 0;
+ }
+}
+
+static bool equals(const char *name0, const char * name1, uint32_t len) {
+ for (uint32_t i = 0; i < len; i ++) {
+ if (name0[i] != name1[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool test_element_getters() {
+ bool failed = false;
+
+ uint32_t subElemOffsets[10];
+ uint32_t index = 0;
+ subElemOffsets[index++] = (uint32_t)&complexStruct->subElem0 - (uint32_t)complexStruct;
+ subElemOffsets[index++] = (uint32_t)&complexStruct->subElem1 - (uint32_t)complexStruct;
+ subElemOffsets[index++] = (uint32_t)&complexStruct->subElem2 - (uint32_t)complexStruct;
+ subElemOffsets[index++] = (uint32_t)&complexStruct->arrayElem0 - (uint32_t)complexStruct;
+ subElemOffsets[index++] = (uint32_t)&complexStruct->arrayElem1 - (uint32_t)complexStruct;
+ subElemOffsets[index++] = (uint32_t)&complexStruct->subElem3 - (uint32_t)complexStruct;
+ subElemOffsets[index++] = (uint32_t)&complexStruct->subElem4 - (uint32_t)complexStruct;
+ subElemOffsets[index++] = (uint32_t)&complexStruct->subElem5 - (uint32_t)complexStruct;
+ subElemOffsets[index++] = (uint32_t)&complexStruct->subElem6 - (uint32_t)complexStruct;
+ subElemOffsets[index++] = (uint32_t)&complexStruct->subElem_7 - (uint32_t)complexStruct;
+
+ uint32_t subElemCount = rsElementGetSubElementCount(simpleElem);
+ _RS_ASSERT(subElemCount == 0);
+ _RS_ASSERT(rsElementGetDataKind(simpleElem) == RS_KIND_USER);
+ _RS_ASSERT(rsElementGetDataType(simpleElem) == RS_TYPE_FLOAT_32);
+ _RS_ASSERT(rsElementGetVectorSize(simpleElem) == 3);
+
+ subElemCount = rsElementGetSubElementCount(complexElem);
+ _RS_ASSERT(subElemCount == 10);
+ _RS_ASSERT(rsElementGetDataKind(complexElem) == RS_KIND_USER);
+ _RS_ASSERT(rsElementGetDataType(complexElem) == RS_TYPE_NONE);
+ _RS_ASSERT(rsElementGetVectorSize(complexElem) == 1);
+ _RS_ASSERT(rsElementGetSizeBytes(complexElem) == sizeof(*complexStruct));
+
+ char buffer[64];
+ for (uint32_t i = 0; i < subElemCount; i ++) {
+ rs_element subElem = rsElementGetSubElement(complexElem, i);
+ _RS_ASSERT(rsIsObject(subElem));
+
+ _RS_ASSERT(rsElementGetSubElementNameLength(complexElem, i) == subElemNamesSizes[i] + 1);
+
+ uint32_t written = rsElementGetSubElementName(complexElem, i, buffer, 64);
+ _RS_ASSERT(written == subElemNamesSizes[i]);
+ _RS_ASSERT(equals(buffer, subElemNames[i], written));
+
+ _RS_ASSERT(rsElementGetSubElementArraySize(complexElem, i) == subElemArraySizes[i]);
+ _RS_ASSERT(rsElementGetSubElementOffsetBytes(complexElem, i) == subElemOffsets[i]);
+ }
+
+ // Tests error checking
+ rs_element subElem = rsElementGetSubElement(complexElem, subElemCount);
+ _RS_ASSERT(!rsIsObject(subElem));
+
+ _RS_ASSERT(rsElementGetSubElementNameLength(complexElem, subElemCount) == 0);
+
+ _RS_ASSERT(rsElementGetSubElementName(complexElem, subElemCount, buffer, 64) == 0);
+ _RS_ASSERT(rsElementGetSubElementName(complexElem, 0, NULL, 64) == 0);
+ _RS_ASSERT(rsElementGetSubElementName(complexElem, 0, buffer, 0) == 0);
+ uint32_t written = rsElementGetSubElementName(complexElem, 0, buffer, 5);
+ _RS_ASSERT(written == 4);
+ _RS_ASSERT(buffer[4] == '\0');
+
+ _RS_ASSERT(rsElementGetSubElementArraySize(complexElem, subElemCount) == 0);
+ _RS_ASSERT(rsElementGetSubElementOffsetBytes(complexElem, subElemCount) == 0);
+
+ if (failed) {
+ rsDebug("test_element_getters FAILED", 0);
+ }
+ else {
+ rsDebug("test_element_getters PASSED", 0);
+ }
+
+ return failed;
+}
+
+void element_test() {
+ bool failed = false;
+ failed |= test_element_getters();
+
+ if (failed) {
+ rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+ }
+ else {
+ rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+ }
+}
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/mesh.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/mesh.rs
new file mode 100644
index 000000000000..627ab9923c72
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/mesh.rs
@@ -0,0 +1,64 @@
+#include "shared.rsh"
+#include "rs_graphics.rsh"
+
+rs_mesh mesh;
+rs_allocation vertexAlloc0;
+rs_allocation vertexAlloc1;
+
+rs_allocation indexAlloc0;
+rs_allocation indexAlloc2;
+
+static bool test_mesh_getters() {
+ bool failed = false;
+
+ _RS_ASSERT(rsMeshGetVertexAllocationCount(mesh) == 2);
+ _RS_ASSERT(rsMeshGetPrimitiveCount(mesh) == 3);
+
+ rs_allocation meshV0 = rsMeshGetVertexAllocation(mesh, 0);
+ rs_allocation meshV1 = rsMeshGetVertexAllocation(mesh, 1);
+ rs_allocation meshV2 = rsMeshGetVertexAllocation(mesh, 2);
+ _RS_ASSERT(meshV0.p == vertexAlloc0.p);
+ _RS_ASSERT(meshV1.p == vertexAlloc1.p);
+ _RS_ASSERT(!rsIsObject(meshV2));
+
+ rs_allocation meshI0 = rsMeshGetIndexAllocation(mesh, 0);
+ rs_allocation meshI1 = rsMeshGetIndexAllocation(mesh, 1);
+ rs_allocation meshI2 = rsMeshGetIndexAllocation(mesh, 2);
+ rs_allocation meshI3 = rsMeshGetIndexAllocation(mesh, 3);
+ _RS_ASSERT(meshI0.p == indexAlloc0.p);
+ _RS_ASSERT(!rsIsObject(meshI1));
+ _RS_ASSERT(meshI2.p == indexAlloc2.p);
+ _RS_ASSERT(!rsIsObject(meshI3));
+
+ rs_primitive p0 = rsMeshGetPrimitive(mesh, 0);
+ rs_primitive p1 = rsMeshGetPrimitive(mesh, 1);
+ rs_primitive p2 = rsMeshGetPrimitive(mesh, 2);
+ rs_primitive p3 = rsMeshGetPrimitive(mesh, 3);
+
+ _RS_ASSERT(p0 == RS_PRIMITIVE_POINT);
+ _RS_ASSERT(p1 == RS_PRIMITIVE_LINE);
+ _RS_ASSERT(p2 == RS_PRIMITIVE_TRIANGLE);
+ _RS_ASSERT(p3 == RS_PRIMITIVE_INVALID);
+
+ if (failed) {
+ rsDebug("test_mesh_getters FAILED", 0);
+ }
+ else {
+ rsDebug("test_mesh_getters PASSED", 0);
+ }
+
+ return failed;
+}
+
+void mesh_test() {
+ bool failed = false;
+ failed |= test_mesh_getters();
+
+ if (failed) {
+ rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+ }
+ else {
+ rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+ }
+}
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs
new file mode 100644
index 000000000000..11b8c3060cd4
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_raster.rs
@@ -0,0 +1,37 @@
+#include "shared.rsh"
+#include "rs_graphics.rsh"
+
+rs_program_raster pointSpriteEnabled;
+rs_program_raster cullMode;
+
+static bool test_program_raster_getters() {
+ bool failed = false;
+
+ _RS_ASSERT(rsgProgramRasterGetPointSpriteEnabled(pointSpriteEnabled) == true);
+ _RS_ASSERT(rsgProgramRasterGetCullMode(pointSpriteEnabled) == RS_CULL_BACK);
+
+ _RS_ASSERT(rsgProgramRasterGetPointSpriteEnabled(cullMode) == false);
+ _RS_ASSERT(rsgProgramRasterGetCullMode(cullMode) == RS_CULL_FRONT);
+
+ if (failed) {
+ rsDebug("test_program_raster_getters FAILED", 0);
+ }
+ else {
+ rsDebug("test_program_raster_getters PASSED", 0);
+ }
+
+ return failed;
+}
+
+void program_raster_test() {
+ bool failed = false;
+ failed |= test_program_raster_getters();
+
+ if (failed) {
+ rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+ }
+ else {
+ rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+ }
+}
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs
new file mode 100644
index 000000000000..3cd8a208ca66
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/program_store.rs
@@ -0,0 +1,128 @@
+#include "shared.rsh"
+#include "rs_graphics.rsh"
+
+rs_program_store ditherEnable;
+rs_program_store colorRWriteEnable;
+rs_program_store colorGWriteEnable;
+rs_program_store colorBWriteEnable;
+rs_program_store colorAWriteEnable;
+rs_program_store blendSrc;
+rs_program_store blendDst;
+rs_program_store depthWriteEnable;
+rs_program_store depthFunc;
+
+static bool test_program_store_getters() {
+ bool failed = false;
+
+ _RS_ASSERT(rsgProgramStoreGetDepthFunc(depthFunc) == RS_DEPTH_FUNC_GREATER);
+ _RS_ASSERT(rsgProgramStoreGetDepthMask(depthFunc) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskR(depthFunc) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskG(depthFunc) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskB(depthFunc) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskA(depthFunc) == false);
+ _RS_ASSERT(rsgProgramStoreGetDitherEnabled(depthFunc) == false);
+ _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(depthFunc) == RS_BLEND_SRC_ZERO);
+ _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(depthFunc) == RS_BLEND_DST_ZERO);
+
+ _RS_ASSERT(rsgProgramStoreGetDepthFunc(depthWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+ _RS_ASSERT(rsgProgramStoreGetDepthMask(depthWriteEnable) == true);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskR(depthWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskG(depthWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskB(depthWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskA(depthWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetDitherEnabled(depthWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(depthWriteEnable) == RS_BLEND_SRC_ZERO);
+ _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(depthWriteEnable) == RS_BLEND_DST_ZERO);
+
+ _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorRWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+ _RS_ASSERT(rsgProgramStoreGetDepthMask(colorRWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorRWriteEnable) == true);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorRWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorRWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorRWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorRWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorRWriteEnable) == RS_BLEND_SRC_ZERO);
+ _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorRWriteEnable) == RS_BLEND_DST_ZERO);
+
+ _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorGWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+ _RS_ASSERT(rsgProgramStoreGetDepthMask(colorGWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorGWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorGWriteEnable) == true);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorGWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorGWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorGWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorGWriteEnable) == RS_BLEND_SRC_ZERO);
+ _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorGWriteEnable) == RS_BLEND_DST_ZERO);
+
+ _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorBWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+ _RS_ASSERT(rsgProgramStoreGetDepthMask(colorBWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorBWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorBWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorBWriteEnable) == true);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorBWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorBWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorBWriteEnable) == RS_BLEND_SRC_ZERO);
+ _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorBWriteEnable) == RS_BLEND_DST_ZERO);
+
+ _RS_ASSERT(rsgProgramStoreGetDepthFunc(colorAWriteEnable) == RS_DEPTH_FUNC_ALWAYS);
+ _RS_ASSERT(rsgProgramStoreGetDepthMask(colorAWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskR(colorAWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskG(colorAWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskB(colorAWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskA(colorAWriteEnable) == true);
+ _RS_ASSERT(rsgProgramStoreGetDitherEnabled(colorAWriteEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(colorAWriteEnable) == RS_BLEND_SRC_ZERO);
+ _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(colorAWriteEnable) == RS_BLEND_DST_ZERO);
+
+ _RS_ASSERT(rsgProgramStoreGetDepthFunc(ditherEnable) == RS_DEPTH_FUNC_ALWAYS);
+ _RS_ASSERT(rsgProgramStoreGetDepthMask(ditherEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskR(ditherEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskG(ditherEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskB(ditherEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskA(ditherEnable) == false);
+ _RS_ASSERT(rsgProgramStoreGetDitherEnabled(ditherEnable) == true);
+ _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(ditherEnable) == RS_BLEND_SRC_ZERO);
+ _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(ditherEnable) == RS_BLEND_DST_ZERO);
+
+ _RS_ASSERT(rsgProgramStoreGetDepthFunc(blendSrc) == RS_DEPTH_FUNC_ALWAYS);
+ _RS_ASSERT(rsgProgramStoreGetDepthMask(blendSrc) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskR(blendSrc) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskG(blendSrc) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskB(blendSrc) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskA(blendSrc) == false);
+ _RS_ASSERT(rsgProgramStoreGetDitherEnabled(blendSrc) == false);
+ _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(blendSrc) == RS_BLEND_SRC_DST_COLOR);
+ _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(blendSrc) == RS_BLEND_DST_ZERO);
+
+ _RS_ASSERT(rsgProgramStoreGetDepthFunc(blendDst) == RS_DEPTH_FUNC_ALWAYS);
+ _RS_ASSERT(rsgProgramStoreGetDepthMask(blendDst) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskR(blendDst) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskG(blendDst) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskB(blendDst) == false);
+ _RS_ASSERT(rsgProgramStoreGetColorMaskA(blendDst) == false);
+ _RS_ASSERT(rsgProgramStoreGetDitherEnabled(blendDst) == false);
+ _RS_ASSERT(rsgProgramStoreGetBlendSrcFunc(blendDst) == RS_BLEND_SRC_ZERO);
+ _RS_ASSERT(rsgProgramStoreGetBlendDstFunc(blendDst) == RS_BLEND_DST_DST_ALPHA);
+
+ if (failed) {
+ rsDebug("test_program_store_getters FAILED", 0);
+ }
+ else {
+ rsDebug("test_program_store_getters PASSED", 0);
+ }
+
+ return failed;
+}
+
+void program_store_test() {
+ bool failed = false;
+ failed |= test_program_store_getters();
+
+ if (failed) {
+ rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+ }
+ else {
+ rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+ }
+}
+
diff --git a/tests/RenderScriptTests/tests/src/com/android/rs/test/sampler.rs b/tests/RenderScriptTests/tests/src/com/android/rs/test/sampler.rs
new file mode 100644
index 000000000000..ac9a5496afb2
--- /dev/null
+++ b/tests/RenderScriptTests/tests/src/com/android/rs/test/sampler.rs
@@ -0,0 +1,63 @@
+#include "shared.rsh"
+#include "rs_graphics.rsh"
+rs_sampler minification;
+rs_sampler magnification;
+rs_sampler wrapS;
+rs_sampler wrapT;
+rs_sampler anisotropy;
+
+static bool test_sampler_getters() {
+ bool failed = false;
+
+ _RS_ASSERT(rsgSamplerGetMagnification(minification) == RS_SAMPLER_NEAREST);
+ _RS_ASSERT(rsgSamplerGetMinification(minification) == RS_SAMPLER_LINEAR_MIP_LINEAR);
+ _RS_ASSERT(rsgSamplerGetWrapS(minification) == RS_SAMPLER_CLAMP);
+ _RS_ASSERT(rsgSamplerGetWrapT(minification) == RS_SAMPLER_CLAMP);
+ _RS_ASSERT(rsgSamplerGetAnisotropy(minification) == 1.0f);
+
+ _RS_ASSERT(rsgSamplerGetMagnification(magnification) == RS_SAMPLER_LINEAR);
+ _RS_ASSERT(rsgSamplerGetMinification(magnification) == RS_SAMPLER_NEAREST);
+ _RS_ASSERT(rsgSamplerGetWrapS(magnification) == RS_SAMPLER_CLAMP);
+ _RS_ASSERT(rsgSamplerGetWrapT(magnification) == RS_SAMPLER_CLAMP);
+ _RS_ASSERT(rsgSamplerGetAnisotropy(magnification) == 1.0f);
+
+ _RS_ASSERT(rsgSamplerGetMagnification(wrapS) == RS_SAMPLER_NEAREST);
+ _RS_ASSERT(rsgSamplerGetMinification(wrapS) == RS_SAMPLER_NEAREST);
+ _RS_ASSERT(rsgSamplerGetWrapS(wrapS) == RS_SAMPLER_WRAP);
+ _RS_ASSERT(rsgSamplerGetWrapT(wrapS) == RS_SAMPLER_CLAMP);
+ _RS_ASSERT(rsgSamplerGetAnisotropy(wrapS) == 1.0f);
+
+ _RS_ASSERT(rsgSamplerGetMagnification(wrapT) == RS_SAMPLER_NEAREST);
+ _RS_ASSERT(rsgSamplerGetMinification(wrapT) == RS_SAMPLER_NEAREST);
+ _RS_ASSERT(rsgSamplerGetWrapS(wrapT) == RS_SAMPLER_CLAMP);
+ _RS_ASSERT(rsgSamplerGetWrapT(wrapT) == RS_SAMPLER_WRAP);
+ _RS_ASSERT(rsgSamplerGetAnisotropy(wrapT) == 1.0f);
+
+ _RS_ASSERT(rsgSamplerGetMagnification(anisotropy) == RS_SAMPLER_NEAREST);
+ _RS_ASSERT(rsgSamplerGetMinification(anisotropy) == RS_SAMPLER_NEAREST);
+ _RS_ASSERT(rsgSamplerGetWrapS(anisotropy) == RS_SAMPLER_CLAMP);
+ _RS_ASSERT(rsgSamplerGetWrapT(anisotropy) == RS_SAMPLER_CLAMP);
+ _RS_ASSERT(rsgSamplerGetAnisotropy(anisotropy) == 8.0f);
+
+ if (failed) {
+ rsDebug("test_sampler_getters FAILED", 0);
+ }
+ else {
+ rsDebug("test_sampler_getters PASSED", 0);
+ }
+
+ return failed;
+}
+
+void sampler_test() {
+ bool failed = false;
+ failed |= test_sampler_getters();
+
+ if (failed) {
+ rsSendToClientBlocking(RS_MSG_TEST_FAILED);
+ }
+ else {
+ rsSendToClientBlocking(RS_MSG_TEST_PASSED);
+ }
+}
+
diff --git a/tools/aidl/Type.cpp b/tools/aidl/Type.cpp
index b84b3c473365..42e12265247d 100755
--- a/tools/aidl/Type.cpp
+++ b/tools/aidl/Type.cpp
@@ -212,6 +212,12 @@ Type::CreatorName() const
}
string
+Type::RpcCreatorName() const
+{
+ return "";
+}
+
+string
Type::InstantiableName() const
{
return QualifiedName();
@@ -910,6 +916,12 @@ UserDataType::CreatorName() const
return QualifiedName() + ".CREATOR";
}
+string
+UserDataType::RpcCreatorName() const
+{
+ return QualifiedName() + ".RPC_CREATOR";
+}
+
void
UserDataType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
{
@@ -1004,48 +1016,17 @@ void
UserDataType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
Variable* data, int flags)
{
- // if (v != null) {
- // RpcData _obj = new RpcData();
- // v.writeToRpcData(_obj);
- // data.putRpcData(k, obj);
- // }
- IfStatement* ifpart = new IfStatement;
- ifpart->expression = new Comparison(v, "!=", NULL_VALUE);
- Variable* _obj = new Variable(RPC_DATA_TYPE, "_obj");
- ifpart->statements->Add(new VariableDeclaration(_obj, new NewExpression(RPC_DATA_TYPE)));
- ifpart->statements->Add(new MethodCall(v, "writeToRpcData", 1, _obj));
- ifpart->statements->Add(new MethodCall(data, "putRpcData", 2, k, _obj));
-
- addTo->Add(ifpart);
+ // data.putFlattenable(k, v);
+ addTo->Add(new MethodCall(data, "putFlattenable", 2, k, v));
}
void
UserDataType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
Variable* data, Variable** cl)
{
- // RpcData _obj_XX = data.getRpcData(k);
- // if (_data_XX != null)
- // v = CLASS.RPC_CREATOR.createFromParcel(parcel)
- // } else {
- // v = null;
- // }
-
- StatementBlock* block = new StatementBlock;
- addTo->Add(block);
-
- Variable* _obj = new Variable(RPC_DATA_TYPE, "_obj");
- block->Add(new VariableDeclaration(_obj, new MethodCall(data, "getRpcData", 1, k)));
-
- IfStatement* ifpart = new IfStatement();
- ifpart->expression = new Comparison(_obj, "!=", NULL_VALUE);
- ifpart->statements->Add(new Assignment(v,
- new MethodCall(v->type, "RPC_CREATOR.createFromRpcData", 1, data)));
-
- IfStatement* elsepart = new IfStatement();
- ifpart->elseif = elsepart;
- elsepart->statements->Add(new Assignment(v, NULL_VALUE));
-
- block->Add(ifpart);
+ // data.getFlattenable(k, CLASS.RPC_CREATOR);
+ addTo->Add(new Assignment(v, new MethodCall(data, "getFlattenable", 2, k,
+ new FieldVariable(v->type, "RPC_CREATOR"))));
}
// ================================================================
@@ -1221,17 +1202,32 @@ void
GenericListType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
Variable* data, int flags)
{
- addTo->Add(new MethodCall(data, "putList", 2, k, v));
+ Type* generic = GenericArgumentTypes()[0];
+ if (generic == RPC_DATA_TYPE) {
+ addTo->Add(new MethodCall(data, "putRpcDataList", 2, k, v));
+ } else if (generic->RpcCreatorName() != "") {
+ addTo->Add(new MethodCall(data, "putFlattenableList", 2, k, v));
+ } else {
+ addTo->Add(new MethodCall(data, "putList", 2, k, v));
+ }
}
void
GenericListType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
Variable* data, Variable** cl)
{
- string classArg = GenericArgumentTypes()[0]->QualifiedName();
- classArg += ".class";
- addTo->Add(new Assignment(v, new MethodCall(data, "getList", 2, k,
- new LiteralExpression(classArg))));
+ Type* generic = GenericArgumentTypes()[0];
+ if (generic == RPC_DATA_TYPE) {
+ addTo->Add(new Assignment(v, new MethodCall(data, "getRpcDataList", 2, k)));
+ } else if (generic->RpcCreatorName() != "") {
+ addTo->Add(new Assignment(v, new MethodCall(data, "getFlattenableList", 2, k,
+ new LiteralExpression(generic->RpcCreatorName()))));
+ } else {
+ string classArg = GenericArgumentTypes()[0]->QualifiedName();
+ classArg += ".class";
+ addTo->Add(new Assignment(v, new MethodCall(data, "getList", 2, k,
+ new LiteralExpression(classArg))));
+ }
}
diff --git a/tools/aidl/Type.h b/tools/aidl/Type.h
index f2f3f21678c8..ae12720142e8 100755
--- a/tools/aidl/Type.h
+++ b/tools/aidl/Type.h
@@ -42,6 +42,7 @@ public:
virtual string ImportType() const;
virtual string CreatorName() const;
+ virtual string RpcCreatorName() const;
virtual string InstantiableName() const;
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
@@ -358,6 +359,7 @@ public:
const string& declFile = "", int declLine = -1);
virtual string CreatorName() const;
+ virtual string RpcCreatorName() const;
virtual void WriteToParcel(StatementBlock* addTo, Variable* v,
Variable* parcel, int flags);
diff --git a/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp
index e5689b915c4b..8dbbf502a007 100644
--- a/tools/aidl/aidl.cpp
+++ b/tools/aidl/aidl.cpp
@@ -475,6 +475,15 @@ check_method(const char* filename, int kind, method_type* m)
err = 1;
}
+ if (returnType == EVENT_FAKE_TYPE
+ && convert_direction(arg->direction.data) != IN_PARAMETER) {
+ fprintf(stderr, "%s:%d parameter %d: '%s %s' All paremeters on events must be 'in'.\n",
+ filename, m->type.type.lineno, index,
+ arg->type.type.data, arg->name.data);
+ err = 1;
+ goto next;
+ }
+
if (arg->direction.data == NULL
&& (arg->type.dimension != 0 || t->CanBeOutParameter())) {
fprintf(stderr, "%s:%d parameter %d: '%s %s' can be an out"
diff --git a/tools/aidl/generate_java_rpc.cpp b/tools/aidl/generate_java_rpc.cpp
index e4867e463a0e..ecff3a1ad3e7 100644
--- a/tools/aidl/generate_java_rpc.cpp
+++ b/tools/aidl/generate_java_rpc.cpp
@@ -15,6 +15,8 @@ Type* RPC_BROKER_TYPE = new Type("com.android.athome.connector", "Broker",
Type::BUILT_IN, false, false, false);
Type* RPC_CONTAINER_TYPE = new Type("com.android.athome.connector", "ConnectorContainer",
Type::BUILT_IN, false, false, false);
+Type* PLACE_INFO_TYPE = new Type("android.support.place.connector", "PlaceInfo",
+ Type::BUILT_IN, false, false, false);
// TODO: Just use Endpoint, so this works for all endpoints.
Type* RPC_CONNECTOR_TYPE = new Type("com.android.athome.connector", "Connector",
Type::BUILT_IN, false, false, false);
@@ -293,6 +295,7 @@ public:
private:
void generate_ctor();
+ void generate_get_endpoint_info();
};
RpcProxyClass::RpcProxyClass(const interface_type* iface, InterfaceType* interfaceType)
@@ -312,6 +315,7 @@ RpcProxyClass::RpcProxyClass(const interface_type* iface, InterfaceType* interfa
// methods
generate_ctor();
+ generate_get_endpoint_info();
}
RpcProxyClass::~RpcProxyClass()
@@ -335,6 +339,19 @@ RpcProxyClass::generate_ctor()
ctor->statements->Add(new Assignment(this->endpoint, endpoint));
}
+void
+RpcProxyClass::generate_get_endpoint_info()
+{
+ Method* get = new Method;
+ get->modifiers = PUBLIC;
+ get->returnType = RPC_ENDPOINT_INFO_TYPE;
+ get->name = "getEndpointInfo";
+ get->statements = new StatementBlock;
+ this->elements.push_back(get);
+
+ get->statements->Add(new ReturnStatement(this->endpoint));
+}
+
// =================================================
class EventListenerClass : public DispatcherClass
{
@@ -460,15 +477,17 @@ EndpointBaseClass::generate_ctor()
{
Variable* container = new Variable(RPC_CONTAINER_TYPE, "container");
Variable* broker = new Variable(RPC_BROKER_TYPE, "broker");
+ Variable* place = new Variable(PLACE_INFO_TYPE, "placeInfo");
Method* ctor = new Method;
ctor->modifiers = PUBLIC;
ctor->name = class_name_leaf(this->type->Name());
ctor->statements = new StatementBlock;
ctor->parameters.push_back(container);
ctor->parameters.push_back(broker);
+ ctor->parameters.push_back(place);
this->elements.push_back(ctor);
- ctor->statements->Add(new MethodCall("super", 2, container, broker));
+ ctor->statements->Add(new MethodCall("super", 3, container, broker, place));
}
// =================================================
@@ -739,11 +758,13 @@ generate_result_dispatcher_method(const method_type* method,
// The return value
{
Type* t = NAMES.Search(method->type.type.data);
- Variable* rv = new Variable(t, "rv");
- dispatchMethod->statements->Add(new VariableDeclaration(rv));
- generate_create_from_data(t, dispatchMethod->statements, "_result", rv,
- resultData, &classLoader);
- realCall->arguments.push_back(rv);
+ if (t != VOID_TYPE) {
+ Variable* rv = new Variable(t, "rv");
+ dispatchMethod->statements->Add(new VariableDeclaration(rv));
+ generate_create_from_data(t, dispatchMethod->statements, "_result", rv,
+ resultData, &classLoader);
+ realCall->arguments.push_back(rv);
+ }
}
VariableFactory stubArgs("arg");
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index b8b7c0eaaae1..fb9286e90915 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -1625,14 +1625,14 @@ public class WifiStateMachine extends StateMachine {
private void handleNetworkDisconnect() {
if (DBG) log("Stopping DHCP and clearing IP");
- /* In case we were in middle of DHCP operation
- restore back powermode */
- handlePostDhcpSetup();
-
/*
* stop DHCP
*/
if (mDhcpStateMachine != null) {
+ /* In case we were in middle of DHCP operation
+ restore back powermode */
+ handlePostDhcpSetup();
+
mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP);
mDhcpStateMachine.quit();
mDhcpStateMachine = null;
@@ -2395,6 +2395,10 @@ public class WifiStateMachine extends StateMachine {
public void enter() {
if (DBG) log(getName() + "\n");
EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+
+ /* Send any reset commands to supplicant before shutting it down */
+ handleNetworkDisconnect();
+
if (DBG) log("stopping supplicant");
if (!mWifiNative.stopSupplicant()) {
loge("Failed to stop supplicant");
@@ -2405,7 +2409,6 @@ public class WifiStateMachine extends StateMachine {
++mSupplicantStopFailureToken, 0), SUPPLICANT_RESTART_INTERVAL_MSECS);
mNetworkInfo.setIsAvailable(false);
- handleNetworkDisconnect();
setWifiState(WIFI_STATE_DISABLING);
sendSupplicantConnectionChangedBroadcast(false);
mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);