summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.mk4
-rw-r--r--CleanSpec.mk1
-rw-r--r--api/current.txt17
-rw-r--r--cmds/app_process/app_main.cpp61
-rw-r--r--cmds/installd/commands.c11
-rw-r--r--cmds/runtime/main_runtime.cpp39
-rw-r--r--cmds/stagefright/stream.cpp2
-rw-r--r--cmds/system_server/library/system_init.cpp28
-rw-r--r--core/java/android/app/ActivityManager.java61
-rw-r--r--core/java/android/app/ActivityManagerNative.java50
-rw-r--r--core/java/android/app/ActivityThread.java12
-rw-r--r--core/java/android/app/ApplicationThreadNative.java6
-rw-r--r--core/java/android/app/BackStackRecord.java48
-rw-r--r--core/java/android/app/Fragment.java37
-rw-r--r--core/java/android/app/FragmentManager.java97
-rw-r--r--core/java/android/app/FragmentTransaction.java25
-rw-r--r--core/java/android/app/IActivityManager.java6
-rw-r--r--core/java/android/app/IApplicationThread.java4
-rw-r--r--core/java/android/app/ListFragment.java6
-rw-r--r--core/java/android/app/Service.java20
-rw-r--r--core/java/android/bluetooth/BluetoothDeviceProfileState.java48
-rw-r--r--core/java/android/bluetooth/BluetoothProfileState.java18
-rw-r--r--core/java/android/content/pm/PackageParser.java7
-rw-r--r--core/java/android/content/pm/ServiceInfo.java20
-rw-r--r--core/java/android/hardware/Camera.java129
-rw-r--r--core/java/android/nfc/ApduList.aidl19
-rw-r--r--core/java/android/nfc/ApduList.java68
-rwxr-xr-xcore/java/android/nfc/INfcAdapterExtras.aidl6
-rw-r--r--core/java/android/os/BatteryStats.java497
-rw-r--r--core/java/android/os/ParcelFileDescriptor.java67
-rw-r--r--core/java/android/os/Process.java2
-rw-r--r--core/java/android/os/RecoverySystem.java7
-rw-r--r--core/java/android/provider/Settings.java7
-rw-r--r--core/java/android/speech/tts/BlockingMediaPlayer.java146
-rw-r--r--core/java/android/speech/tts/FileSynthesisRequest.java251
-rwxr-xr-xcore/java/android/speech/tts/ITextToSpeechCallback.aidl (renamed from core/java/android/speech/tts/ITtsCallback.aidl)8
-rw-r--r--core/java/android/speech/tts/ITextToSpeechService.aidl140
-rwxr-xr-xcore/java/android/speech/tts/ITts.aidl69
-rw-r--r--core/java/android/speech/tts/PlaybackSynthesisRequest.java274
-rw-r--r--core/java/android/speech/tts/SynthesisRequest.java193
-rwxr-xr-xcore/java/android/speech/tts/TextToSpeech.java1200
-rw-r--r--core/java/android/speech/tts/TextToSpeechService.java714
-rw-r--r--core/java/android/text/CharSequenceIterator.java29
-rw-r--r--core/java/android/text/TextUtils.java7
-rw-r--r--core/java/android/text/method/ArrowKeyMovementMethod.java6
-rw-r--r--core/java/android/text/style/SuggestionSpan.java4
-rw-r--r--core/java/android/view/inputmethod/InputMethodManager.java50
-rw-r--r--core/java/android/webkit/webdriver/By.java209
-rw-r--r--core/java/android/webkit/webdriver/WebDriver.java526
-rw-r--r--core/java/android/webkit/webdriver/WebElement.java136
-rw-r--r--core/java/android/webkit/webdriver/WebElementNotFoundException.java41
-rw-r--r--core/java/android/webkit/webdriver/WebElementStaleException.java42
-rw-r--r--core/java/android/webkit/webdriver/WebchromeClientWrapper.java193
-rw-r--r--core/java/android/widget/FrameLayout.java3
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java243
-rw-r--r--core/java/com/android/internal/util/IState.java (renamed from core/java/com/android/internal/util/HierarchicalState.java)51
-rw-r--r--core/java/com/android/internal/util/State.java74
-rw-r--r--core/java/com/android/internal/util/StateMachine.java (renamed from core/java/com/android/internal/util/HierarchicalStateMachine.java)250
-rw-r--r--core/java/com/android/internal/view/IInputMethodManager.aidl1
-rw-r--r--core/jni/AndroidRuntime.cpp202
-rw-r--r--core/jni/android/graphics/Bitmap.cpp1
-rw-r--r--core/jni/android/graphics/BitmapFactory.cpp71
-rw-r--r--core/jni/android/graphics/BitmapRegionDecoder.cpp24
-rw-r--r--core/jni/android/graphics/Camera.cpp2
-rw-r--r--core/jni/android/graphics/Canvas.cpp60
-rw-r--r--core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp63
-rw-r--r--core/jni/android/graphics/Graphics.cpp37
-rw-r--r--core/jni/android/graphics/Interpolator.cpp5
-rw-r--r--core/jni/android/graphics/LayerRasterizer.cpp4
-rw-r--r--core/jni/android/graphics/MaskFilter.cpp8
-rw-r--r--core/jni/android/graphics/Movie.cpp7
-rw-r--r--core/jni/android/graphics/NinePatch.cpp1
-rw-r--r--core/jni/android/graphics/PathEffect.cpp20
-rw-r--r--core/jni/android/graphics/Region.cpp31
-rw-r--r--core/jni/android/graphics/Shader.cpp22
-rw-r--r--core/jni/android/graphics/TextLayout.h34
-rw-r--r--core/jni/android/graphics/TextLayoutCache.cpp143
-rw-r--r--core/jni/android/graphics/TextLayoutCache.h4
-rw-r--r--core/jni/android/graphics/Typeface.cpp27
-rw-r--r--core/jni/android/graphics/YuvToJpegEncoder.cpp1
-rw-r--r--core/jni/android_backup_BackupDataInput.cpp17
-rw-r--r--core/jni/android_backup_BackupDataOutput.cpp15
-rw-r--r--core/jni/android_backup_BackupHelperDispatcher.cpp29
-rw-r--r--core/jni/android_backup_FileBackupHelperBase.cpp17
-rw-r--r--core/jni/android_content_res_ObbScanner.cpp2
-rw-r--r--core/jni/android_database_SQLiteStatement.cpp2
-rw-r--r--core/jni/android_emoji_EmojiFactory.cpp31
-rw-r--r--core/jni/android_hardware_UsbDevice.cpp7
-rw-r--r--core/jni/android_hardware_UsbDeviceConnection.cpp2
-rw-r--r--core/jni/android_media_JetPlayer.cpp2
-rw-r--r--core/jni/android_net_NetUtils.cpp19
-rw-r--r--core/jni/android_net_TrafficStats.cpp14
-rw-r--r--core/jni/android_net_wifi_Wifi.cpp414
-rw-r--r--core/jni/android_nio_utils.cpp9
-rw-r--r--core/jni/android_opengl_GLES10.cpp186
-rw-r--r--core/jni/android_opengl_GLES10Ext.cpp65
-rw-r--r--core/jni/android_opengl_GLES11.cpp236
-rw-r--r--core/jni/android_opengl_GLES11Ext.cpp236
-rw-r--r--core/jni/android_opengl_GLES20.cpp398
-rw-r--r--core/jni/android_os_FileUtils.cpp27
-rw-r--r--core/jni/android_os_MemoryFile.cpp9
-rw-r--r--core/jni/android_os_ParcelFileDescriptor.cpp75
-rw-r--r--core/jni/android_pim_EventRecurrence.cpp6
-rw-r--r--core/jni/android_text_AndroidBidi.cpp23
-rw-r--r--core/jni/android_text_AndroidCharacter.cpp3
-rw-r--r--core/jni/android_util_AssetManager.cpp2
-rw-r--r--core/jni/android_util_Binder.cpp63
-rw-r--r--core/jni/android_util_Binder.h17
-rw-r--r--core/jni/android_util_EventLog.cpp3
-rw-r--r--core/jni/android_util_Process.cpp16
-rw-r--r--core/jni/android_view_GLES20Canvas.cpp10
-rw-r--r--core/jni/com_android_internal_graphics_NativeUtils.cpp5
-rw-r--r--core/jni/com_google_android_gles_jni_EGLImpl.cpp44
-rw-r--r--core/jni/com_google_android_gles_jni_GLImpl.cpp558
-rw-r--r--core/res/AndroidManifest.xml7
-rw-r--r--core/res/res/raw/execute_script_android.js8
-rw-r--r--core/res/res/raw/find_element_android.js26
-rw-r--r--core/res/res/raw/find_elements_android.js26
-rw-r--r--core/res/res/raw/get_attribute_value_android.js11
-rw-r--r--core/res/res/raw/get_size_android.js11
-rw-r--r--core/res/res/raw/get_text_android.js19
-rw-r--r--core/res/res/raw/get_top_left_coordinates_android.js18
-rw-r--r--core/res/res/raw/get_value_of_css_property_android.js10
-rw-r--r--core/res/res/raw/is_enabled_android.js12
-rw-r--r--core/res/res/raw/is_selected_android.js10
-rw-r--r--core/res/res/raw/set_selected_android.js26
-rw-r--r--core/res/res/raw/toggle_android.js29
-rw-r--r--core/res/res/raw/webdriver_readme.txt37
-rw-r--r--core/res/res/values-ar/strings.xml4
-rw-r--r--core/res/res/values-bg/strings.xml4
-rw-r--r--core/res/res/values-ca/strings.xml4
-rw-r--r--core/res/res/values-cs/strings.xml4
-rw-r--r--core/res/res/values-da/strings.xml4
-rw-r--r--core/res/res/values-de/strings.xml12
-rw-r--r--core/res/res/values-el/strings.xml4
-rw-r--r--core/res/res/values-en-rGB/strings.xml4
-rw-r--r--core/res/res/values-es-rUS/strings.xml4
-rw-r--r--core/res/res/values-es/strings.xml4
-rw-r--r--core/res/res/values-fa/strings.xml4
-rw-r--r--core/res/res/values-fi/strings.xml4
-rw-r--r--core/res/res/values-fr/strings.xml4
-rw-r--r--core/res/res/values-hr/strings.xml4
-rw-r--r--core/res/res/values-hu/strings.xml4
-rw-r--r--core/res/res/values-in/strings.xml4
-rw-r--r--core/res/res/values-it/strings.xml4
-rw-r--r--core/res/res/values-iw/strings.xml4
-rw-r--r--core/res/res/values-ja/strings.xml4
-rw-r--r--core/res/res/values-ko/strings.xml4
-rw-r--r--core/res/res/values-lt/strings.xml4
-rw-r--r--core/res/res/values-lv/strings.xml4
-rw-r--r--core/res/res/values-nb/strings.xml4
-rw-r--r--core/res/res/values-nl/strings.xml4
-rw-r--r--core/res/res/values-pl/strings.xml4
-rw-r--r--core/res/res/values-pt-rPT/strings.xml4
-rw-r--r--core/res/res/values-pt/strings.xml4
-rw-r--r--core/res/res/values-rm/strings.xml4
-rw-r--r--core/res/res/values-ro/strings.xml4
-rw-r--r--core/res/res/values-ru/strings.xml4
-rw-r--r--core/res/res/values-sk/strings.xml4
-rw-r--r--core/res/res/values-sl/strings.xml4
-rw-r--r--core/res/res/values-sr/strings.xml4
-rw-r--r--core/res/res/values-sv/strings.xml4
-rw-r--r--core/res/res/values-th/strings.xml4
-rw-r--r--core/res/res/values-tl/strings.xml4
-rw-r--r--core/res/res/values-tr/strings.xml4
-rw-r--r--core/res/res/values-uk/strings.xml4
-rw-r--r--core/res/res/values-vi/strings.xml4
-rw-r--r--core/res/res/values-zh-rCN/strings.xml4
-rw-r--r--core/res/res/values-zh-rTW/strings.xml4
-rw-r--r--core/res/res/values/attrs_manifest.xml4
-rw-r--r--core/res/res/values/public.xml1
-rwxr-xr-xcore/res/res/values/strings.xml7
-rw-r--r--core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java1
-rw-r--r--core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java47
-rw-r--r--core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java35
-rw-r--r--core/tests/coretests/src/com/android/internal/util/StateMachineTest.java (renamed from core/tests/coretests/src/com/android/internal/util/HierarchicalStateMachineTest.java)376
-rw-r--r--core/tests/overlaytests/Android.mk4
-rw-r--r--core/tests/overlaytests/OverlayTest/Android.mk10
-rw-r--r--core/tests/overlaytests/OverlayTest/AndroidManifest.xml10
-rw-r--r--core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java118
-rw-r--r--core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithOverlayTest.java7
-rw-r--r--core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithoutOverlayTest.java7
-rw-r--r--core/tests/overlaytests/OverlayTestOverlay/Android.mk14
-rw-r--r--core/tests/overlaytests/OverlayTestOverlay/AndroidManifest.xml6
-rw-r--r--core/tests/overlaytests/OverlayTestOverlay/res/drawable/default_wallpaper.jpgbin0 -> 399 bytes
-rw-r--r--core/tests/overlaytests/OverlayTestOverlay/res/values-sv/config.xml4
-rw-r--r--core/tests/overlaytests/OverlayTestOverlay/res/values/config.xml13
-rw-r--r--core/tests/overlaytests/README15
-rwxr-xr-xcore/tests/overlaytests/runtests.sh89
-rw-r--r--docs/html/guide/developing/tools/logcat.jd3
-rwxr-xr-xdocs/html/guide/market/billing/billing_admin.jd2
-rwxr-xr-xdocs/html/guide/market/billing/billing_integrate.jd6
-rw-r--r--docs/html/guide/practices/design/accessibility.jd14
-rw-r--r--docs/html/guide/practices/design/jni.jd715
-rw-r--r--docs/html/guide/practices/design/performance.jd3
-rw-r--r--docs/html/guide/publishing/licensing.jd8
-rw-r--r--docs/html/guide/topics/fundamentals/tasks-and-back-stack.jd8
-rw-r--r--docs/html/guide/webapps/targeting.jd6
-rw-r--r--docs/html/sdk/download.jd91
-rw-r--r--docs/html/sdk/older_releases.jd42
-rw-r--r--docs/html/sdk/terms_body.html336
-rw-r--r--include/android_runtime/AndroidRuntime.h27
-rw-r--r--include/binder/Parcel.h3
-rw-r--r--include/camera/CameraParameters.h38
-rw-r--r--include/gui/SurfaceTexture.h31
-rw-r--r--include/gui/SurfaceTextureClient.h22
-rw-r--r--include/media/IMediaPlayerClient.h2
-rw-r--r--include/media/MediaPlayerInterface.h8
-rw-r--r--include/media/mediaplayer.h5
-rw-r--r--include/surfaceflinger/IGraphicBufferAlloc.h10
-rw-r--r--include/tts/TtsEngine.h232
-rw-r--r--include/utils/AssetManager.h11
-rw-r--r--include/utils/ResourceTypes.h26
-rw-r--r--libs/binder/Parcel.cpp24
-rw-r--r--libs/camera/CameraParameters.cpp2
-rw-r--r--libs/gui/IGraphicBufferAlloc.cpp39
-rw-r--r--libs/gui/SurfaceTexture.cpp86
-rw-r--r--libs/gui/SurfaceTextureClient.cpp65
-rw-r--r--libs/rs/driver/rsdBcc.cpp2
-rw-r--r--libs/usb/src/com/android/future/usb/UsbManager.java4
-rw-r--r--libs/utils/AssetManager.cpp237
-rw-r--r--libs/utils/README275
-rw-r--r--libs/utils/ResourceTypes.cpp404
-rw-r--r--media/java/android/media/AudioService.java89
-rw-r--r--media/java/android/media/MediaPlayer.java40
-rw-r--r--media/jni/android_media_MediaMetadataRetriever.cpp2
-rw-r--r--media/jni/android_media_MediaPlayer.cpp21
-rw-r--r--media/jni/android_media_MediaRecorder.cpp10
-rw-r--r--media/jni/android_media_MediaScanner.cpp8
-rw-r--r--media/jni/soundpool/android_media_SoundPool.cpp2
-rw-r--r--media/libmedia/IMediaPlayerClient.cpp12
-rw-r--r--media/libmedia/mediaplayer.cpp7
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.cpp8
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.h6
-rw-r--r--media/libstagefright/AwesomePlayer.cpp77
-rw-r--r--media/libstagefright/MPEG4Extractor.cpp91
-rw-r--r--media/libstagefright/SampleTable.cpp159
-rw-r--r--media/libstagefright/StagefrightMetadataRetriever.cpp3
-rw-r--r--media/libstagefright/include/AwesomePlayer.h5
-rw-r--r--media/libstagefright/include/MPEG4Extractor.h2
-rw-r--r--media/libstagefright/include/SampleTable.h12
-rw-r--r--native/include/android/tts.h313
-rw-r--r--nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java17
-rw-r--r--opengl/java/android/opengl/GLES10.java29
-rw-r--r--opengl/java/android/opengl/GLES10Ext.java29
-rw-r--r--opengl/java/android/opengl/GLES11.java29
-rw-r--r--opengl/java/android/opengl/GLES11Ext.java29
-rw-r--r--opengl/java/android/opengl/GLES20.java29
-rw-r--r--opengl/java/com/google/android/gles_jni/GLImpl.java31
-rw-r--r--opengl/java/javax/microedition/khronos/opengles/GL.java31
-rw-r--r--opengl/java/javax/microedition/khronos/opengles/GL10.java31
-rw-r--r--opengl/java/javax/microedition/khronos/opengles/GL10Ext.java31
-rw-r--r--opengl/java/javax/microedition/khronos/opengles/GL11.java31
-rw-r--r--opengl/java/javax/microedition/khronos/opengles/GL11Ext.java31
-rw-r--r--opengl/java/javax/microedition/khronos/opengles/GL11ExtensionPack.java31
-rw-r--r--opengl/libs/Android.mk4
-rw-r--r--opengl/libs/EGL/egl.cpp51
-rw-r--r--opengl/libs/GLES2_dbg/Android.mk7
-rwxr-xr-xopengl/libs/GLES2_dbg/generate_api_cpp.py61
-rwxr-xr-xopengl/libs/GLES2_dbg/generate_caller_cpp.py1
-rwxr-xr-xopengl/libs/GLES2_dbg/generate_debugger_message_proto.py39
-rw-r--r--opengl/libs/GLES2_dbg/src/api.cpp77
-rw-r--r--opengl/libs/GLES2_dbg/src/api.h26
-rw-r--r--opengl/libs/GLES2_dbg/src/caller.cpp3
-rw-r--r--opengl/libs/GLES2_dbg/src/caller.h18
-rw-r--r--opengl/libs/GLES2_dbg/src/dbgcontext.cpp65
-rw-r--r--opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp92
-rw-r--r--opengl/libs/GLES2_dbg/src/debugger_message.pb.h88
-rw-r--r--opengl/libs/GLES2_dbg/src/egl.cpp17
-rw-r--r--opengl/libs/GLES2_dbg/src/header.h28
-rw-r--r--opengl/libs/GLES2_dbg/src/server.cpp88
-rw-r--r--opengl/libs/GLES2_dbg/src/vertex.cpp141
-rw-r--r--opengl/libs/egl_tls.h40
-rw-r--r--opengl/libs/glesv2dbg.h25
-rwxr-xr-xopengl/tools/glgen/gen2
-rw-r--r--opengl/tools/glgen/src/JniCodeEmitter.java206
-rw-r--r--opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp49
-rw-r--r--opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp52
-rw-r--r--opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp52
-rw-r--r--opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp52
-rw-r--r--opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp52
-rw-r--r--opengl/tools/glgen/stubs/gles11/glGetProgramInfoLog.cpp34
-rw-r--r--opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.cpp34
-rw-r--r--opengl/tools/glgen/stubs/gles11/glGetString.cpp12
-rw-r--r--opengl/tools/glgen/stubs/gles11/glShaderSource.cpp2
-rw-r--r--opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp54
-rw-r--r--opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl4
-rw-r--r--opengl/tools/glgen/stubs/jsr239/glGetString.cpp12
-rw-r--r--packages/SystemUI/src/com/android/systemui/recent/RecentApplicationsActivity.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java3
-rw-r--r--packages/TtsService/Android.mk15
-rwxr-xr-xpackages/TtsService/AndroidManifest.xml17
-rw-r--r--packages/TtsService/MODULE_LICENSE_APACHE20
-rw-r--r--packages/TtsService/NOTICE190
-rwxr-xr-xpackages/TtsService/jni/Android.mk30
-rw-r--r--packages/TtsService/jni/android_tts_SynthProxy.cpp1071
-rw-r--r--packages/TtsService/proguard.flags5
-rw-r--r--packages/TtsService/res/drawable-hdpi/ic_launcher_text_to_speech.pngbin6931 -> 0 bytes
-rw-r--r--packages/TtsService/res/drawable-mdpi/ic_launcher_text_to_speech.pngbin6809 -> 0 bytes
-rwxr-xr-xpackages/TtsService/src/android/tts/SynthProxy.java238
-rwxr-xr-xpackages/TtsService/src/android/tts/TtsService.java1503
-rw-r--r--policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java25
-rw-r--r--services/audioflinger/AudioResampler.cpp8
-rw-r--r--services/input/Android.mk4
-rw-r--r--services/input/InputReader.h4
-rw-r--r--services/input/PointerController.cpp212
-rw-r--r--services/input/PointerController.h26
-rw-r--r--services/input/SpotController.cpp45
-rw-r--r--services/input/SpotController.h71
-rw-r--r--services/input/SpriteController.cpp472
-rw-r--r--services/input/SpriteController.h251
-rw-r--r--services/input/tests/InputReader_test.cpp4
-rw-r--r--services/java/com/android/server/InputMethodManagerService.java18
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java352
-rw-r--r--services/java/com/android/server/am/ActivityStack.java228
-rw-r--r--services/java/com/android/server/am/BatteryStatsService.java13
-rw-r--r--services/java/com/android/server/am/ProcessRecord.java6
-rw-r--r--services/java/com/android/server/am/ServiceRecord.java20
-rw-r--r--services/java/com/android/server/am/TaskAccessInfo.java35
-rw-r--r--services/java/com/android/server/connectivity/Tethering.java49
-rw-r--r--services/java/com/android/server/pm/Settings.java13
-rw-r--r--services/jni/com_android_server_AlarmManagerService.cpp32
-rw-r--r--services/jni/com_android_server_InputManager.cpp34
-rw-r--r--services/jni/com_android_server_UsbService.cpp29
-rw-r--r--services/surfaceflinger/DisplayHardware/DisplayHardware.cpp10
-rw-r--r--services/surfaceflinger/DisplayHardware/DisplayHardware.h2
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp13
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h6
-rw-r--r--telephony/java/com/android/internal/telephony/DataConnection.java50
-rw-r--r--telephony/java/com/android/internal/telephony/DataConnectionTracker.java28
-rw-r--r--telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java4
-rw-r--r--telephony/java/com/android/internal/telephony/Phone.java11
-rw-r--r--telephony/java/com/android/internal/telephony/PhoneBase.java9
-rw-r--r--telephony/java/com/android/internal/telephony/PhoneFactory.java33
-rw-r--r--telephony/java/com/android/internal/telephony/PhoneProxy.java8
-rw-r--r--telephony/java/com/android/internal/telephony/RIL.java63
-rw-r--r--telephony/java/com/android/internal/telephony/RILConstants.java2
-rw-r--r--telephony/java/com/android/internal/telephony/ServiceStateTracker.java4
-rw-r--r--telephony/java/com/android/internal/telephony/cat/RilMessageDecoder.java16
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java5
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java30
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java254
-rwxr-xr-xtelephony/java/com/android/internal/telephony/gsm/SIMRecords.java14
-rw-r--r--tests/ActivityTests/AndroidManifest.xml2
-rw-r--r--tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java74
-rw-r--r--tests/BiDiTests/AndroidManifest.xml3
-rw-r--r--tests/BiDiTests/res/values/strings.xml3
-rw-r--r--tests/BiDiTests/src/com/android/bidi/BiDiTestView.java28
-rw-r--r--tools/aapt/Bundle.h4
-rw-r--r--tools/aapt/Main.cpp5
-rw-r--r--tools/aapt/ResourceTable.cpp4
-rw-r--r--wifi/java/android/net/wifi/SupplicantStateTracker.java38
-rw-r--r--wifi/java/android/net/wifi/WifiStateMachine.java116
-rw-r--r--wifi/java/android/net/wifi/WpsStateMachine.java18
354 files changed, 13031 insertions, 9184 deletions
diff --git a/Android.mk b/Android.mk
index 28340cf75a33..cd9ae7d07734 100644
--- a/Android.mk
+++ b/Android.mk
@@ -137,8 +137,8 @@ LOCAL_SRC_FILES += \
core/java/android/view/IWindowSession.aidl \
core/java/android/speech/IRecognitionListener.aidl \
core/java/android/speech/IRecognitionService.aidl \
- core/java/android/speech/tts/ITts.aidl \
- core/java/android/speech/tts/ITtsCallback.aidl \
+ core/java/android/speech/tts/ITextToSpeechCallback.aidl \
+ core/java/android/speech/tts/ITextToSpeechService.aidl \
core/java/com/android/internal/app/IBatteryStats.aidl \
core/java/com/android/internal/app/IUsageStats.aidl \
core/java/com/android/internal/app/IMediaContainerService.aidl \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 023ce59b9bc1..50292e4e3ddf 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -96,6 +96,7 @@ $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/PerfTest_interme
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/RSTest_intermediates/)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/hardware/IUsbManager.java)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/nfc)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/api/current.txt b/api/current.txt
index e946c060625c..975444ef44aa 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -87,6 +87,7 @@ package android {
field public static final java.lang.String RECEIVE_SMS = "android.permission.RECEIVE_SMS";
field public static final java.lang.String RECEIVE_WAP_PUSH = "android.permission.RECEIVE_WAP_PUSH";
field public static final java.lang.String RECORD_AUDIO = "android.permission.RECORD_AUDIO";
+ field public static final java.lang.String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
field public static final java.lang.String REORDER_TASKS = "android.permission.REORDER_TASKS";
field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES";
field public static final java.lang.String SEND_SMS = "android.permission.SEND_SMS";
@@ -855,6 +856,7 @@ package android {
field public static final int state_window_focused = 16842909; // 0x101009d
field public static final int staticWallpaperPreview = 16843569; // 0x1010331
field public static final int stepSize = 16843078; // 0x1010146
+ field public static final int stopWithTask = 16843623; // 0x1010367
field public static final int streamType = 16843273; // 0x1010209
field public static final int stretchColumns = 16843081; // 0x1010149
field public static final int stretchMode = 16843030; // 0x1010116
@@ -929,9 +931,9 @@ package android {
field public static final int textEditPasteWindowLayout = 16843540; // 0x1010314
field public static final int textEditSideNoPasteWindowLayout = 16843615; // 0x101035f
field public static final int textEditSidePasteWindowLayout = 16843614; // 0x101035e
- field public static final int textEditSuggestionItemLayout = 16843626; // 0x101036a
- field public static final int textEditSuggestionsBottomWindowLayout = 16843624; // 0x1010368
- field public static final int textEditSuggestionsTopWindowLayout = 16843625; // 0x1010369
+ field public static final int textEditSuggestionItemLayout = 16843627; // 0x101036b
+ field public static final int textEditSuggestionsBottomWindowLayout = 16843625; // 0x1010369
+ field public static final int textEditSuggestionsTopWindowLayout = 16843626; // 0x101036a
field public static final int textFilterEnabled = 16843007; // 0x10100ff
field public static final int textIsSelectable = 16843542; // 0x1010316
field public static final int textOff = 16843045; // 0x1010125
@@ -943,7 +945,7 @@ package android {
field public static final int textSelectHandleWindowStyle = 16843464; // 0x10102c8
field public static final int textSize = 16842901; // 0x1010095
field public static final int textStyle = 16842903; // 0x1010097
- field public static final int textSuggestionsWindowStyle = 16843623; // 0x1010367
+ field public static final int textSuggestionsWindowStyle = 16843624; // 0x1010368
field public static final int textViewStyle = 16842884; // 0x1010084
field public static final int theme = 16842752; // 0x1010000
field public static final int thickness = 16843360; // 0x1010260
@@ -2849,6 +2851,7 @@ package android.app {
method public void onSaveInstanceState(android.os.Bundle);
method public void onStart();
method public void onStop();
+ method public void onViewCreated(android.view.View, android.os.Bundle);
method public void registerForContextMenu(android.view.View);
method public void setArguments(android.os.Bundle);
method public void setHasOptionsMenu(boolean);
@@ -2921,8 +2924,10 @@ package android.app {
method public abstract android.app.FragmentTransaction add(int, android.app.Fragment);
method public abstract android.app.FragmentTransaction add(int, android.app.Fragment, java.lang.String);
method public abstract android.app.FragmentTransaction addToBackStack(java.lang.String);
+ method public abstract android.app.FragmentTransaction attach(android.app.Fragment);
method public abstract int commit();
method public abstract int commitAllowingStateLoss();
+ method public abstract android.app.FragmentTransaction detach(android.app.Fragment);
method public abstract android.app.FragmentTransaction disallowAddToBackStack();
method public abstract android.app.FragmentTransaction hide(android.app.Fragment);
method public abstract boolean isAddToBackStackAllowed();
@@ -3384,6 +3389,7 @@ package android.app {
method public void onRebind(android.content.Intent);
method public deprecated void onStart(android.content.Intent, int);
method public int onStartCommand(android.content.Intent, int, int);
+ method public void onTaskRemoved(android.content.Intent);
method public boolean onUnbind(android.content.Intent);
method public final void startForeground(int, android.app.Notification);
method public final void stopForeground(boolean);
@@ -5840,6 +5846,8 @@ package android.content.pm {
method public int describeContents();
method public void dump(android.util.Printer, java.lang.String);
field public static final android.os.Parcelable.Creator CREATOR;
+ field public static final int FLAG_STOP_WITH_TASK = 1; // 0x1
+ field public int flags;
field public java.lang.String permission;
}
@@ -22574,6 +22582,7 @@ package android.view.inputmethod {
method public java.util.List<android.view.inputmethod.InputMethodInfo> getEnabledInputMethodList();
method public java.util.List<android.view.inputmethod.InputMethodSubtype> getEnabledInputMethodSubtypeList(android.view.inputmethod.InputMethodInfo, boolean);
method public java.util.List<android.view.inputmethod.InputMethodInfo> getInputMethodList();
+ method public android.view.inputmethod.InputMethodSubtype getLastInputMethodSubtype();
method public java.util.Map<android.view.inputmethod.InputMethodInfo, java.util.List<android.view.inputmethod.InputMethodSubtype>> getShortcutInputMethodsAndSubtypes();
method public void hideSoftInputFromInputMethod(android.os.IBinder, int);
method public boolean hideSoftInputFromWindow(android.os.IBinder, int);
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 0159eddc0965..371268fb2d45 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -1,8 +1,8 @@
/*
* Main entry of app process.
- *
+ *
* Starts the interpreted runtime, then starts up the application.
- *
+ *
*/
#define LOG_TAG "appproc"
@@ -25,23 +25,13 @@ void app_usage()
"Usage: app_process [java-options] cmd-dir start-class-name [options]\n");
}
-status_t app_init(const char* className, int argc, const char* const argv[])
-{
- LOGV("Entered app_init()!\n");
-
- AndroidRuntime* jr = AndroidRuntime::getRuntime();
- jr->callMain(className, argc, argv);
-
- LOGV("Exiting app_init()!\n");
- return NO_ERROR;
-}
-
class AppRuntime : public AndroidRuntime
{
public:
AppRuntime()
: mParentDir(NULL)
, mClassName(NULL)
+ , mClass(NULL)
, mArgC(0)
, mArgV(NULL)
{
@@ -60,6 +50,35 @@ public:
return mClassName;
}
+ virtual void onVmCreated(JNIEnv* env)
+ {
+ if (mClassName == NULL) {
+ return; // Zygote. Nothing to do here.
+ }
+
+ /*
+ * This is a little awkward because the JNI FindClass call uses the
+ * class loader associated with the native method we're executing in.
+ * If called in onStarted (from RuntimeInit.finishInit because we're
+ * launching "am", for example), FindClass would see that we're calling
+ * from a boot class' native method, and so wouldn't look for the class
+ * we're trying to look up in CLASSPATH. Unfortunately it needs to,
+ * because the "am" classes are not boot classes.
+ *
+ * The easiest fix is to call FindClass here, early on before we start
+ * executing boot class Java code and thereby deny ourselves access to
+ * non-boot classes.
+ */
+ char* slashClassName = toSlashClassName(mClassName);
+ mClass = env->FindClass(slashClassName);
+ if (mClass == NULL) {
+ LOGE("ERROR: could not find class '%s'\n", mClassName);
+ }
+ free(slashClassName);
+
+ mClass = reinterpret_cast<jclass>(env->NewGlobalRef(mClass));
+ }
+
virtual void onStarted()
{
sp<ProcessState> proc = ProcessState::self();
@@ -67,8 +86,9 @@ public:
LOGV("App process: starting thread pool.\n");
proc->startThreadPool();
}
-
- app_init(mClassName, mArgC, mArgV);
+
+ AndroidRuntime* ar = AndroidRuntime::getRuntime();
+ ar->callMain(mClassName, mClass, mArgC, mArgV);
if (ProcessState::self()->supportsProcesses()) {
IPCThreadState::self()->stopProcess();
@@ -81,7 +101,7 @@ public:
if (proc->supportsProcesses()) {
LOGV("App process: starting thread pool.\n");
proc->startThreadPool();
- }
+ }
}
virtual void onExit(int code)
@@ -96,9 +116,10 @@ public:
AndroidRuntime::onExit(code);
}
-
+
const char* mParentDir;
const char* mClassName;
+ jclass mClass;
int mArgC;
const char* const* mArgV;
};
@@ -120,7 +141,7 @@ int main(int argc, const char* const argv[])
// These are global variables in ProcessState.cpp
mArgC = argc;
mArgV = argv;
-
+
mArgLen = 0;
for (int i=0; i<argc; i++) {
mArgLen += strlen(argv[i]) + 1;
@@ -139,7 +160,7 @@ int main(int argc, const char* const argv[])
argv++;
// Everything up to '--' or first non '-' arg goes to the vm
-
+
int i = runtime.addVmArguments(argc, argv);
// Next arg is parent directory
@@ -151,7 +172,7 @@ int main(int argc, const char* const argv[])
if (i < argc) {
arg = argv[i++];
if (0 == strcmp("--zygote", arg)) {
- bool startSystemServer = (i < argc) ?
+ bool startSystemServer = (i < argc) ?
strcmp(argv[i], "--start-system-server") == 0 : false;
setArgv0(argv0, "zygote");
set_process_name("zygote");
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index 9a93137ed6e9..9aa70a458240 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -48,6 +48,11 @@ int install(const char *pkgname, uid_t uid, gid_t gid)
LOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
return -errno;
}
+ if (chmod(pkgdir, 0751) < 0) {
+ LOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
+ unlink(pkgdir);
+ return -errno;
+ }
if (chown(pkgdir, uid, gid) < 0) {
LOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
unlink(pkgdir);
@@ -58,6 +63,12 @@ int install(const char *pkgname, uid_t uid, gid_t gid)
unlink(pkgdir);
return -errno;
}
+ if (chmod(libdir, 0755) < 0) {
+ LOGE("cannot chmod dir '%s': %s\n", libdir, strerror(errno));
+ unlink(libdir);
+ unlink(pkgdir);
+ return -errno;
+ }
if (chown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
LOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
unlink(libdir);
diff --git a/cmds/runtime/main_runtime.cpp b/cmds/runtime/main_runtime.cpp
index 83cb53317028..785e4cc228c9 100644
--- a/cmds/runtime/main_runtime.cpp
+++ b/cmds/runtime/main_runtime.cpp
@@ -12,7 +12,7 @@
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
-#include <utils/Log.h>
+#include <utils/Log.h>
#include <cutils/zygote.h>
#include <cutils/properties.h>
@@ -41,7 +41,7 @@
#undef LOG_TAG
#define LOG_TAG "runtime"
-static const char* ZYGOTE_ARGV[] = {
+static const char* ZYGOTE_ARGV[] = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,3001,3002,3003",
@@ -68,7 +68,6 @@ extern Condition gEventQCondition;
namespace android {
-extern status_t app_init(const char* className);
extern void set_finish_init_func(void (*func)());
@@ -76,7 +75,7 @@ extern void set_finish_init_func(void (*func)());
* This class is used to kill this process (runtime) when the system_server dies.
*/
class GrimReaper : public IBinder::DeathRecipient {
-public:
+public:
GrimReaper() { }
virtual void binderDied(const wp<IBinder>& who)
@@ -170,7 +169,7 @@ LOGI("run() sending FIRST_CALL_TRANSACTION to activity manager");
/*
* Post-system-process initialization.
- *
+ *
* This function continues initialization after the system process
* has been initialized. It needs to be separate because the system
* initialization needs to care of starting the Android runtime if it is not
@@ -210,17 +209,17 @@ static bool contextChecker(
static void boot_init()
{
LOGI("Entered boot_init()!\n");
-
+
sp<ProcessState> proc(ProcessState::self());
LOGD("ProcessState: %p\n", proc.get());
proc->becomeContextManager(contextChecker, NULL);
-
+
if (proc->supportsProcesses()) {
LOGI("Binder driver opened. Multiprocess enabled.\n");
} else {
LOGI("Binder driver not found. Processes not supported.\n");
}
-
+
sp<BServiceManager> sm = new BServiceManager;
proc->setContextObject(sm);
}
@@ -258,7 +257,7 @@ static void validateTime()
int res;
time_t min_time = 1167652800; // jan 1 2007, type 'date -ud "1/1 12:00" +%s' to get value for current year
struct timespec ts;
-
+
fd = open("/dev/alarm", O_RDWR);
if(fd < 0) {
LOGW("Unable to open alarm driver: %s\n", strerror(errno));
@@ -346,14 +345,14 @@ int main(int argc, char* const argv[])
int ic;
int result = 1;
pid_t systemPid;
-
+
sp<ProcessState> proc;
#ifndef HAVE_ANDROID_OS
/* Set stdout/stderr to unbuffered for MinGW/MSYS. */
//setvbuf(stdout, NULL, _IONBF, 0);
//setvbuf(stderr, NULL, _IONBF, 0);
-
+
LOGI("commandline args:\n");
for (int i = 0; i < argc; i++)
LOGI(" %2d: '%s'\n", i, argv[i]);
@@ -455,7 +454,7 @@ int main(int argc, char* const argv[])
#if 0
// Hack to keep libc from beating the filesystem to death. It's
- // hitting /etc/localtime frequently,
+ // hitting /etc/localtime frequently,
//
// This statement locks us into Pacific time. We could do better,
// but there's not much point until we're sure that the library
@@ -467,15 +466,15 @@ int main(int argc, char* const argv[])
/* track our progress through the boot sequence */
const int LOG_BOOT_PROGRESS_START = 3000;
- LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,
+ LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,
ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
validateTime();
proc = ProcessState::self();
-
+
boot_init();
-
+
/* If we are in multiprocess mode, have zygote spawn the system
* server process and call system_init(). If we are running in
* single process mode just call system_init() directly.
@@ -488,8 +487,8 @@ int main(int argc, char* const argv[])
property_get("log.redirect-stdio", propBuf, "");
logStdio = (strcmp(propBuf, "true") == 0);
- zygote_run_oneshot((int)(!logStdio),
- sizeof(ZYGOTE_ARGV) / sizeof(ZYGOTE_ARGV[0]),
+ zygote_run_oneshot((int)(!logStdio),
+ sizeof(ZYGOTE_ARGV) / sizeof(ZYGOTE_ARGV[0]),
ZYGOTE_ARGV);
//start_process("/system/bin/mediaserver");
@@ -497,7 +496,7 @@ int main(int argc, char* const argv[])
} else {
#ifndef HAVE_ANDROID_OS
QuickRuntime* runt = new QuickRuntime();
- runt->start("com/android/server/SystemServer",
+ runt->start("com/android/server/SystemServer",
false /* spontaneously fork system server from zygote */);
#endif
}
@@ -506,11 +505,11 @@ int main(int argc, char* const argv[])
finish_system_init(proc);
run(proc);
-
+
bail:
if (proc != NULL) {
proc->setContextObject(NULL);
}
-
+
return 0;
}
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
index bb84bd1ab995..be443d0330d6 100644
--- a/cmds/stagefright/stream.cpp
+++ b/cmds/stagefright/stream.cpp
@@ -107,7 +107,7 @@ struct MyClient : public BnMediaPlayerClient {
: mEOS(false) {
}
- virtual void notify(int msg, int ext1, int ext2) {
+ virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) {
Mutex::Autolock autoLock(mLock);
if (msg == MEDIA_ERROR || msg == MEDIA_PLAYBACK_COMPLETE) {
diff --git a/cmds/system_server/library/system_init.cpp b/cmds/system_server/library/system_init.cpp
index a29ba733a0f0..b615764c029f 100644
--- a/cmds/system_server/library/system_init.cpp
+++ b/cmds/system_server/library/system_init.cpp
@@ -37,7 +37,7 @@ namespace android {
* This class is used to kill this process when the runtime dies.
*/
class GrimReaper : public IBinder::DeathRecipient {
-public:
+public:
GrimReaper() { }
virtual void binderDied(const wp<IBinder>& who)
@@ -54,15 +54,15 @@ public:
extern "C" status_t system_init()
{
LOGI("Entered system_init()");
-
+
sp<ProcessState> proc(ProcessState::self());
-
+
sp<IServiceManager> sm = defaultServiceManager();
LOGI("ServiceManager: %p\n", sm.get());
-
+
sp<GrimReaper> grim = new GrimReaper();
sm->asBinder()->linkToDeath(grim, grim.get(), 0);
-
+
char propBuf[PROPERTY_VALUE_MAX];
property_get("system_init.startsurfaceflinger", propBuf, "1");
if (strcmp(propBuf, "1") == 0) {
@@ -97,12 +97,23 @@ extern "C" status_t system_init()
// the beginning of their processes's main(), before calling
// the init function.
LOGI("System server: starting Android runtime.\n");
-
AndroidRuntime* runtime = AndroidRuntime::getRuntime();
LOGI("System server: starting Android services.\n");
- runtime->callStatic("com/android/server/SystemServer", "init2");
-
+ JNIEnv* env = runtime->getJNIEnv();
+ if (env == NULL) {
+ return UNKNOWN_ERROR;
+ }
+ jclass clazz = env->FindClass("com/android/server/SystemServer");
+ if (clazz == NULL) {
+ return UNKNOWN_ERROR;
+ }
+ jmethodID methodId = env->GetStaticMethodID(clazz, "init2", "()V");
+ if (methodId == NULL) {
+ return UNKNOWN_ERROR;
+ }
+ env->CallStaticVoidMethod(clazz, methodId);
+
// If running in our own process, just go into the thread
// pool. Otherwise, call the initialization finished
// func to let this process continue its initilization.
@@ -114,4 +125,3 @@ extern "C" status_t system_init()
}
return NO_ERROR;
}
-
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index ebe403bfe53a..fca6868da0dd 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -205,13 +205,6 @@ public class ActivityManager {
public static final int RECENT_IGNORE_UNAVAILABLE = 0x0002;
/**
- * Flag for use with {@link #getRecentTasks}: also return the thumbnail
- * bitmap (if available) for each recent task.
- * @hide
- */
- public static final int TASKS_GET_THUMBNAILS = 0x0001000;
-
- /**
* Return a list of the tasks that the user has recently launched, with
* the most recent being first and older ones after in order.
*
@@ -241,7 +234,7 @@ public class ActivityManager {
/**
* Information you can retrieve about a particular task that is currently
* "running" in the system. Note that a running task does not mean the
- * given task actual has a process it is actively running in; it simply
+ * given task actually has a process it is actively running in; it simply
* means that the user has gone to it and never closed it, but currently
* the system may have killed its process and is only holding on to its
* last state in order to restart it when the user returns.
@@ -396,6 +389,55 @@ public class ActivityManager {
return getRunningTasks(maxNum, 0, null);
}
+ /**
+ * Remove some end of a task's activity stack that is not part of
+ * the main application. The selected activities will be finished, so
+ * they are no longer part of the main task.
+ *
+ * @param taskId The identifier of the task.
+ * @param subTaskIndex The number of the sub-task; this corresponds
+ * to the index of the thumbnail returned by {@link #getTaskThumbnails(int)}.
+ * @return Returns true if the sub-task was found and was removed.
+ *
+ * @hide
+ */
+ public boolean removeSubTask(int taskId, int subTaskIndex)
+ throws SecurityException {
+ try {
+ return ActivityManagerNative.getDefault().removeSubTask(taskId, subTaskIndex);
+ } catch (RemoteException e) {
+ // System dead, we will be dead too soon!
+ return false;
+ }
+ }
+
+ /**
+ * If set, the process of the root activity of the task will be killed
+ * as part of removing the task.
+ * @hide
+ */
+ public static final int REMOVE_TASK_KILL_PROCESS = 0x0001;
+
+ /**
+ * Completely remove the given task.
+ *
+ * @param taskId Identifier of the task to be removed.
+ * @param flags Additional operational flags. May be 0 or
+ * {@link #REMOVE_TASK_KILL_PROCESS}.
+ * @return Returns true if the given task was found and removed.
+ *
+ * @hide
+ */
+ public boolean removeTask(int taskId, int flags)
+ throws SecurityException {
+ try {
+ return ActivityManagerNative.getDefault().removeTask(taskId, flags);
+ } catch (RemoteException e) {
+ // System dead, we will be dead too soon!
+ return false;
+ }
+ }
+
/** @hide */
public static class TaskThumbnails implements Parcelable {
public Bitmap mainThumbnail;
@@ -405,9 +447,6 @@ public class ActivityManager {
/** @hide */
public IThumbnailRetriever retriever;
- /** @hide Magic for ActivityManagerService. Not marshalled */
- public ArrayList<Bitmap> otherThumbnails;
-
public TaskThumbnails() {
}
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index d41c2d0dca3b..4b09b34c04bd 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1405,6 +1405,28 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
reply.writeInt(result ? 1 : 0);
return true;
}
+
+ case REMOVE_SUB_TASK_TRANSACTION:
+ {
+ data.enforceInterface(IActivityManager.descriptor);
+ int taskId = data.readInt();
+ int subTaskIndex = data.readInt();
+ boolean result = removeSubTask(taskId, subTaskIndex);
+ reply.writeNoException();
+ reply.writeInt(result ? 1 : 0);
+ return true;
+ }
+
+ case REMOVE_TASK_TRANSACTION:
+ {
+ data.enforceInterface(IActivityManager.descriptor);
+ int taskId = data.readInt();
+ int fl = data.readInt();
+ boolean result = removeTask(taskId, fl);
+ reply.writeNoException();
+ reply.writeInt(result ? 1 : 0);
+ return true;
+ }
}
@@ -3162,6 +3184,34 @@ class ActivityManagerProxy implements IActivityManager
data.recycle();
return result;
}
+
+ public boolean removeSubTask(int taskId, int subTaskIndex) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeInt(taskId);
+ data.writeInt(subTaskIndex);
+ mRemote.transact(REMOVE_SUB_TASK_TRANSACTION, data, reply, 0);
+ reply.readException();
+ boolean result = reply.readInt() != 0;
+ reply.recycle();
+ data.recycle();
+ return result;
+ }
+
+ public boolean removeTask(int taskId, int flags) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeInt(taskId);
+ data.writeInt(flags);
+ mRemote.transact(REMOVE_TASK_TRANSACTION, data, reply, 0);
+ reply.readException();
+ boolean result = reply.readInt() != 0;
+ reply.recycle();
+ data.recycle();
+ return result;
+ }
private IBinder mRemote;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 57a79a9224cf..4dfba913c778 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -334,6 +334,7 @@ public final class ActivityThread {
private static final class ServiceArgsData {
IBinder token;
+ boolean taskRemoved;
int startId;
int flags;
Intent args;
@@ -534,10 +535,11 @@ public final class ActivityThread {
queueOrSendMessage(H.UNBIND_SERVICE, s);
}
- public final void scheduleServiceArgs(IBinder token, int startId,
+ public final void scheduleServiceArgs(IBinder token, boolean taskRemoved, int startId,
int flags ,Intent args) {
ServiceArgsData s = new ServiceArgsData();
s.token = token;
+ s.taskRemoved = taskRemoved;
s.startId = startId;
s.flags = flags;
s.args = args;
@@ -2129,7 +2131,13 @@ public final class ActivityThread {
if (data.args != null) {
data.args.setExtrasClassLoader(s.getClassLoader());
}
- int res = s.onStartCommand(data.args, data.flags, data.startId);
+ int res;
+ if (!data.taskRemoved) {
+ res = s.onStartCommand(data.args, data.flags, data.startId);
+ } else {
+ s.onTaskRemoved(data.args);
+ res = Service.START_TASK_REMOVED_COMPLETE;
+ }
QueuedWork.waitToFinish();
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index a82234ea8d1b..0e511f2892ac 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -219,6 +219,7 @@ public abstract class ApplicationThreadNative extends Binder
{
data.enforceInterface(IApplicationThread.descriptor);
IBinder token = data.readStrongBinder();
+ boolean taskRemoved = data.readInt() != 0;
int startId = data.readInt();
int fl = data.readInt();
Intent args;
@@ -227,7 +228,7 @@ public abstract class ApplicationThreadNative extends Binder
} else {
args = null;
}
- scheduleServiceArgs(token, startId, fl, args);
+ scheduleServiceArgs(token, taskRemoved, startId, fl, args);
return true;
}
@@ -688,11 +689,12 @@ class ApplicationThreadProxy implements IApplicationThread {
data.recycle();
}
- public final void scheduleServiceArgs(IBinder token, int startId,
+ public final void scheduleServiceArgs(IBinder token, boolean taskRemoved, int startId,
int flags, Intent args) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
data.writeStrongBinder(token);
+ data.writeInt(taskRemoved ? 1 : 0);
data.writeInt(startId);
data.writeInt(flags);
if (args != null) {
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 850f56a998ac..e5a7980b0c8c 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -173,6 +173,8 @@ final class BackStackRecord extends FragmentTransaction implements
static final int OP_REMOVE = 3;
static final int OP_HIDE = 4;
static final int OP_SHOW = 5;
+ static final int OP_DETACH = 6;
+ static final int OP_ATTACH = 7;
static final class Op {
Op next;
@@ -416,6 +418,32 @@ final class BackStackRecord extends FragmentTransaction implements
return this;
}
+ public FragmentTransaction detach(Fragment fragment) {
+ //if (fragment.mImmediateActivity == null) {
+ // throw new IllegalStateException("Fragment not added: " + fragment);
+ //}
+
+ Op op = new Op();
+ op.cmd = OP_DETACH;
+ op.fragment = fragment;
+ addOp(op);
+
+ return this;
+ }
+
+ public FragmentTransaction attach(Fragment fragment) {
+ //if (fragment.mImmediateActivity == null) {
+ // throw new IllegalStateException("Fragment not added: " + fragment);
+ //}
+
+ Op op = new Op();
+ op.cmd = OP_ATTACH;
+ op.fragment = fragment;
+ addOp(op);
+
+ return this;
+ }
+
public FragmentTransaction setCustomAnimations(int enter, int exit) {
return setCustomAnimations(enter, exit, 0, 0);
}
@@ -589,6 +617,16 @@ final class BackStackRecord extends FragmentTransaction implements
f.mNextAnim = op.enterAnim;
mManager.showFragment(f, mTransition, mTransitionStyle);
} break;
+ case OP_DETACH: {
+ Fragment f = op.fragment;
+ f.mNextAnim = op.exitAnim;
+ mManager.detachFragment(f, mTransition, mTransitionStyle);
+ } break;
+ case OP_ATTACH: {
+ Fragment f = op.fragment;
+ f.mNextAnim = op.enterAnim;
+ mManager.attachFragment(f, mTransition, mTransitionStyle);
+ } break;
default: {
throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
}
@@ -655,6 +693,16 @@ final class BackStackRecord extends FragmentTransaction implements
mManager.hideFragment(f,
FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
} break;
+ case OP_DETACH: {
+ Fragment f = op.fragment;
+ mManager.attachFragment(f,
+ FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
+ } break;
+ case OP_ATTACH: {
+ Fragment f = op.fragment;
+ mManager.detachFragment(f,
+ FragmentManagerImpl.reverseTransit(mTransition), mTransitionStyle);
+ } break;
default: {
throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
}
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 53dc7c8a0c4a..dd158f94fbab 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -52,6 +52,7 @@ final class FragmentState implements Parcelable {
final int mContainerId;
final String mTag;
final boolean mRetainInstance;
+ final boolean mDetached;
final Bundle mArguments;
Bundle mSavedFragmentState;
@@ -66,6 +67,7 @@ final class FragmentState implements Parcelable {
mContainerId = frag.mContainerId;
mTag = frag.mTag;
mRetainInstance = frag.mRetainInstance;
+ mDetached = frag.mDetached;
mArguments = frag.mArguments;
}
@@ -77,6 +79,7 @@ final class FragmentState implements Parcelable {
mContainerId = in.readInt();
mTag = in.readString();
mRetainInstance = in.readInt() != 0;
+ mDetached = in.readInt() != 0;
mArguments = in.readBundle();
mSavedFragmentState = in.readBundle();
}
@@ -103,6 +106,7 @@ final class FragmentState implements Parcelable {
mInstance.mContainerId = mContainerId;
mInstance.mTag = mTag;
mInstance.mRetainInstance = mRetainInstance;
+ mInstance.mDetached = mDetached;
mInstance.mFragmentManager = activity.mFragments;
return mInstance;
@@ -120,6 +124,7 @@ final class FragmentState implements Parcelable {
dest.writeInt(mContainerId);
dest.writeString(mTag);
dest.writeInt(mRetainInstance ? 1 : 0);
+ dest.writeInt(mDetached ? 1 : 0);
dest.writeBundle(mArguments);
dest.writeBundle(mSavedFragmentState);
}
@@ -321,8 +326,9 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
static final int INITIALIZING = 0; // Not yet created.
static final int CREATED = 1; // Created.
static final int ACTIVITY_CREATED = 2; // The activity has finished its creation.
- static final int STARTED = 3; // Created and started, not resumed.
- static final int RESUMED = 4; // Created started and resumed.
+ static final int STOPPED = 3; // Fully created, not started.
+ static final int STARTED = 4; // Created and started, not resumed.
+ static final int RESUMED = 5; // Created started and resumed.
int mState = INITIALIZING;
@@ -404,6 +410,9 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
// from the user.
boolean mHidden;
+ // Set to true when the app has requested that this fragment be detached.
+ boolean mDetached;
+
// If set this fragment would like its instance retained across
// configuration changes.
boolean mRetainInstance;
@@ -511,23 +520,27 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
}
}
- void restoreViewState() {
+ final void restoreViewState() {
if (mSavedViewState != null) {
mView.restoreHierarchyState(mSavedViewState);
mSavedViewState = null;
}
}
- void setIndex(int index) {
+ final void setIndex(int index) {
mIndex = index;
mWho = "android:fragment:" + mIndex;
}
- void clearIndex() {
+ final void clearIndex() {
mIndex = -1;
mWho = null;
}
+ final boolean isInBackStack() {
+ return mBackStackNesting > 0;
+ }
+
/**
* Subclasses can not override equals().
*/
@@ -947,6 +960,19 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
}
/**
+ * Called immediately after {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}
+ * has returned, but before any saved state has been restored in to the view.
+ * This gives subclasses a chance to initialize themselves once
+ * they know their view hierarchy has been completely created. The fragment's
+ * view hierarchy is not however attached to its parent at this point.
+ * @param view The View returned by {@link #onCreateView(LayoutInflater, ViewGroup, Bundle)}.
+ * @param savedInstanceState If non-null, this fragment is being re-constructed
+ * from a previous saved state as given here.
+ */
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ }
+
+ /**
* Called to have the fragment instantiate its user interface view.
* This is optional, and non-graphical fragments can return null (which
* is the default implementation). This will be called between
@@ -1280,6 +1306,7 @@ public class Fragment implements ComponentCallbacks, OnCreateContextMenuListener
writer.print(" mFromLayout="); writer.print(mFromLayout);
writer.print(" mInLayout="); writer.println(mInLayout);
writer.print(prefix); writer.print("mHidden="); writer.print(mHidden);
+ writer.print(" mDetached="); writer.print(mDetached);
writer.print(" mRetainInstance="); writer.print(mRetainInstance);
writer.print(" mRetaining="); writer.print(mRetaining);
writer.print(" mHasMenu="); writer.println(mHasMenu);
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index ab60cf016ba9..0da656fb6419 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -714,13 +714,14 @@ final class FragmentManagerImpl extends FragmentManager {
null, f.mSavedFragmentState);
if (f.mView != null) {
f.mView.setSaveFromParentEnabled(false);
+ if (f.mHidden) f.mView.setVisibility(View.GONE);
f.restoreViewState();
- if (f.mHidden) f.mView.setVisibility(View.GONE);
+ f.onViewCreated(f.mView, f.mSavedFragmentState);
}
}
case Fragment.CREATED:
if (newState > Fragment.CREATED) {
- if (DEBUG) Log.v(TAG, "moveto CONTENT: " + f);
+ if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
if (!f.mFromLayout) {
ViewGroup container = null;
if (f.mContainerId != 0) {
@@ -744,9 +745,10 @@ final class FragmentManagerImpl extends FragmentManager {
anim.start();
}
container.addView(f.mView);
- f.restoreViewState();
}
- if (f.mHidden) f.mView.setVisibility(View.GONE);
+ if (f.mHidden) f.mView.setVisibility(View.GONE);
+ f.restoreViewState();
+ f.onViewCreated(f.mView, f.mSavedFragmentState);
}
}
@@ -756,10 +758,13 @@ final class FragmentManagerImpl extends FragmentManager {
throw new SuperNotCalledException("Fragment " + f
+ " did not call through to super.onActivityCreated()");
}
+ if (f.mView != null) {
+ }
f.mSavedFragmentState = null;
}
case Fragment.ACTIVITY_CREATED:
- if (newState > Fragment.ACTIVITY_CREATED) {
+ case Fragment.STOPPED:
+ if (newState > Fragment.STOPPED) {
if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
f.mCalled = false;
f.onStart();
@@ -803,9 +808,10 @@ final class FragmentManagerImpl extends FragmentManager {
+ " did not call through to super.onStop()");
}
}
+ case Fragment.STOPPED:
case Fragment.ACTIVITY_CREATED:
if (newState < Fragment.ACTIVITY_CREATED) {
- if (DEBUG) Log.v(TAG, "movefrom CONTENT: " + f);
+ if (DEBUG) Log.v(TAG, "movefrom ACTIVITY_CREATED: " + f);
if (f.mView != null) {
// Need to save the current view state if not
// done already.
@@ -971,32 +977,36 @@ final class FragmentManagerImpl extends FragmentManager {
if (mAdded == null) {
mAdded = new ArrayList<Fragment>();
}
- mAdded.add(fragment);
- makeActive(fragment);
if (DEBUG) Log.v(TAG, "add: " + fragment);
- fragment.mAdded = true;
- fragment.mRemoving = false;
- if (fragment.mHasMenu) {
- mNeedMenuInvalidate = true;
- }
- if (moveToStateNow) {
- moveToState(fragment);
+ makeActive(fragment);
+ if (!fragment.mDetached) {
+ mAdded.add(fragment);
+ fragment.mAdded = true;
+ fragment.mRemoving = false;
+ if (fragment.mHasMenu) {
+ mNeedMenuInvalidate = true;
+ }
+ if (moveToStateNow) {
+ moveToState(fragment);
+ }
}
}
public void removeFragment(Fragment fragment, int transition, int transitionStyle) {
if (DEBUG) Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting);
- mAdded.remove(fragment);
- final boolean inactive = fragment.mBackStackNesting <= 0;
- if (fragment.mHasMenu) {
- mNeedMenuInvalidate = true;
- }
- fragment.mAdded = false;
- fragment.mRemoving = true;
- moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED,
- transition, transitionStyle);
- if (inactive) {
- makeInactive(fragment);
+ final boolean inactive = !fragment.isInBackStack();
+ if (!fragment.mDetached || inactive) {
+ mAdded.remove(fragment);
+ if (fragment.mHasMenu) {
+ mNeedMenuInvalidate = true;
+ }
+ fragment.mAdded = false;
+ fragment.mRemoving = true;
+ moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED,
+ transition, transitionStyle);
+ if (inactive) {
+ makeInactive(fragment);
+ }
}
}
@@ -1052,6 +1062,39 @@ final class FragmentManagerImpl extends FragmentManager {
}
}
+ public void detachFragment(Fragment fragment, int transition, int transitionStyle) {
+ if (DEBUG) Log.v(TAG, "detach: " + fragment);
+ if (!fragment.mDetached) {
+ fragment.mDetached = true;
+ if (fragment.mAdded) {
+ // We are not already in back stack, so need to remove the fragment.
+ mAdded.remove(fragment);
+ if (fragment.mHasMenu) {
+ mNeedMenuInvalidate = true;
+ }
+ fragment.mAdded = false;
+ fragment.mRemoving = true;
+ moveToState(fragment, Fragment.CREATED, transition, transitionStyle);
+ }
+ }
+ }
+
+ public void attachFragment(Fragment fragment, int transition, int transitionStyle) {
+ if (DEBUG) Log.v(TAG, "attach: " + fragment);
+ if (fragment.mDetached) {
+ fragment.mDetached = false;
+ if (!fragment.mAdded) {
+ mAdded.add(fragment);
+ fragment.mAdded = true;
+ fragment.mRemoving = false;
+ if (fragment.mHasMenu) {
+ mNeedMenuInvalidate = true;
+ }
+ moveToState(fragment, mCurState, transition, transitionStyle);
+ }
+ }
+ }
+
public Fragment findFragmentById(int id) {
if (mActive != null) {
// First look through added fragments.
@@ -1594,7 +1637,7 @@ final class FragmentManagerImpl extends FragmentManager {
}
public void dispatchStop() {
- moveToState(Fragment.ACTIVITY_CREATED, false);
+ moveToState(Fragment.STOPPED, false);
}
public void dispatchDestroy() {
diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java
index 68600b34ea80..c1f3cd61da1d 100644
--- a/core/java/android/app/FragmentTransaction.java
+++ b/core/java/android/app/FragmentTransaction.java
@@ -87,6 +87,31 @@ public abstract class FragmentTransaction {
public abstract FragmentTransaction show(Fragment fragment);
/**
+ * Detach the given fragment from the UI. This is the same state as
+ * when it is put on the back stack: the fragment is removed from
+ * the UI, however its state is still being actively managed by the
+ * fragment manager. When going into this state its view hierarchy
+ * is destroyed.
+ *
+ * @param fragment The fragment to be detached.
+ *
+ * @return Returns the same FragmentTransaction instance.
+ */
+ public abstract FragmentTransaction detach(Fragment fragment);
+
+ /**
+ * Re-attach a fragment after it had previously been deatched from
+ * the UI with {@link #detach(Fragment)}. This
+ * causes its view hierarchy to be re-created, attached to the UI,
+ * and displayed.
+ *
+ * @param fragment The fragment to be attached.
+ *
+ * @return Returns the same FragmentTransaction instance.
+ */
+ public abstract FragmentTransaction attach(Fragment fragment);
+
+ /**
* @return <code>true</code> if this transaction contains no operations,
* <code>false</code> otherwise.
*/
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 5a15b08a981a..bec697a2a905 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -344,6 +344,10 @@ public interface IActivityManager extends IInterface {
// Multi-user APIs
public boolean switchUser(int userid) throws RemoteException;
+
+ public boolean removeSubTask(int taskId, int subTaskIndex) throws RemoteException;
+
+ public boolean removeTask(int taskId, int flags) throws RemoteException;
/*
* Private non-Binder interfaces
@@ -561,4 +565,6 @@ public interface IActivityManager extends IInterface {
int START_ACTIVITIES_IN_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+121;
int ACTIVITY_SLEPT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+122;
int SWITCH_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+123;
+ int REMOVE_SUB_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+124;
+ int REMOVE_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+125;
}
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 55177a90592a..b29b0885bd02 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -73,8 +73,8 @@ public interface IApplicationThread extends IInterface {
Intent intent, boolean rebind) throws RemoteException;
void scheduleUnbindService(IBinder token,
Intent intent) throws RemoteException;
- void scheduleServiceArgs(IBinder token, int startId, int flags, Intent args)
- throws RemoteException;
+ void scheduleServiceArgs(IBinder token, boolean taskRemoved, int startId,
+ int flags, Intent args) throws RemoteException;
void scheduleStopService(IBinder token) throws RemoteException;
static final int DEBUG_OFF = 0;
static final int DEBUG_ON = 1;
diff --git a/core/java/android/app/ListFragment.java b/core/java/android/app/ListFragment.java
index 6e2f4b6b54d3..a5ee26c9a22f 100644
--- a/core/java/android/app/ListFragment.java
+++ b/core/java/android/app/ListFragment.java
@@ -195,11 +195,11 @@ public class ListFragment extends Fragment {
}
/**
- * Attach to list view once Fragment is ready to run.
+ * Attach to list view once the view hierarchy has been created.
*/
@Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
ensureList();
}
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index 05b9781354d9..c179b3576211 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -371,6 +371,13 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac
public static final int START_REDELIVER_INTENT = 3;
/**
+ * Special constant for reporting that we are done processing
+ * {@link #onTaskRemoved(Intent)}.
+ * @hide
+ */
+ public static final int START_TASK_REMOVED_COMPLETE = 1000;
+
+ /**
* This flag is set in {@link #onStartCommand} if the Intent is a
* re-delivery of a previously delivered intent, because the service
* had previously returned {@link #START_REDELIVER_INTENT} but had been
@@ -500,6 +507,19 @@ public abstract class Service extends ContextWrapper implements ComponentCallbac
}
/**
+ * This is called if the service is currently running and the user has
+ * removed a task that comes from the service's application. If you have
+ * set {@link android.content.pm.ServiceInfo#FLAG_STOP_WITH_TASK ServiceInfo.FLAG_STOP_WITH_TASK}
+ * then you will not receive this callback; instead, the service will simply
+ * be stopped.
+ *
+ * @param rootIntent The original root Intent that was used to launch
+ * the task that is being removed.
+ */
+ public void onTaskRemoved(Intent rootIntent) {
+ }
+
+ /**
* Stop the service, if it was previously started. This is the same as
* calling {@link android.content.Context#stopService} for this particular service.
*
diff --git a/core/java/android/bluetooth/BluetoothDeviceProfileState.java b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
index f4693c21c01d..56f236d164b9 100644
--- a/core/java/android/bluetooth/BluetoothDeviceProfileState.java
+++ b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
@@ -26,8 +26,8 @@ import android.server.BluetoothA2dpService;
import android.server.BluetoothService;
import android.util.Log;
-import com.android.internal.util.HierarchicalState;
-import com.android.internal.util.HierarchicalStateMachine;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
import java.util.Set;
@@ -57,7 +57,7 @@ import java.util.Set;
* Todo(): Write tests for this class, when the Android Mock support is completed.
* @hide
*/
-public final class BluetoothDeviceProfileState extends HierarchicalStateMachine {
+public final class BluetoothDeviceProfileState extends StateMachine {
private static final String TAG = "BluetoothDeviceProfileState";
private static final boolean DBG = false;
@@ -235,16 +235,16 @@ public final class BluetoothDeviceProfileState extends HierarchicalStateMachine
}
}
- private class BondedDevice extends HierarchicalState {
+ private class BondedDevice extends State {
@Override
- protected void enter() {
+ public void enter() {
Log.i(TAG, "Entering ACL Connected state with: " + getCurrentMessage().what);
Message m = new Message();
m.copyFrom(getCurrentMessage());
sendMessageAtFrontOfQueue(m);
}
@Override
- protected boolean processMessage(Message message) {
+ public boolean processMessage(Message message) {
log("ACL Connected State -> Processing Message: " + message.what);
switch(message.what) {
case CONNECT_HFP_OUTGOING:
@@ -353,12 +353,12 @@ public final class BluetoothDeviceProfileState extends HierarchicalStateMachine
}
}
- private class OutgoingHandsfree extends HierarchicalState {
+ private class OutgoingHandsfree extends State {
private boolean mStatus = false;
private int mCommand;
@Override
- protected void enter() {
+ public void enter() {
Log.i(TAG, "Entering OutgoingHandsfree state with: " + getCurrentMessage().what);
mCommand = getCurrentMessage().what;
if (mCommand != CONNECT_HFP_OUTGOING &&
@@ -374,7 +374,7 @@ public final class BluetoothDeviceProfileState extends HierarchicalStateMachine
}
@Override
- protected boolean processMessage(Message message) {
+ public boolean processMessage(Message message) {
log("OutgoingHandsfree State -> Processing Message: " + message.what);
Message deferMsg = new Message();
int command = message.what;
@@ -466,12 +466,12 @@ public final class BluetoothDeviceProfileState extends HierarchicalStateMachine
}
}
- private class IncomingHandsfree extends HierarchicalState {
+ private class IncomingHandsfree extends State {
private boolean mStatus = false;
private int mCommand;
@Override
- protected void enter() {
+ public void enter() {
Log.i(TAG, "Entering IncomingHandsfree state with: " + getCurrentMessage().what);
mCommand = getCurrentMessage().what;
if (mCommand != CONNECT_HFP_INCOMING &&
@@ -487,7 +487,7 @@ public final class BluetoothDeviceProfileState extends HierarchicalStateMachine
}
@Override
- protected boolean processMessage(Message message) {
+ public boolean processMessage(Message message) {
log("IncomingHandsfree State -> Processing Message: " + message.what);
switch(message.what) {
case CONNECT_HFP_OUTGOING:
@@ -546,12 +546,12 @@ public final class BluetoothDeviceProfileState extends HierarchicalStateMachine
}
}
- private class OutgoingA2dp extends HierarchicalState {
+ private class OutgoingA2dp extends State {
private boolean mStatus = false;
private int mCommand;
@Override
- protected void enter() {
+ public void enter() {
Log.i(TAG, "Entering OutgoingA2dp state with: " + getCurrentMessage().what);
mCommand = getCurrentMessage().what;
if (mCommand != CONNECT_A2DP_OUTGOING &&
@@ -567,7 +567,7 @@ public final class BluetoothDeviceProfileState extends HierarchicalStateMachine
}
@Override
- protected boolean processMessage(Message message) {
+ public boolean processMessage(Message message) {
log("OutgoingA2dp State->Processing Message: " + message.what);
Message deferMsg = new Message();
switch(message.what) {
@@ -656,12 +656,12 @@ public final class BluetoothDeviceProfileState extends HierarchicalStateMachine
}
}
- private class IncomingA2dp extends HierarchicalState {
+ private class IncomingA2dp extends State {
private boolean mStatus = false;
private int mCommand;
@Override
- protected void enter() {
+ public void enter() {
Log.i(TAG, "Entering IncomingA2dp state with: " + getCurrentMessage().what);
mCommand = getCurrentMessage().what;
if (mCommand != CONNECT_A2DP_INCOMING &&
@@ -677,7 +677,7 @@ public final class BluetoothDeviceProfileState extends HierarchicalStateMachine
}
@Override
- protected boolean processMessage(Message message) {
+ public boolean processMessage(Message message) {
log("IncomingA2dp State->Processing Message: " + message.what);
switch(message.what) {
case CONNECT_HFP_OUTGOING:
@@ -734,12 +734,12 @@ public final class BluetoothDeviceProfileState extends HierarchicalStateMachine
}
- private class OutgoingHid extends HierarchicalState {
+ private class OutgoingHid extends State {
private boolean mStatus = false;
private int mCommand;
@Override
- protected void enter() {
+ public void enter() {
log("Entering OutgoingHid state with: " + getCurrentMessage().what);
mCommand = getCurrentMessage().what;
if (mCommand != CONNECT_HID_OUTGOING &&
@@ -751,7 +751,7 @@ public final class BluetoothDeviceProfileState extends HierarchicalStateMachine
}
@Override
- protected boolean processMessage(Message message) {
+ public boolean processMessage(Message message) {
log("OutgoingHid State->Processing Message: " + message.what);
Message deferMsg = new Message();
switch(message.what) {
@@ -815,12 +815,12 @@ public final class BluetoothDeviceProfileState extends HierarchicalStateMachine
}
}
- private class IncomingHid extends HierarchicalState {
+ private class IncomingHid extends State {
private boolean mStatus = false;
private int mCommand;
@Override
- protected void enter() {
+ public void enter() {
log("Entering IncomingHid state with: " + getCurrentMessage().what);
mCommand = getCurrentMessage().what;
if (mCommand != CONNECT_HID_INCOMING &&
@@ -832,7 +832,7 @@ public final class BluetoothDeviceProfileState extends HierarchicalStateMachine
}
@Override
- protected boolean processMessage(Message message) {
+ public boolean processMessage(Message message) {
log("IncomingHid State->Processing Message: " + message.what);
Message deferMsg = new Message();
switch(message.what) {
diff --git a/core/java/android/bluetooth/BluetoothProfileState.java b/core/java/android/bluetooth/BluetoothProfileState.java
index 18060a0234d5..98afdb82a8e6 100644
--- a/core/java/android/bluetooth/BluetoothProfileState.java
+++ b/core/java/android/bluetooth/BluetoothProfileState.java
@@ -22,8 +22,8 @@ import android.content.IntentFilter;
import android.os.Message;
import android.util.Log;
-import com.android.internal.util.HierarchicalState;
-import com.android.internal.util.HierarchicalStateMachine;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
/**
* This state machine is used to serialize the connections
@@ -39,7 +39,7 @@ import com.android.internal.util.HierarchicalStateMachine;
* @hide
*/
-public class BluetoothProfileState extends HierarchicalStateMachine {
+public class BluetoothProfileState extends StateMachine {
private static final boolean DBG = true;
private static final String TAG = "BluetoothProfileState";
@@ -101,15 +101,15 @@ public class BluetoothProfileState extends HierarchicalStateMachine {
context.registerReceiver(mBroadcastReceiver, filter);
}
- private class StableState extends HierarchicalState {
+ private class StableState extends State {
@Override
- protected void enter() {
+ public void enter() {
log("Entering Stable State");
mPendingDevice = null;
}
@Override
- protected boolean processMessage(Message msg) {
+ public boolean processMessage(Message msg) {
if (msg.what != TRANSITION_TO_STABLE) {
transitionTo(mPendingCommandState);
}
@@ -117,15 +117,15 @@ public class BluetoothProfileState extends HierarchicalStateMachine {
}
}
- private class PendingCommandState extends HierarchicalState {
+ private class PendingCommandState extends State {
@Override
- protected void enter() {
+ public void enter() {
log("Entering PendingCommandState State");
dispatchMessage(getCurrentMessage());
}
@Override
- protected boolean processMessage(Message msg) {
+ public boolean processMessage(Message msg) {
if (msg.what == TRANSITION_TO_STABLE) {
transitionTo(mStableState);
} else {
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index ebda40ec381b..564f4f4a4618 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2474,6 +2474,13 @@ public class PackageParser {
s.info.permission = str.length() > 0 ? str.toString().intern() : null;
}
+ s.info.flags = 0;
+ if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestService_stopWithTask,
+ false)) {
+ s.info.flags |= ServiceInfo.FLAG_STOP_WITH_TASK;
+ }
+
sa.recycle();
if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) {
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index 087a4fec49c1..612e34574469 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -33,17 +33,35 @@ public class ServiceInfo extends ComponentInfo
*/
public String permission;
+ /**
+ * Bit in {@link #flags}: If set, the service will automatically be
+ * stopped by the system if the user removes a task that is rooted
+ * in one of the application's activities. Set from the
+ * {@link android.R.attr#stopWithTask} attribute.
+ */
+ public static final int FLAG_STOP_WITH_TASK = 0x0001;
+
+ /**
+ * Options that have been set in the service declaration in the
+ * manifest.
+ * These include:
+ * {@link #FLAG_STOP_WITH_TASK}
+ */
+ public int flags;
+
public ServiceInfo() {
}
public ServiceInfo(ServiceInfo orig) {
super(orig);
permission = orig.permission;
+ flags = orig.flags;
}
public void dump(Printer pw, String prefix) {
super.dumpFront(pw, prefix);
pw.println(prefix + "permission=" + permission);
+ pw.println(prefix + "flags=0x" + Integer.toHexString(flags));
}
public String toString() {
@@ -59,6 +77,7 @@ public class ServiceInfo extends ComponentInfo
public void writeToParcel(Parcel dest, int parcelableFlags) {
super.writeToParcel(dest, parcelableFlags);
dest.writeString(permission);
+ dest.writeInt(flags);
}
public static final Creator<ServiceInfo> CREATOR =
@@ -74,5 +93,6 @@ public class ServiceInfo extends ComponentInfo
private ServiceInfo(Parcel source) {
super(source);
permission = source.readString();
+ flags = source.readInt();
}
}
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 0a13b4e64974..328a55bca90f 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -1086,7 +1086,7 @@ public class Camera {
/**
* Area class for focus.
*
- * @see #setFocusAreas(List<Area>)
+ * @see #setFocusAreas(List)
* @see #getFocusAreas()
* @hide
*/
@@ -1180,6 +1180,8 @@ public class Camera {
private static final String KEY_MAX_EXPOSURE_COMPENSATION = "max-exposure-compensation";
private static final String KEY_MIN_EXPOSURE_COMPENSATION = "min-exposure-compensation";
private static final String KEY_EXPOSURE_COMPENSATION_STEP = "exposure-compensation-step";
+ private static final String KEY_METERING_AREAS = "metering-areas";
+ private static final String KEY_MAX_NUM_METERING_AREAS = "max-num-metering-areas";
private static final String KEY_ZOOM = "zoom";
private static final String KEY_MAX_ZOOM = "max-zoom";
private static final String KEY_ZOOM_RATIOS = "zoom-ratios";
@@ -1518,6 +1520,27 @@ public class Camera {
mMap.put(key, Integer.toString(value));
}
+ private void set(String key, List<Area> areas) {
+ StringBuilder buffer = new StringBuilder();
+ for (int i = 0; i < areas.size(); i++) {
+ Area area = areas.get(i);
+ Rect rect = area.rect;
+ buffer.append('(');
+ buffer.append(rect.left);
+ buffer.append(',');
+ buffer.append(rect.top);
+ buffer.append(',');
+ buffer.append(rect.right);
+ buffer.append(',');
+ buffer.append(rect.bottom);
+ buffer.append(',');
+ buffer.append(area.weight);
+ buffer.append(')');
+ if (i != areas.size() - 1) buffer.append(',');
+ }
+ set(key, buffer.toString());
+ }
+
/**
* Returns the value of a String parameter.
*
@@ -2550,8 +2573,8 @@ public class Camera {
/**
* Gets the maximum number of focus areas supported. This is the maximum
- * length of the list in {@link #setFocusArea(List<Area>)} and
- * {@link #getFocusArea()}.
+ * length of the list in {@link #setFocusAreas(List)} and
+ * {@link #getFocusAreas()}.
*
* @return the maximum number of focus areas supported by the camera.
* @see #getFocusAreas()
@@ -2562,10 +2585,11 @@ public class Camera {
}
/**
- * Gets the current focus areas.
+ * Gets the current focus areas. Camera driver uses the areas to decide
+ * focus.
*
- * Before using this API or {@link #setFocusAreas(List<int>)}, apps
- * should call {@link #getMaxNumFocusArea()} to know the maximum number of
+ * Before using this API or {@link #setFocusAreas(List)}, apps should
+ * call {@link #getMaxNumFocusAreas()} to know the maximum number of
* focus areas first. If the value is 0, focus area is not supported.
*
* Each focus area is a rectangle with specified weight. The direction
@@ -2594,7 +2618,7 @@ public class Camera {
*
* Focus area only has effect if the current focus mode is
* {@link #FOCUS_MODE_AUTO}, {@link #FOCUS_MODE_MACRO}, or
- * {@link #FOCUS_MODE_CONTINOUS_VIDEO}.
+ * {@link #FOCUS_MODE_CONTINUOUS_VIDEO}.
*
* @return a list of current focus areas
* @hide
@@ -2606,29 +2630,80 @@ public class Camera {
/**
* Sets focus areas. See {@link #getFocusAreas()} for documentation.
*
- * @param focusArea the focus areas
+ * @param focusAreas the focus areas
* @see #getFocusAreas()
* @hide
*/
- public void setFocusAreas(List<Area> focusArea) {
- StringBuilder buffer = new StringBuilder();
- for (int i = 0; i < focusArea.size(); i++) {
- Area area = focusArea.get(i);
- Rect rect = area.rect;
- buffer.append('(');
- buffer.append(rect.left);
- buffer.append(',');
- buffer.append(rect.top);
- buffer.append(',');
- buffer.append(rect.right);
- buffer.append(',');
- buffer.append(rect.bottom);
- buffer.append(',');
- buffer.append(area.weight);
- buffer.append(')');
- if (i != focusArea.size() - 1) buffer.append(',');
- }
- set(KEY_FOCUS_AREAS, buffer.toString());
+ public void setFocusAreas(List<Area> focusAreas) {
+ set(KEY_FOCUS_AREAS, focusAreas);
+ }
+
+ /**
+ * Gets the maximum number of metering areas supported. This is the
+ * maximum length of the list in {@link #setMeteringAreas(List)} and
+ * {@link #getMeteringAreas()}.
+ *
+ * @return the maximum number of metering areas supported by the camera.
+ * @see #getMeteringAreas()
+ * @hide
+ */
+ public int getMaxNumMeteringAreas() {
+ return getInt(KEY_MAX_NUM_METERING_AREAS, 0);
+ }
+
+ /**
+ * Gets the current metering areas. Camera driver uses these areas to
+ * decide exposure.
+ *
+ * Before using this API or {@link #setMeteringAreas(List)}, apps should
+ * call {@link #getMaxNumMeteringAreas()} to know the maximum number of
+ * metering areas first. If the value is 0, metering area is not
+ * supported.
+ *
+ * Each metering area is a rectangle with specified weight. The
+ * direction is relative to the sensor orientation, that is, what the
+ * sensor sees. The direction is not affected by the rotation or
+ * mirroring of {@link #setDisplayOrientation(int)}. Coordinates of the
+ * rectangle range from -1000 to 1000. (-1000, -1000) is the upper left
+ * point. (1000, 1000) is the lower right point. The length and width of
+ * metering areas cannot be 0 or negative.
+ *
+ * The weight ranges from 1 to 1000. The sum of the weights of all
+ * metering areas must be 1000. Metering areas can partially overlap and
+ * the driver will add the weights in the overlap region. But apps
+ * should not set two metering areas that have identical coordinates.
+ *
+ * A special case of all-zero single metering area means driver to
+ * decide the metering area. For example, the driver may use more
+ * signals to decide metering areas and change them dynamically. Apps
+ * can set all-zero if they want the driver to decide metering areas.
+ *
+ * Metering areas are relative to the current field of view
+ * ({@link #getZoom()}). No matter what the zoom level is, (-1000,-1000)
+ * represents the top of the currently visible camera frame. The
+ * metering area cannot be set to be outside the current field of view,
+ * even when using zoom.
+ *
+ * No matter what metering areas are, the final exposure are compensated
+ * by {@link #setExposureCompensation(int)}.
+ *
+ * @return a list of current metering areas
+ * @hide
+ */
+ public List<Area> getMeteringAreas() {
+ return splitArea(KEY_METERING_AREAS);
+ }
+
+ /**
+ * Sets metering areas. See {@link #getMeteringAreas()} for
+ * documentation.
+ *
+ * @param meteringAreas the metering areas
+ * @see #getMeteringAreas()
+ * @hide
+ */
+ public void setMeteringAreas(List<Area> meteringAreas) {
+ set(KEY_METERING_AREAS, meteringAreas);
}
// Splits a comma delimited string to an ArrayList of String.
diff --git a/core/java/android/nfc/ApduList.aidl b/core/java/android/nfc/ApduList.aidl
new file mode 100644
index 000000000000..f6236b2bfb3b
--- /dev/null
+++ b/core/java/android/nfc/ApduList.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 android.nfc;
+
+parcelable ApduList; \ No newline at end of file
diff --git a/core/java/android/nfc/ApduList.java b/core/java/android/nfc/ApduList.java
new file mode 100644
index 000000000000..85b0547942a6
--- /dev/null
+++ b/core/java/android/nfc/ApduList.java
@@ -0,0 +1,68 @@
+package android.nfc;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @hide
+ */
+public class ApduList implements Parcelable {
+
+ private ArrayList<byte[]> commands = new ArrayList<byte[]>();
+
+ public ApduList() {
+ }
+
+ public void add(byte[] command) {
+ commands.add(command);
+ }
+
+ public List<byte[]> get() {
+ return commands;
+ }
+
+ public static final Parcelable.Creator<ApduList> CREATOR =
+ new Parcelable.Creator<ApduList>() {
+ @Override
+ public ApduList createFromParcel(Parcel in) {
+ return new ApduList(in);
+ }
+
+ @Override
+ public ApduList[] newArray(int size) {
+ return new ApduList[size];
+ }
+ };
+
+ private ApduList(Parcel in) {
+ int count = in.readInt();
+
+ for (int i = 0 ; i < count ; i++) {
+
+ int length = in.readInt();
+ byte[] cmd = new byte[length];
+ in.readByteArray(cmd);
+ commands.add(cmd);
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(commands.size());
+
+ for (byte[] cmd : commands) {
+ dest.writeInt(cmd.length);
+ dest.writeByteArray(cmd);
+ }
+ }
+}
+
+
diff --git a/core/java/android/nfc/INfcAdapterExtras.aidl b/core/java/android/nfc/INfcAdapterExtras.aidl
index ab5c1a656bba..8677a503b270 100755
--- a/core/java/android/nfc/INfcAdapterExtras.aidl
+++ b/core/java/android/nfc/INfcAdapterExtras.aidl
@@ -16,8 +16,10 @@
package android.nfc;
+import android.nfc.ApduList;
import android.os.Bundle;
+
/**
* {@hide}
*/
@@ -26,5 +28,7 @@ interface INfcAdapterExtras {
Bundle close();
Bundle transceive(in byte[] data_in);
int getCardEmulationRoute();
- void setCardEmulationRoute(int route);
+ void setCardEmulationRoute(int route);
+ void registerTearDownApdus(String packageName, in ApduList apdu);
+ void unregisterTearDownApdus(String packageName);
}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 90e2e797cbee..b0f3ac3e23a4 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -26,6 +26,7 @@ import android.content.pm.ApplicationInfo;
import android.telephony.SignalStrength;
import android.util.Log;
import android.util.Printer;
+import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
@@ -408,15 +409,19 @@ public abstract class BatteryStats implements Parcelable {
}
public final static class HistoryItem implements Parcelable {
+ static final String TAG = "HistoryItem";
+ static final boolean DEBUG = false;
+
public HistoryItem next;
public long time;
- public static final byte CMD_UPDATE = 0;
- public static final byte CMD_START = 1;
- public static final byte CMD_OVERFLOW = 2;
+ public static final byte CMD_NULL = 0;
+ public static final byte CMD_UPDATE = 1;
+ public static final byte CMD_START = 2;
+ public static final byte CMD_OVERFLOW = 3;
- public byte cmd;
+ public byte cmd = CMD_NULL;
public byte batteryLevel;
public byte batteryStatus;
@@ -427,33 +432,38 @@ public abstract class BatteryStats implements Parcelable {
public char batteryVoltage;
// Constants from SCREEN_BRIGHTNESS_*
- public static final int STATE_BRIGHTNESS_MASK = 0x000000f;
+ public static final int STATE_BRIGHTNESS_MASK = 0x0000000f;
public static final int STATE_BRIGHTNESS_SHIFT = 0;
// Constants from SIGNAL_STRENGTH_*
- public static final int STATE_SIGNAL_STRENGTH_MASK = 0x00000f0;
+ public static final int STATE_SIGNAL_STRENGTH_MASK = 0x000000f0;
public static final int STATE_SIGNAL_STRENGTH_SHIFT = 4;
// Constants from ServiceState.STATE_*
- public static final int STATE_PHONE_STATE_MASK = 0x0000f00;
+ public static final int STATE_PHONE_STATE_MASK = 0x00000f00;
public static final int STATE_PHONE_STATE_SHIFT = 8;
// Constants from DATA_CONNECTION_*
- public static final int STATE_DATA_CONNECTION_MASK = 0x000f000;
+ public static final int STATE_DATA_CONNECTION_MASK = 0x0000f000;
public static final int STATE_DATA_CONNECTION_SHIFT = 12;
- public static final int STATE_BATTERY_PLUGGED_FLAG = 1<<30;
- public static final int STATE_SCREEN_ON_FLAG = 1<<29;
+ // These states always appear directly in the first int token
+ // of a delta change; they should be ones that change relatively
+ // frequently.
+ public static final int STATE_WAKE_LOCK_FLAG = 1<<30;
+ public static final int STATE_SENSOR_ON_FLAG = 1<<29;
public static final int STATE_GPS_ON_FLAG = 1<<28;
- public static final int STATE_PHONE_IN_CALL_FLAG = 1<<27;
- public static final int STATE_PHONE_SCANNING_FLAG = 1<<26;
- public static final int STATE_WIFI_ON_FLAG = 1<<25;
- public static final int STATE_WIFI_RUNNING_FLAG = 1<<24;
- public static final int STATE_WIFI_FULL_LOCK_FLAG = 1<<23;
- public static final int STATE_WIFI_SCAN_LOCK_FLAG = 1<<22;
- public static final int STATE_WIFI_MULTICAST_ON_FLAG = 1<<21;
- public static final int STATE_BLUETOOTH_ON_FLAG = 1<<20;
- public static final int STATE_AUDIO_ON_FLAG = 1<<19;
- public static final int STATE_VIDEO_ON_FLAG = 1<<18;
- public static final int STATE_WAKE_LOCK_FLAG = 1<<17;
- public static final int STATE_SENSOR_ON_FLAG = 1<<16;
+ public static final int STATE_PHONE_SCANNING_FLAG = 1<<27;
+ public static final int STATE_WIFI_RUNNING_FLAG = 1<<26;
+ public static final int STATE_WIFI_FULL_LOCK_FLAG = 1<<25;
+ public static final int STATE_WIFI_SCAN_LOCK_FLAG = 1<<24;
+ public static final int STATE_WIFI_MULTICAST_ON_FLAG = 1<<23;
+ // These are on the lower bits used for the command; if they change
+ // we need to write another int of data.
+ public static final int STATE_AUDIO_ON_FLAG = 1<<22;
+ public static final int STATE_VIDEO_ON_FLAG = 1<<21;
+ public static final int STATE_SCREEN_ON_FLAG = 1<<20;
+ public static final int STATE_BATTERY_PLUGGED_FLAG = 1<<19;
+ public static final int STATE_PHONE_IN_CALL_FLAG = 1<<18;
+ public static final int STATE_WIFI_ON_FLAG = 1<<17;
+ public static final int STATE_BLUETOOTH_ON_FLAG = 1<<16;
public static final int MOST_INTERESTING_STATES =
STATE_BATTERY_PLUGGED_FLAG | STATE_SCREEN_ON_FLAG
@@ -466,16 +476,7 @@ public abstract class BatteryStats implements Parcelable {
public HistoryItem(long time, Parcel src) {
this.time = time;
- int bat = src.readInt();
- cmd = (byte)(bat&0xff);
- batteryLevel = (byte)((bat>>8)&0xff);
- batteryStatus = (byte)((bat>>16)&0xf);
- batteryHealth = (byte)((bat>>20)&0xf);
- batteryPlugType = (byte)((bat>>24)&0xf);
- bat = src.readInt();
- batteryTemperature = (char)(bat&0xffff);
- batteryVoltage = (char)((bat>>16)&0xffff);
- states = src.readInt();
+ readFromParcel(src);
}
public int describeContents() {
@@ -495,6 +496,174 @@ public abstract class BatteryStats implements Parcelable {
dest.writeInt(bat);
dest.writeInt(states);
}
+
+ private void readFromParcel(Parcel src) {
+ int bat = src.readInt();
+ cmd = (byte)(bat&0xff);
+ batteryLevel = (byte)((bat>>8)&0xff);
+ batteryStatus = (byte)((bat>>16)&0xf);
+ batteryHealth = (byte)((bat>>20)&0xf);
+ batteryPlugType = (byte)((bat>>24)&0xf);
+ bat = src.readInt();
+ batteryTemperature = (char)(bat&0xffff);
+ batteryVoltage = (char)((bat>>16)&0xffff);
+ states = src.readInt();
+ }
+
+ // Part of initial delta int that specifies the time delta.
+ static final int DELTA_TIME_MASK = 0x3ffff;
+ static final int DELTA_TIME_ABS = 0x3fffd; // Following is an entire abs update.
+ static final int DELTA_TIME_INT = 0x3fffe; // The delta is a following int
+ static final int DELTA_TIME_LONG = 0x3ffff; // The delta is a following long
+ // Part of initial delta int holding the command code.
+ static final int DELTA_CMD_MASK = 0x3;
+ static final int DELTA_CMD_SHIFT = 18;
+ // Flag in delta int: a new battery level int follows.
+ static final int DELTA_BATTERY_LEVEL_FLAG = 1<<20;
+ // Flag in delta int: a new full state and battery status int follows.
+ static final int DELTA_STATE_FLAG = 1<<21;
+ static final int DELTA_STATE_MASK = 0xffc00000;
+
+ public void writeDelta(Parcel dest, HistoryItem last) {
+ if (last == null || last.cmd != CMD_UPDATE) {
+ dest.writeInt(DELTA_TIME_ABS);
+ writeToParcel(dest, 0);
+ return;
+ }
+
+ final long deltaTime = time - last.time;
+ final int lastBatteryLevelInt = last.buildBatteryLevelInt();
+ final int lastStateInt = last.buildStateInt();
+
+ int deltaTimeToken;
+ if (deltaTime < 0 || deltaTime > Integer.MAX_VALUE) {
+ deltaTimeToken = DELTA_TIME_LONG;
+ } else if (deltaTime >= DELTA_TIME_ABS) {
+ deltaTimeToken = DELTA_TIME_INT;
+ } else {
+ deltaTimeToken = (int)deltaTime;
+ }
+ int firstToken = deltaTimeToken
+ | (cmd<<DELTA_CMD_SHIFT)
+ | (states&DELTA_STATE_MASK);
+ final int batteryLevelInt = buildBatteryLevelInt();
+ final boolean batteryLevelIntChanged = batteryLevelInt != lastBatteryLevelInt;
+ if (batteryLevelIntChanged) {
+ firstToken |= DELTA_BATTERY_LEVEL_FLAG;
+ }
+ final int stateInt = buildStateInt();
+ final boolean stateIntChanged = stateInt != lastStateInt;
+ if (stateIntChanged) {
+ firstToken |= DELTA_STATE_FLAG;
+ }
+ dest.writeInt(firstToken);
+ if (DEBUG) Slog.i(TAG, "WRITE DELTA: firstToken=0x" + Integer.toHexString(firstToken)
+ + " deltaTime=" + deltaTime);
+
+ if (deltaTimeToken >= DELTA_TIME_INT) {
+ if (deltaTimeToken == DELTA_TIME_INT) {
+ if (DEBUG) Slog.i(TAG, "WRITE DELTA: int deltaTime=" + (int)deltaTime);
+ dest.writeInt((int)deltaTime);
+ } else {
+ if (DEBUG) Slog.i(TAG, "WRITE DELTA: long deltaTime=" + deltaTime);
+ dest.writeLong(deltaTime);
+ }
+ }
+ if (batteryLevelIntChanged) {
+ dest.writeInt(batteryLevelInt);
+ if (DEBUG) Slog.i(TAG, "WRITE DELTA: batteryToken=0x"
+ + Integer.toHexString(batteryLevelInt)
+ + " batteryLevel=" + batteryLevel
+ + " batteryTemp=" + (int)batteryTemperature
+ + " batteryVolt=" + (int)batteryVoltage);
+ }
+ if (stateIntChanged) {
+ dest.writeInt(stateInt);
+ if (DEBUG) Slog.i(TAG, "WRITE DELTA: stateToken=0x"
+ + Integer.toHexString(stateInt)
+ + " batteryStatus=" + batteryStatus
+ + " batteryHealth=" + batteryHealth
+ + " batteryPlugType=" + batteryPlugType
+ + " states=0x" + Integer.toHexString(states));
+ }
+ }
+
+ private int buildBatteryLevelInt() {
+ return ((((int)batteryLevel)<<24)&0xff000000)
+ | ((((int)batteryTemperature)<<14)&0x00ffc000)
+ | (((int)batteryVoltage)&0x00003fff);
+ }
+
+ private int buildStateInt() {
+ return ((((int)batteryStatus)<<28)&0xf0000000)
+ | ((((int)batteryHealth)<<24)&0x0f000000)
+ | ((((int)batteryPlugType)<<22)&0x00c00000)
+ | (states&(~DELTA_STATE_MASK));
+ }
+
+ public void readDelta(Parcel src) {
+ int firstToken = src.readInt();
+ int deltaTimeToken = firstToken&DELTA_TIME_MASK;
+ cmd = (byte)((firstToken>>DELTA_CMD_SHIFT)&DELTA_CMD_MASK);
+ if (DEBUG) Slog.i(TAG, "READ DELTA: firstToken=0x" + Integer.toHexString(firstToken)
+ + " deltaTimeToken=" + deltaTimeToken);
+
+ if (deltaTimeToken < DELTA_TIME_ABS) {
+ time += deltaTimeToken;
+ } else if (deltaTimeToken == DELTA_TIME_ABS) {
+ time = src.readLong();
+ readFromParcel(src);
+ return;
+ } else if (deltaTimeToken == DELTA_TIME_INT) {
+ int delta = src.readInt();
+ time += delta;
+ if (DEBUG) Slog.i(TAG, "READ DELTA: time delta=" + delta + " new time=" + time);
+ } else {
+ long delta = src.readLong();
+ if (DEBUG) Slog.i(TAG, "READ DELTA: time delta=" + delta + " new time=" + time);
+ time += delta;
+ }
+
+ if ((firstToken&DELTA_BATTERY_LEVEL_FLAG) != 0) {
+ int batteryLevelInt = src.readInt();
+ batteryLevel = (byte)((batteryLevelInt>>24)&0xff);
+ batteryTemperature = (char)((batteryLevelInt>>14)&0x3ff);
+ batteryVoltage = (char)(batteryLevelInt&0x3fff);
+ if (DEBUG) Slog.i(TAG, "READ DELTA: batteryToken=0x"
+ + Integer.toHexString(batteryLevelInt)
+ + " batteryLevel=" + batteryLevel
+ + " batteryTemp=" + (int)batteryTemperature
+ + " batteryVolt=" + (int)batteryVoltage);
+ }
+
+ if ((firstToken&DELTA_STATE_FLAG) != 0) {
+ int stateInt = src.readInt();
+ states = (firstToken&DELTA_STATE_MASK) | (stateInt&(~DELTA_STATE_MASK));
+ batteryStatus = (byte)((stateInt>>28)&0xf);
+ batteryHealth = (byte)((stateInt>>24)&0xf);
+ batteryPlugType = (byte)((stateInt>>22)&0x3);
+ if (DEBUG) Slog.i(TAG, "READ DELTA: stateToken=0x"
+ + Integer.toHexString(stateInt)
+ + " batteryStatus=" + batteryStatus
+ + " batteryHealth=" + batteryHealth
+ + " batteryPlugType=" + batteryPlugType
+ + " states=0x" + Integer.toHexString(states));
+ } else {
+ states = (firstToken&DELTA_STATE_MASK) | (states&(~DELTA_STATE_MASK));
+ }
+ }
+
+ public void clear() {
+ time = 0;
+ cmd = CMD_NULL;
+ batteryLevel = 0;
+ batteryStatus = 0;
+ batteryHealth = 0;
+ batteryPlugType = 0;
+ batteryTemperature = 0;
+ batteryVoltage = 0;
+ states = 0;
+ }
public void setTo(HistoryItem o) {
time = o.time;
@@ -556,11 +725,14 @@ public abstract class BatteryStats implements Parcelable {
public abstract boolean getNextHistoryLocked(HistoryItem out);
- /**
- * Return the current history of battery state changes.
- */
- public abstract HistoryItem getHistory();
-
+ public abstract void finishIteratingHistoryLocked();
+
+ public abstract boolean startIteratingOldHistoryLocked();
+
+ public abstract boolean getNextOldHistoryLocked(HistoryItem out);
+
+ public abstract void finishIteratingOldHistoryLocked();
+
/**
* Return the base time offset for the battery history.
*/
@@ -1729,7 +1901,7 @@ public abstract class BatteryStats implements Parcelable {
}
}
- void printBitDescriptions(PrintWriter pw, int oldval, int newval, BitDescription[] descriptions) {
+ static void printBitDescriptions(PrintWriter pw, int oldval, int newval, BitDescription[] descriptions) {
int diff = oldval ^ newval;
if (diff == 0) return;
for (int i=0; i<descriptions.length; i++) {
@@ -1753,6 +1925,125 @@ public abstract class BatteryStats implements Parcelable {
}
}
+ public void prepareForDumpLocked() {
+ }
+
+ public static class HistoryPrinter {
+ int oldState = 0;
+ int oldStatus = -1;
+ int oldHealth = -1;
+ int oldPlug = -1;
+ int oldTemp = -1;
+ int oldVolt = -1;
+
+ public void printNextItem(PrintWriter pw, HistoryItem rec, long now) {
+ pw.print(" ");
+ TimeUtils.formatDuration(rec.time-now, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN);
+ pw.print(" ");
+ if (rec.cmd == HistoryItem.CMD_START) {
+ pw.println(" START");
+ } else if (rec.cmd == HistoryItem.CMD_OVERFLOW) {
+ pw.println(" *OVERFLOW*");
+ } else {
+ if (rec.batteryLevel < 10) pw.print("00");
+ else if (rec.batteryLevel < 100) pw.print("0");
+ pw.print(rec.batteryLevel);
+ pw.print(" ");
+ if (rec.states < 0x10) pw.print("0000000");
+ else if (rec.states < 0x100) pw.print("000000");
+ else if (rec.states < 0x1000) pw.print("00000");
+ else if (rec.states < 0x10000) pw.print("0000");
+ else if (rec.states < 0x100000) pw.print("000");
+ else if (rec.states < 0x1000000) pw.print("00");
+ else if (rec.states < 0x10000000) pw.print("0");
+ pw.print(Integer.toHexString(rec.states));
+ if (oldStatus != rec.batteryStatus) {
+ oldStatus = rec.batteryStatus;
+ pw.print(" status=");
+ switch (oldStatus) {
+ case BatteryManager.BATTERY_STATUS_UNKNOWN:
+ pw.print("unknown");
+ break;
+ case BatteryManager.BATTERY_STATUS_CHARGING:
+ pw.print("charging");
+ break;
+ case BatteryManager.BATTERY_STATUS_DISCHARGING:
+ pw.print("discharging");
+ break;
+ case BatteryManager.BATTERY_STATUS_NOT_CHARGING:
+ pw.print("not-charging");
+ break;
+ case BatteryManager.BATTERY_STATUS_FULL:
+ pw.print("full");
+ break;
+ default:
+ pw.print(oldStatus);
+ break;
+ }
+ }
+ if (oldHealth != rec.batteryHealth) {
+ oldHealth = rec.batteryHealth;
+ pw.print(" health=");
+ switch (oldHealth) {
+ case BatteryManager.BATTERY_HEALTH_UNKNOWN:
+ pw.print("unknown");
+ break;
+ case BatteryManager.BATTERY_HEALTH_GOOD:
+ pw.print("good");
+ break;
+ case BatteryManager.BATTERY_HEALTH_OVERHEAT:
+ pw.print("overheat");
+ break;
+ case BatteryManager.BATTERY_HEALTH_DEAD:
+ pw.print("dead");
+ break;
+ case BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE:
+ pw.print("over-voltage");
+ break;
+ case BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE:
+ pw.print("failure");
+ break;
+ default:
+ pw.print(oldHealth);
+ break;
+ }
+ }
+ if (oldPlug != rec.batteryPlugType) {
+ oldPlug = rec.batteryPlugType;
+ pw.print(" plug=");
+ switch (oldPlug) {
+ case 0:
+ pw.print("none");
+ break;
+ case BatteryManager.BATTERY_PLUGGED_AC:
+ pw.print("ac");
+ break;
+ case BatteryManager.BATTERY_PLUGGED_USB:
+ pw.print("usb");
+ break;
+ default:
+ pw.print(oldPlug);
+ break;
+ }
+ }
+ if (oldTemp != rec.batteryTemperature) {
+ oldTemp = rec.batteryTemperature;
+ pw.print(" temp=");
+ pw.print(oldTemp);
+ }
+ if (oldVolt != rec.batteryVoltage) {
+ oldVolt = rec.batteryVoltage;
+ pw.print(" volt=");
+ pw.print(oldVolt);
+ }
+ printBitDescriptions(pw, oldState, rec.states,
+ HISTORY_STATE_DESCRIPTIONS);
+ pw.println();
+ }
+ oldState = rec.states;
+ }
+ }
+
/**
* Dumps a human-readable summary of the battery statistics to the given PrintWriter.
*
@@ -1760,122 +2051,28 @@ public abstract class BatteryStats implements Parcelable {
*/
@SuppressWarnings("unused")
public void dumpLocked(PrintWriter pw) {
+ prepareForDumpLocked();
+
+ long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
+
final HistoryItem rec = new HistoryItem();
if (startIteratingHistoryLocked()) {
pw.println("Battery History:");
- long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
- int oldState = 0;
- int oldStatus = -1;
- int oldHealth = -1;
- int oldPlug = -1;
- int oldTemp = -1;
- int oldVolt = -1;
+ HistoryPrinter hprinter = new HistoryPrinter();
while (getNextHistoryLocked(rec)) {
- pw.print(" ");
- TimeUtils.formatDuration(rec.time-now, pw, TimeUtils.HUNDRED_DAY_FIELD_LEN);
- pw.print(" ");
- if (rec.cmd == HistoryItem.CMD_START) {
- pw.println(" START");
- } else if (rec.cmd == HistoryItem.CMD_OVERFLOW) {
- pw.println(" *OVERFLOW*");
- } else {
- if (rec.batteryLevel < 10) pw.print("00");
- else if (rec.batteryLevel < 100) pw.print("0");
- pw.print(rec.batteryLevel);
- pw.print(" ");
- if (rec.states < 0x10) pw.print("0000000");
- else if (rec.states < 0x100) pw.print("000000");
- else if (rec.states < 0x1000) pw.print("00000");
- else if (rec.states < 0x10000) pw.print("0000");
- else if (rec.states < 0x100000) pw.print("000");
- else if (rec.states < 0x1000000) pw.print("00");
- else if (rec.states < 0x10000000) pw.print("0");
- pw.print(Integer.toHexString(rec.states));
- if (oldStatus != rec.batteryStatus) {
- oldStatus = rec.batteryStatus;
- pw.print(" status=");
- switch (oldStatus) {
- case BatteryManager.BATTERY_STATUS_UNKNOWN:
- pw.print("unknown");
- break;
- case BatteryManager.BATTERY_STATUS_CHARGING:
- pw.print("charging");
- break;
- case BatteryManager.BATTERY_STATUS_DISCHARGING:
- pw.print("discharging");
- break;
- case BatteryManager.BATTERY_STATUS_NOT_CHARGING:
- pw.print("not-charging");
- break;
- case BatteryManager.BATTERY_STATUS_FULL:
- pw.print("full");
- break;
- default:
- pw.print(oldStatus);
- break;
- }
- }
- if (oldHealth != rec.batteryHealth) {
- oldHealth = rec.batteryHealth;
- pw.print(" health=");
- switch (oldHealth) {
- case BatteryManager.BATTERY_HEALTH_UNKNOWN:
- pw.print("unknown");
- break;
- case BatteryManager.BATTERY_HEALTH_GOOD:
- pw.print("good");
- break;
- case BatteryManager.BATTERY_HEALTH_OVERHEAT:
- pw.print("overheat");
- break;
- case BatteryManager.BATTERY_HEALTH_DEAD:
- pw.print("dead");
- break;
- case BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE:
- pw.print("over-voltage");
- break;
- case BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE:
- pw.print("failure");
- break;
- default:
- pw.print(oldHealth);
- break;
- }
- }
- if (oldPlug != rec.batteryPlugType) {
- oldPlug = rec.batteryPlugType;
- pw.print(" plug=");
- switch (oldPlug) {
- case 0:
- pw.print("none");
- break;
- case BatteryManager.BATTERY_PLUGGED_AC:
- pw.print("ac");
- break;
- case BatteryManager.BATTERY_PLUGGED_USB:
- pw.print("usb");
- break;
- default:
- pw.print(oldPlug);
- break;
- }
- }
- if (oldTemp != rec.batteryTemperature) {
- oldTemp = rec.batteryTemperature;
- pw.print(" temp=");
- pw.print(oldTemp);
- }
- if (oldVolt != rec.batteryVoltage) {
- oldVolt = rec.batteryVoltage;
- pw.print(" volt=");
- pw.print(oldVolt);
- }
- printBitDescriptions(pw, oldState, rec.states,
- HISTORY_STATE_DESCRIPTIONS);
- pw.println();
- }
- oldState = rec.states;
+ hprinter.printNextItem(pw, rec, now);
+ }
+ finishIteratingHistoryLocked();
+ pw.println("");
+ }
+
+ if (startIteratingOldHistoryLocked()) {
+ pw.println("Old battery History:");
+ HistoryPrinter hprinter = new HistoryPrinter();
+ while (getNextOldHistoryLocked(rec)) {
+ hprinter.printNextItem(pw, rec, now);
}
+ finishIteratingOldHistoryLocked();
pw.println("");
}
@@ -1918,6 +2115,8 @@ public abstract class BatteryStats implements Parcelable {
@SuppressWarnings("unused")
public void dumpCheckinLocked(PrintWriter pw, String[] args, List<ApplicationInfo> apps) {
+ prepareForDumpLocked();
+
boolean isUnpluggedOnly = false;
for (String arg : args) {
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index aa959b4ded1a..f7661b61f539 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -35,64 +35,64 @@ public class ParcelFileDescriptor implements Parcelable {
//consider ParcelFileDescriptor A(fileDescriptor fd), ParcelFileDescriptor B(A)
//in this particular case fd.close might be invoked twice.
private final ParcelFileDescriptor mParcelDescriptor;
-
+
/**
* For use with {@link #open}: if {@link #MODE_CREATE} has been supplied
* and this file doesn't already exist, then create the file with
* permissions such that any application can read it.
*/
public static final int MODE_WORLD_READABLE = 0x00000001;
-
+
/**
* For use with {@link #open}: if {@link #MODE_CREATE} has been supplied
* and this file doesn't already exist, then create the file with
* permissions such that any application can write it.
*/
public static final int MODE_WORLD_WRITEABLE = 0x00000002;
-
+
/**
* For use with {@link #open}: open the file with read-only access.
*/
public static final int MODE_READ_ONLY = 0x10000000;
-
+
/**
* For use with {@link #open}: open the file with write-only access.
*/
public static final int MODE_WRITE_ONLY = 0x20000000;
-
+
/**
* For use with {@link #open}: open the file with read and write access.
*/
public static final int MODE_READ_WRITE = 0x30000000;
-
+
/**
* For use with {@link #open}: create the file if it doesn't already exist.
*/
public static final int MODE_CREATE = 0x08000000;
-
+
/**
* For use with {@link #open}: erase contents of file when opening.
*/
public static final int MODE_TRUNCATE = 0x04000000;
-
+
/**
* For use with {@link #open}: append to end of file while writing.
*/
public static final int MODE_APPEND = 0x02000000;
-
+
/**
* Create a new ParcelFileDescriptor accessing a given file.
- *
+ *
* @param file The file to be opened.
* @param mode The desired access mode, must be one of
* {@link #MODE_READ_ONLY}, {@link #MODE_WRITE_ONLY}, or
* {@link #MODE_READ_WRITE}; may also be any combination of
* {@link #MODE_CREATE}, {@link #MODE_TRUNCATE},
* {@link #MODE_WORLD_READABLE}, and {@link #MODE_WORLD_WRITEABLE}.
- *
+ *
* @return Returns a new ParcelFileDescriptor pointing to the given
* file.
- *
+ *
* @throws FileNotFoundException Throws FileNotFoundException if the given
* file does not exist or can not be opened with the requested mode.
*/
@@ -106,12 +106,12 @@ public class ParcelFileDescriptor implements Parcelable {
security.checkWrite(path);
}
}
-
+
if ((mode&MODE_READ_WRITE) == 0) {
throw new IllegalArgumentException(
"Must specify MODE_READ_ONLY, MODE_WRITE_ONLY, or MODE_READ_WRITE");
}
-
+
FileDescriptor fd = Parcel.openFileDescriptor(path, mode);
return fd != null ? new ParcelFileDescriptor(fd) : null;
}
@@ -137,13 +137,10 @@ public class ParcelFileDescriptor implements Parcelable {
* specified Socket.
*/
public static ParcelFileDescriptor fromSocket(Socket socket) {
- FileDescriptor fd = getFileDescriptorFromSocket(socket);
+ FileDescriptor fd = socket.getFileDescriptor$();
return fd != null ? new ParcelFileDescriptor(fd) : null;
}
- // Extracts the file descriptor from the specified socket and returns it untouched
- private static native FileDescriptor getFileDescriptorFromSocket(Socket socket);
-
/**
* Create two ParcelFileDescriptors structured as a data pipe. The first
* ParcelFileDescriptor in the returned array is the read side; the second
@@ -187,26 +184,26 @@ public class ParcelFileDescriptor implements Parcelable {
/**
* Retrieve the actual FileDescriptor associated with this object.
- *
+ *
* @return Returns the FileDescriptor associated with this object.
*/
public FileDescriptor getFileDescriptor() {
return mFileDescriptor;
}
-
+
/**
* Return the total size of the file representing this fd, as determined
* by stat(). Returns -1 if the fd is not a file.
*/
public native long getStatSize();
-
+
/**
* This is needed for implementing AssetFileDescriptor.AutoCloseOutputStream,
* and I really don't think we want it to be public.
* @hide
*/
public native long seekTo(long pos);
-
+
/**
* Return the native fd int for this ParcelFileDescriptor. The
* ParcelFileDescriptor still owns the fd, and it still must be closed
@@ -218,9 +215,9 @@ public class ParcelFileDescriptor implements Parcelable {
}
return getFdNative();
}
-
+
private native int getFdNative();
-
+
/**
* Return the native fd int for this ParcelFileDescriptor and detach it
* from the object here. You are now responsible for closing the fd in
@@ -240,11 +237,11 @@ public class ParcelFileDescriptor implements Parcelable {
Parcel.clearFileDescriptor(mFileDescriptor);
return fd;
}
-
+
/**
* Close the ParcelFileDescriptor. This implementation closes the underlying
* OS resources allocated to represent this stream.
- *
+ *
* @throws IOException
* If an error occurs attempting to close this ParcelFileDescriptor.
*/
@@ -261,7 +258,7 @@ public class ParcelFileDescriptor implements Parcelable {
Parcel.closeFileDescriptor(mFileDescriptor);
}
}
-
+
/**
* An InputStream you can create on a ParcelFileDescriptor, which will
* take care of calling {@link ParcelFileDescriptor#close
@@ -269,7 +266,7 @@ public class ParcelFileDescriptor implements Parcelable {
*/
public static class AutoCloseInputStream extends FileInputStream {
private final ParcelFileDescriptor mFd;
-
+
public AutoCloseInputStream(ParcelFileDescriptor fd) {
super(fd.getFileDescriptor());
mFd = fd;
@@ -284,7 +281,7 @@ public class ParcelFileDescriptor implements Parcelable {
}
}
}
-
+
/**
* An OutputStream you can create on a ParcelFileDescriptor, which will
* take care of calling {@link ParcelFileDescriptor#close
@@ -292,7 +289,7 @@ public class ParcelFileDescriptor implements Parcelable {
*/
public static class AutoCloseOutputStream extends FileOutputStream {
private final ParcelFileDescriptor mFd;
-
+
public AutoCloseOutputStream(ParcelFileDescriptor fd) {
super(fd.getFileDescriptor());
mFd = fd;
@@ -307,12 +304,12 @@ public class ParcelFileDescriptor implements Parcelable {
}
}
}
-
+
@Override
public String toString() {
return "{ParcelFileDescriptor: " + mFileDescriptor + "}";
}
-
+
@Override
protected void finalize() throws Throwable {
try {
@@ -323,13 +320,13 @@ public class ParcelFileDescriptor implements Parcelable {
super.finalize();
}
}
-
+
public ParcelFileDescriptor(ParcelFileDescriptor descriptor) {
super();
mParcelDescriptor = descriptor;
mFileDescriptor = mParcelDescriptor.mFileDescriptor;
}
-
+
/*package */ParcelFileDescriptor(FileDescriptor descriptor) {
super();
if (descriptor == null) {
@@ -338,7 +335,7 @@ public class ParcelFileDescriptor implements Parcelable {
mFileDescriptor = descriptor;
mParcelDescriptor = null;
}
-
+
/* Parcelable interface */
public int describeContents() {
return Parcelable.CONTENTS_FILE_DESCRIPTOR;
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 7151ac262d64..f85df6ce6adb 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -101,7 +101,7 @@ public class Process {
* Defines the UID/GID for the NFC service process.
* @hide
*/
- public static final int NFC_UID = 1023;
+ public static final int NFC_UID = 1025;
/**
* Defines the GID for the group that allows write access to the internal media storage.
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index c1dd9119e4cc..ae605fb3ac5d 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -70,7 +70,7 @@ public class RecoverySystem {
private static File RECOVERY_DIR = new File("/cache/recovery");
private static File COMMAND_FILE = new File(RECOVERY_DIR, "command");
private static File LOG_FILE = new File(RECOVERY_DIR, "log");
- private static String LAST_LOG_FILENAME = "last_log";
+ private static String LAST_PREFIX = "last_";
// Length limits for reading files.
private static int LOG_FILE_MAX_LENGTH = 64 * 1024;
@@ -415,10 +415,11 @@ public class RecoverySystem {
Log.e(TAG, "Error reading recovery log", e);
}
- // Delete everything in RECOVERY_DIR except LAST_LOG_FILENAME
+ // Delete everything in RECOVERY_DIR except those beginning
+ // with LAST_PREFIX
String[] names = RECOVERY_DIR.list();
for (int i = 0; names != null && i < names.length; i++) {
- if (names[i].equals(LAST_LOG_FILENAME)) continue;
+ if (names[i].startsWith(LAST_PREFIX)) continue;
File f = new File(RECOVERY_DIR, names[i]);
if (!f.delete()) {
Log.e(TAG, "Can't delete: " + f);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index a675618c6c28..2f4a4bbee490 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1505,6 +1505,13 @@ public final class Settings {
public static final Uri DEFAULT_ALARM_ALERT_URI = getUriFor(ALARM_ALERT);
/**
+ * Persistent store for the system default media button event receiver.
+ *
+ * @hide
+ */
+ public static final String MEDIA_BUTTON_RECEIVER = "media_button_receiver";
+
+ /**
* Setting to enable Auto Replace (AutoText) in text editors. 1 = On, 0 = Off
*/
public static final String TEXT_AUTO_REPLACE = "auto_replace";
diff --git a/core/java/android/speech/tts/BlockingMediaPlayer.java b/core/java/android/speech/tts/BlockingMediaPlayer.java
new file mode 100644
index 000000000000..3cf60dd8f992
--- /dev/null
+++ b/core/java/android/speech/tts/BlockingMediaPlayer.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 android.speech.tts;
+
+import android.content.Context;
+import android.media.MediaPlayer;
+import android.net.Uri;
+import android.os.ConditionVariable;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.util.Log;
+
+/**
+ * A media player that allows blocking to wait for it to finish.
+ */
+class BlockingMediaPlayer {
+
+ private static final String TAG = "BlockMediaPlayer";
+
+ private static final String MEDIA_PLAYER_THREAD_NAME = "TTS-MediaPlayer";
+
+ private final Context mContext;
+ private final Uri mUri;
+ private final int mStreamType;
+ private final ConditionVariable mDone;
+ // Only accessed on the Handler thread
+ private MediaPlayer mPlayer;
+ private volatile boolean mFinished;
+
+ /**
+ * Creates a new blocking media player.
+ * Creating a blocking media player is a cheap operation.
+ *
+ * @param context
+ * @param uri
+ * @param streamType
+ */
+ public BlockingMediaPlayer(Context context, Uri uri, int streamType) {
+ mContext = context;
+ mUri = uri;
+ mStreamType = streamType;
+ mDone = new ConditionVariable();
+
+ }
+
+ /**
+ * Starts playback and waits for it to finish.
+ * Can be called from any thread.
+ *
+ * @return {@code true} if the playback finished normally, {@code false} if the playback
+ * failed or {@link #stop} was called before the playback finished.
+ */
+ public boolean startAndWait() {
+ HandlerThread thread = new HandlerThread(MEDIA_PLAYER_THREAD_NAME);
+ thread.start();
+ Handler handler = new Handler(thread.getLooper());
+ mFinished = false;
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ startPlaying();
+ }
+ });
+ mDone.block();
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ finish();
+ // No new messages should get posted to the handler thread after this
+ Looper.myLooper().quit();
+ }
+ });
+ return mFinished;
+ }
+
+ /**
+ * Stops playback. Can be called multiple times.
+ * Can be called from any thread.
+ */
+ public void stop() {
+ mDone.open();
+ }
+
+ /**
+ * Starts playback.
+ * Called on the handler thread.
+ */
+ private void startPlaying() {
+ mPlayer = MediaPlayer.create(mContext, mUri);
+ if (mPlayer == null) {
+ Log.w(TAG, "Failed to play " + mUri);
+ mDone.open();
+ return;
+ }
+ try {
+ mPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
+ @Override
+ public boolean onError(MediaPlayer mp, int what, int extra) {
+ Log.w(TAG, "Audio playback error: " + what + ", " + extra);
+ mDone.open();
+ return true;
+ }
+ });
+ mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
+ @Override
+ public void onCompletion(MediaPlayer mp) {
+ mFinished = true;
+ mDone.open();
+ }
+ });
+ mPlayer.setAudioStreamType(mStreamType);
+ mPlayer.start();
+ } catch (IllegalArgumentException ex) {
+ Log.w(TAG, "MediaPlayer failed", ex);
+ mDone.open();
+ }
+ }
+
+ /**
+ * Stops playback and release the media player.
+ * Called on the handler thread.
+ */
+ private void finish() {
+ try {
+ mPlayer.stop();
+ } catch (IllegalStateException ex) {
+ // Do nothing, the player is already stopped
+ }
+ mPlayer.release();
+ }
+
+} \ No newline at end of file
diff --git a/core/java/android/speech/tts/FileSynthesisRequest.java b/core/java/android/speech/tts/FileSynthesisRequest.java
new file mode 100644
index 000000000000..7efc26466c8e
--- /dev/null
+++ b/core/java/android/speech/tts/FileSynthesisRequest.java
@@ -0,0 +1,251 @@
+/*
+ * 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 android.speech.tts;
+
+import android.media.AudioFormat;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Speech synthesis request that writes the audio to a WAV file.
+ */
+class FileSynthesisRequest extends SynthesisRequest {
+
+ private static final String TAG = "FileSynthesisRequest";
+ private static final boolean DBG = false;
+
+ private static final int MAX_AUDIO_BUFFER_SIZE = 8192;
+
+ private static final int WAV_HEADER_LENGTH = 44;
+ private static final short WAV_FORMAT_PCM = 0x0001;
+
+ private final Object mStateLock = new Object();
+ private final File mFileName;
+ private int mSampleRateInHz;
+ private int mAudioFormat;
+ private int mChannelCount;
+ private RandomAccessFile mFile;
+ private boolean mStopped = false;
+ private boolean mDone = false;
+
+ FileSynthesisRequest(String text, File fileName) {
+ super(text);
+ mFileName = fileName;
+ }
+
+ @Override
+ void stop() {
+ synchronized (mStateLock) {
+ mStopped = true;
+ cleanUp();
+ }
+ }
+
+ /**
+ * Must be called while holding the monitor on {@link #mStateLock}.
+ */
+ private void cleanUp() {
+ closeFile();
+ if (mFile != null) {
+ mFileName.delete();
+ }
+ }
+
+ /**
+ * Must be called while holding the monitor on {@link #mStateLock}.
+ */
+ private void closeFile() {
+ try {
+ if (mFile != null) {
+ mFile.close();
+ mFile = null;
+ }
+ } catch (IOException ex) {
+ Log.e(TAG, "Failed to close " + mFileName + ": " + ex);
+ }
+ }
+
+ @Override
+ public int getMaxBufferSize() {
+ return MAX_AUDIO_BUFFER_SIZE;
+ }
+
+ @Override
+ boolean isDone() {
+ return mDone;
+ }
+
+ @Override
+ public int start(int sampleRateInHz, int audioFormat, int channelCount) {
+ if (DBG) {
+ Log.d(TAG, "FileSynthesisRequest.start(" + sampleRateInHz + "," + audioFormat
+ + "," + channelCount + ")");
+ }
+ synchronized (mStateLock) {
+ if (mStopped) {
+ if (DBG) Log.d(TAG, "Request has been aborted.");
+ return TextToSpeech.ERROR;
+ }
+ if (mFile != null) {
+ cleanUp();
+ throw new IllegalArgumentException("FileSynthesisRequest.start() called twice");
+ }
+ mSampleRateInHz = sampleRateInHz;
+ mAudioFormat = audioFormat;
+ mChannelCount = channelCount;
+ try {
+ mFile = new RandomAccessFile(mFileName, "rw");
+ // Reserve space for WAV header
+ mFile.write(new byte[WAV_HEADER_LENGTH]);
+ return TextToSpeech.SUCCESS;
+ } catch (IOException ex) {
+ Log.e(TAG, "Failed to open " + mFileName + ": " + ex);
+ cleanUp();
+ return TextToSpeech.ERROR;
+ }
+ }
+ }
+
+ @Override
+ public int audioAvailable(byte[] buffer, int offset, int length) {
+ if (DBG) {
+ Log.d(TAG, "FileSynthesisRequest.audioAvailable(" + buffer + "," + offset
+ + "," + length + ")");
+ }
+ synchronized (mStateLock) {
+ if (mStopped) {
+ if (DBG) Log.d(TAG, "Request has been aborted.");
+ return TextToSpeech.ERROR;
+ }
+ if (mFile == null) {
+ Log.e(TAG, "File not open");
+ return TextToSpeech.ERROR;
+ }
+ try {
+ mFile.write(buffer, offset, length);
+ return TextToSpeech.SUCCESS;
+ } catch (IOException ex) {
+ Log.e(TAG, "Failed to write to " + mFileName + ": " + ex);
+ cleanUp();
+ return TextToSpeech.ERROR;
+ }
+ }
+ }
+
+ @Override
+ public int done() {
+ if (DBG) Log.d(TAG, "FileSynthesisRequest.done()");
+ synchronized (mStateLock) {
+ if (mStopped) {
+ if (DBG) Log.d(TAG, "Request has been aborted.");
+ return TextToSpeech.ERROR;
+ }
+ if (mFile == null) {
+ Log.e(TAG, "File not open");
+ return TextToSpeech.ERROR;
+ }
+ try {
+ // Write WAV header at start of file
+ mFile.seek(0);
+ int dataLength = (int) (mFile.length() - WAV_HEADER_LENGTH);
+ mFile.write(
+ makeWavHeader(mSampleRateInHz, mAudioFormat, mChannelCount, dataLength));
+ closeFile();
+ mDone = true;
+ return TextToSpeech.SUCCESS;
+ } catch (IOException ex) {
+ Log.e(TAG, "Failed to write to " + mFileName + ": " + ex);
+ cleanUp();
+ return TextToSpeech.ERROR;
+ }
+ }
+ }
+
+ @Override
+ public void error() {
+ if (DBG) Log.d(TAG, "FileSynthesisRequest.error()");
+ synchronized (mStateLock) {
+ cleanUp();
+ }
+ }
+
+ @Override
+ public int completeAudioAvailable(int sampleRateInHz, int audioFormat, int channelCount,
+ byte[] buffer, int offset, int length) {
+ synchronized (mStateLock) {
+ if (mStopped) {
+ if (DBG) Log.d(TAG, "Request has been aborted.");
+ return TextToSpeech.ERROR;
+ }
+ }
+ FileOutputStream out = null;
+ try {
+ out = new FileOutputStream(mFileName);
+ out.write(makeWavHeader(sampleRateInHz, audioFormat, channelCount, length));
+ out.write(buffer, offset, length);
+ mDone = true;
+ return TextToSpeech.SUCCESS;
+ } catch (IOException ex) {
+ Log.e(TAG, "Failed to write to " + mFileName + ": " + ex);
+ mFileName.delete();
+ return TextToSpeech.ERROR;
+ } finally {
+ try {
+ if (out != null) {
+ out.close();
+ }
+ } catch (IOException ex) {
+ Log.e(TAG, "Failed to close " + mFileName + ": " + ex);
+ }
+ }
+ }
+
+ private byte[] makeWavHeader(int sampleRateInHz, int audioFormat, int channelCount,
+ int dataLength) {
+ // TODO: is AudioFormat.ENCODING_DEFAULT always the same as ENCODING_PCM_16BIT?
+ int sampleSizeInBytes = (audioFormat == AudioFormat.ENCODING_PCM_8BIT ? 1 : 2);
+ int byteRate = sampleRateInHz * sampleSizeInBytes * channelCount;
+ short blockAlign = (short) (sampleSizeInBytes * channelCount);
+ short bitsPerSample = (short) (sampleSizeInBytes * 8);
+
+ byte[] headerBuf = new byte[WAV_HEADER_LENGTH];
+ ByteBuffer header = ByteBuffer.wrap(headerBuf);
+ header.order(ByteOrder.LITTLE_ENDIAN);
+
+ header.put(new byte[]{ 'R', 'I', 'F', 'F' });
+ header.putInt(dataLength + WAV_HEADER_LENGTH - 8); // RIFF chunk size
+ header.put(new byte[]{ 'W', 'A', 'V', 'E' });
+ header.put(new byte[]{ 'f', 'm', 't', ' ' });
+ header.putInt(16); // size of fmt chunk
+ header.putShort(WAV_FORMAT_PCM);
+ header.putShort((short) channelCount);
+ header.putInt(sampleRateInHz);
+ header.putInt(byteRate);
+ header.putShort(blockAlign);
+ header.putShort(bitsPerSample);
+ header.put(new byte[]{ 'd', 'a', 't', 'a' });
+ header.putInt(dataLength);
+
+ return headerBuf;
+ }
+
+}
diff --git a/core/java/android/speech/tts/ITtsCallback.aidl b/core/java/android/speech/tts/ITextToSpeechCallback.aidl
index c9898eb76130..40902ae53f9a 100755
--- a/core/java/android/speech/tts/ITtsCallback.aidl
+++ b/core/java/android/speech/tts/ITextToSpeechCallback.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 The Android Open Source Project
+ * 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.
@@ -13,15 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package android.speech.tts;
/**
- * AIDL for the callback from the TTS Service
- * ITtsCallback.java is autogenerated from this.
+ * Interface for callbacks from TextToSpeechService
*
* {@hide}
*/
-oneway interface ITtsCallback {
+oneway interface ITextToSpeechCallback {
void utteranceCompleted(String utteranceId);
}
diff --git a/core/java/android/speech/tts/ITextToSpeechService.aidl b/core/java/android/speech/tts/ITextToSpeechService.aidl
new file mode 100644
index 000000000000..ff3fa112584a
--- /dev/null
+++ b/core/java/android/speech/tts/ITextToSpeechService.aidl
@@ -0,0 +1,140 @@
+/*
+ * 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 android.speech.tts;
+
+import android.net.Uri;
+import android.os.Bundle;
+import android.speech.tts.ITextToSpeechCallback;
+
+/**
+ * Interface for TextToSpeech to talk to TextToSpeechService.
+ *
+ * {@hide}
+ */
+interface ITextToSpeechService {
+
+ /**
+ * Tells the engine to synthesize some speech and play it back.
+ *
+ * @param callingApp The package name of the calling app. Used to connect requests
+ * callbacks and to clear requests when the calling app is stopping.
+ * @param text The text to synthesize.
+ * @param queueMode Determines what to do to requests already in the queue.
+ * @param param Request parameters.
+ */
+ int speak(in String callingApp, in String text, in int queueMode, in Bundle params);
+
+ /**
+ * Tells the engine to synthesize some speech and write it to a file.
+ *
+ * @param callingApp The package name of the calling app. Used to connect requests
+ * callbacks and to clear requests when the calling app is stopping.
+ * @param text The text to synthesize.
+ * @param filename The file to write the synthesized audio to.
+ * @param param Request parameters.
+ */
+ int synthesizeToFile(in String callingApp, in String text,
+ in String filename, in Bundle params);
+
+ /**
+ * Plays an existing audio resource.
+ *
+ * @param callingApp The package name of the calling app. Used to connect requests
+ * callbacks and to clear requests when the calling app is stopping.
+ * @param audioUri URI for the audio resource (a file or android.resource URI)
+ * @param queueMode Determines what to do to requests already in the queue.
+ * @param param Request parameters.
+ */
+ int playAudio(in String callingApp, in Uri audioUri, in int queueMode, in Bundle params);
+
+ /**
+ * Plays silence.
+ *
+ * @param callingApp The package name of the calling app. Used to connect requests
+ * callbacks and to clear requests when the calling app is stopping.
+ * @param duration Number of milliseconds of silence to play.
+ * @param queueMode Determines what to do to requests already in the queue.
+ * @param param Request parameters.
+ */
+ int playSilence(in String callingApp, in long duration, in int queueMode, in Bundle params);
+
+ /**
+ * Checks whether the service is currently playing some audio.
+ */
+ boolean isSpeaking();
+
+ /**
+ * Interrupts the current utterance (if from the given app) and removes any utterances
+ * in the queue that are from the given app.
+ *
+ * @param callingApp Package name of the app whose utterances
+ * should be interrupted and cleared.
+ */
+ int stop(in String callingApp);
+
+ /**
+ * Returns the language, country and variant currently being used by the TTS engine.
+ *
+ * Can be called from multiple threads.
+ *
+ * @return A 3-element array, containing language (ISO 3-letter code),
+ * country (ISO 3-letter code) and variant used by the engine.
+ * The country and variant may be {@code ""}. If country is empty, then variant must
+ * be empty too.
+ */
+ String[] getLanguage();
+
+ /**
+ * Checks whether the engine supports a given language.
+ *
+ * @param lang ISO-3 language code.
+ * @param country ISO-3 country code. May be empty or null.
+ * @param variant Language variant. May be empty or null.
+ * @return Code indicating the support status for the locale.
+ * One of {@link TextToSpeech#LANG_AVAILABLE},
+ * {@link TextToSpeech#LANG_COUNTRY_AVAILABLE},
+ * {@link TextToSpeech#LANG_COUNTRY_VAR_AVAILABLE},
+ * {@link TextToSpeech#LANG_MISSING_DATA}
+ * {@link TextToSpeech#LANG_NOT_SUPPORTED}.
+ */
+ int isLanguageAvailable(in String lang, in String country, in String variant);
+
+ /**
+ * Notifies the engine that it should load a speech synthesis language.
+ *
+ * @param lang ISO-3 language code.
+ * @param country ISO-3 country code. May be empty or null.
+ * @param variant Language variant. May be empty or null.
+ * @return Code indicating the support status for the locale.
+ * One of {@link TextToSpeech#LANG_AVAILABLE},
+ * {@link TextToSpeech#LANG_COUNTRY_AVAILABLE},
+ * {@link TextToSpeech#LANG_COUNTRY_VAR_AVAILABLE},
+ * {@link TextToSpeech#LANG_MISSING_DATA}
+ * {@link TextToSpeech#LANG_NOT_SUPPORTED}.
+ */
+ int loadLanguage(in String lang, in String country, in String variant);
+
+ /**
+ * Sets the callback that will be notified when playback of utterance from the
+ * given app are completed.
+ *
+ * @param callingApp Package name for the app whose utterance the callback will handle.
+ * @param cb The callback.
+ */
+ void setCallback(in String callingApp, ITextToSpeechCallback cb);
+
+}
diff --git a/core/java/android/speech/tts/ITts.aidl b/core/java/android/speech/tts/ITts.aidl
deleted file mode 100755
index c1051c49e02d..000000000000
--- a/core/java/android/speech/tts/ITts.aidl
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.speech.tts;
-
-import android.speech.tts.ITtsCallback;
-
-import android.content.Intent;
-
-/**
- * AIDL for the TTS Service
- * ITts.java is autogenerated from this.
- *
- * {@hide}
- */
-interface ITts {
- int setSpeechRate(in String callingApp, in int speechRate);
-
- int setPitch(in String callingApp, in int pitch);
-
- int speak(in String callingApp, in String text, in int queueMode, in String[] params);
-
- boolean isSpeaking();
-
- int stop(in String callingApp);
-
- void addSpeech(in String callingApp, in String text, in String packageName, in int resId);
-
- void addSpeechFile(in String callingApp, in String text, in String filename);
-
- String[] getLanguage();
-
- int isLanguageAvailable(in String language, in String country, in String variant, in String[] params);
-
- int setLanguage(in String callingApp, in String language, in String country, in String variant);
-
- boolean synthesizeToFile(in String callingApp, in String text, in String[] params, in String outputDirectory);
-
- int playEarcon(in String callingApp, in String earcon, in int queueMode, in String[] params);
-
- void addEarcon(in String callingApp, in String earcon, in String packageName, in int resId);
-
- void addEarconFile(in String callingApp, in String earcon, in String filename);
-
- int registerCallback(in String callingApp, ITtsCallback cb);
-
- int unregisterCallback(in String callingApp, ITtsCallback cb);
-
- int playSilence(in String callingApp, in long duration, in int queueMode, in String[] params);
-
- int setEngineByPackageName(in String enginePackageName);
-
- String getDefaultEngine();
-
- boolean areDefaultsEnforced();
-}
diff --git a/core/java/android/speech/tts/PlaybackSynthesisRequest.java b/core/java/android/speech/tts/PlaybackSynthesisRequest.java
new file mode 100644
index 000000000000..227b0428ed03
--- /dev/null
+++ b/core/java/android/speech/tts/PlaybackSynthesisRequest.java
@@ -0,0 +1,274 @@
+/*
+ * 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 android.speech.tts;
+
+import android.media.AudioFormat;
+import android.media.AudioTrack;
+import android.util.Log;
+
+/**
+ * Speech synthesis request that plays the audio as it is received.
+ */
+class PlaybackSynthesisRequest extends SynthesisRequest {
+
+ private static final String TAG = "PlaybackSynthesisRequest";
+ private static final boolean DBG = false;
+
+ private static final int MIN_AUDIO_BUFFER_SIZE = 8192;
+
+ /**
+ * Audio stream type. Must be one of the STREAM_ contants defined in
+ * {@link android.media.AudioManager}.
+ */
+ private final int mStreamType;
+
+ /**
+ * Volume, in the range [0.0f, 1.0f]. The default value is
+ * {@link TextToSpeech.Engine#DEFAULT_VOLUME} (1.0f).
+ */
+ private final float mVolume;
+
+ /**
+ * Left/right position of the audio, in the range [-1.0f, 1.0f].
+ * The default value is {@link TextToSpeech.Engine#DEFAULT_PAN} (0.0f).
+ */
+ private final float mPan;
+
+ private final Object mStateLock = new Object();
+ private AudioTrack mAudioTrack = null;
+ private boolean mStopped = false;
+ private boolean mDone = false;
+
+ PlaybackSynthesisRequest(String text, int streamType, float volume, float pan) {
+ super(text);
+ mStreamType = streamType;
+ mVolume = volume;
+ mPan = pan;
+ }
+
+ @Override
+ void stop() {
+ if (DBG) Log.d(TAG, "stop()");
+ synchronized (mStateLock) {
+ mStopped = true;
+ cleanUp();
+ }
+ }
+
+ private void cleanUp() {
+ if (DBG) Log.d(TAG, "cleanUp()");
+ if (mAudioTrack != null) {
+ mAudioTrack.flush();
+ mAudioTrack.stop();
+ // TODO: do we need to wait for playback to finish before releasing?
+ mAudioTrack.release();
+ mAudioTrack = null;
+ }
+ }
+
+ @Override
+ public int getMaxBufferSize() {
+ // The AudioTrack buffer will be at least MIN_AUDIO_BUFFER_SIZE, so that should always be
+ // a safe buffer size to pass in.
+ return MIN_AUDIO_BUFFER_SIZE;
+ }
+
+ @Override
+ boolean isDone() {
+ return mDone;
+ }
+
+ // TODO: add a thread that writes to the AudioTrack?
+ @Override
+ public int start(int sampleRateInHz, int audioFormat, int channelCount) {
+ if (DBG) {
+ Log.d(TAG, "start(" + sampleRateInHz + "," + audioFormat
+ + "," + channelCount + ")");
+ }
+
+ synchronized (mStateLock) {
+ if (mStopped) {
+ if (DBG) Log.d(TAG, "Request has been aborted.");
+ return TextToSpeech.ERROR;
+ }
+ if (mAudioTrack != null) {
+ Log.e(TAG, "start() called twice");
+ cleanUp();
+ return TextToSpeech.ERROR;
+ }
+
+ mAudioTrack = createAudioTrack(sampleRateInHz, audioFormat, channelCount,
+ AudioTrack.MODE_STREAM);
+ if (mAudioTrack == null) {
+ return TextToSpeech.ERROR;
+ }
+ }
+
+ return TextToSpeech.SUCCESS;
+ }
+
+ private void setupVolume(AudioTrack audioTrack, float volume, float pan) {
+ float vol = clip(volume, 0.0f, 1.0f);
+ float panning = clip(pan, -1.0f, 1.0f);
+ float volLeft = vol;
+ float volRight = vol;
+ if (panning > 0.0f) {
+ volLeft *= (1.0f - panning);
+ } else if (panning < 0.0f) {
+ volRight *= (1.0f + panning);
+ }
+ if (DBG) Log.d(TAG, "volLeft=" + volLeft + ",volRight=" + volRight);
+ if (audioTrack.setStereoVolume(volLeft, volRight) != AudioTrack.SUCCESS) {
+ Log.e(TAG, "Failed to set volume");
+ }
+ }
+
+ private float clip(float value, float min, float max) {
+ return value > max ? max : (value < min ? min : value);
+ }
+
+ @Override
+ public int audioAvailable(byte[] buffer, int offset, int length) {
+ if (DBG) {
+ Log.d(TAG, "audioAvailable(byte[" + buffer.length + "],"
+ + offset + "," + length + ")");
+ }
+ if (length > getMaxBufferSize()) {
+ throw new IllegalArgumentException("buffer is too large (" + length + " bytes)");
+ }
+ synchronized (mStateLock) {
+ if (mStopped) {
+ if (DBG) Log.d(TAG, "Request has been aborted.");
+ return TextToSpeech.ERROR;
+ }
+ if (mAudioTrack == null) {
+ Log.e(TAG, "audioAvailable(): Not started");
+ return TextToSpeech.ERROR;
+ }
+ int playState = mAudioTrack.getPlayState();
+ if (playState == AudioTrack.PLAYSTATE_STOPPED) {
+ if (DBG) Log.d(TAG, "AudioTrack stopped, restarting");
+ mAudioTrack.play();
+ }
+ // TODO: loop until all data is written?
+ if (DBG) Log.d(TAG, "AudioTrack.write()");
+ int count = mAudioTrack.write(buffer, offset, length);
+ if (DBG) Log.d(TAG, "AudioTrack.write() returned " + count);
+ if (count < 0) {
+ Log.e(TAG, "Writing to AudioTrack failed: " + count);
+ cleanUp();
+ return TextToSpeech.ERROR;
+ } else {
+ return TextToSpeech.SUCCESS;
+ }
+ }
+ }
+
+ @Override
+ public int done() {
+ if (DBG) Log.d(TAG, "done()");
+ synchronized (mStateLock) {
+ if (mStopped) {
+ if (DBG) Log.d(TAG, "Request has been aborted.");
+ return TextToSpeech.ERROR;
+ }
+ if (mAudioTrack == null) {
+ Log.e(TAG, "done(): Not started");
+ return TextToSpeech.ERROR;
+ }
+ mDone = true;
+ cleanUp();
+ }
+ return TextToSpeech.SUCCESS;
+ }
+
+ @Override
+ public void error() {
+ if (DBG) Log.d(TAG, "error()");
+ synchronized (mStateLock) {
+ cleanUp();
+ }
+ }
+
+ @Override
+ public int completeAudioAvailable(int sampleRateInHz, int audioFormat, int channelCount,
+ byte[] buffer, int offset, int length) {
+ if (DBG) {
+ Log.d(TAG, "completeAudioAvailable(" + sampleRateInHz + "," + audioFormat
+ + "," + channelCount + "byte[" + buffer.length + "],"
+ + offset + "," + length + ")");
+ }
+
+ synchronized (mStateLock) {
+ if (mStopped) {
+ if (DBG) Log.d(TAG, "Request has been aborted.");
+ return TextToSpeech.ERROR;
+ }
+ if (mAudioTrack != null) {
+ Log.e(TAG, "start() called before completeAudioAvailable()");
+ cleanUp();
+ return TextToSpeech.ERROR;
+ }
+
+ mAudioTrack = createAudioTrack(sampleRateInHz, audioFormat, channelCount,
+ AudioTrack.MODE_STATIC);
+ if (mAudioTrack == null) {
+ return TextToSpeech.ERROR;
+ }
+
+ try {
+ mAudioTrack.write(buffer, offset, length);
+ mAudioTrack.play();
+ mDone = true;
+ } catch (IllegalStateException ex) {
+ Log.e(TAG, "Playback error", ex);
+ return TextToSpeech.ERROR;
+ } finally {
+ cleanUp();
+ }
+ }
+
+ return TextToSpeech.SUCCESS;
+ }
+
+ private AudioTrack createAudioTrack(int sampleRateInHz, int audioFormat, int channelCount,
+ int mode) {
+ int channelConfig;
+ if (channelCount == 1) {
+ channelConfig = AudioFormat.CHANNEL_OUT_MONO;
+ } else if (channelCount == 2){
+ channelConfig = AudioFormat.CHANNEL_OUT_STEREO;
+ } else {
+ Log.e(TAG, "Unsupported number of channels: " + channelCount);
+ return null;
+ }
+
+ int minBufferSizeInBytes
+ = AudioTrack.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat);
+ int bufferSizeInBytes = Math.max(MIN_AUDIO_BUFFER_SIZE, minBufferSizeInBytes);
+ AudioTrack audioTrack = new AudioTrack(mStreamType, sampleRateInHz, channelConfig,
+ audioFormat, bufferSizeInBytes, mode);
+ if (audioTrack == null) {
+ return null;
+ }
+ if (audioTrack.getState() != AudioTrack.STATE_INITIALIZED) {
+ audioTrack.release();
+ return null;
+ }
+ setupVolume(audioTrack, mVolume, mPan);
+ return audioTrack;
+ }
+} \ No newline at end of file
diff --git a/core/java/android/speech/tts/SynthesisRequest.java b/core/java/android/speech/tts/SynthesisRequest.java
new file mode 100644
index 000000000000..515218b2a38e
--- /dev/null
+++ b/core/java/android/speech/tts/SynthesisRequest.java
@@ -0,0 +1,193 @@
+/*
+ * 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 android.speech.tts;
+
+/**
+ * A request for speech synthesis given to a TTS engine for processing.
+ *
+ * The engine can provide streaming audio by calling
+ * {@link #start}, then {@link #audioAvailable} until all audio has been provided, then finally
+ * {@link #done}.
+ *
+ * Alternatively, the engine can provide all the audio at once, by using
+ * {@link #completeAudioAvailable}.
+ *
+ * @hide Pending approval
+ */
+public abstract class SynthesisRequest {
+
+ private final String mText;
+ private String mLanguage;
+ private String mCountry;
+ private String mVariant;
+ private int mSpeechRate;
+ private int mPitch;
+
+ public SynthesisRequest(String text) {
+ mText = text;
+ }
+
+ /**
+ * Sets the locale for the request.
+ */
+ void setLanguage(String language, String country, String variant) {
+ mLanguage = language;
+ mCountry = country;
+ mVariant = variant;
+ }
+
+ /**
+ * Sets the speech rate.
+ */
+ void setSpeechRate(int speechRate) {
+ mSpeechRate = speechRate;
+ }
+
+ /**
+ * Sets the pitch.
+ */
+ void setPitch(int pitch) {
+ mPitch = pitch;
+ }
+
+ /**
+ * Gets the text which should be synthesized.
+ */
+ public String getText() {
+ return mText;
+ }
+
+ /**
+ * Gets the ISO 3-letter language code for the language to use.
+ */
+ public String getLanguage() {
+ return mLanguage;
+ }
+
+ /**
+ * Gets the ISO 3-letter country code for the language to use.
+ */
+ public String getCountry() {
+ return mCountry;
+ }
+
+ /**
+ * Gets the language variant to use.
+ */
+ public String getVariant() {
+ return mVariant;
+ }
+
+ /**
+ * Gets the speech rate to use. {@link TextToSpeech.Engine#DEFAULT_RATE} (100)
+ * is the normal rate.
+ */
+ public int getSpeechRate() {
+ return mSpeechRate;
+ }
+
+ /**
+ * Gets the pitch to use. {@link TextToSpeech.Engine#DEFAULT_PITCH} (100)
+ * is the normal pitch.
+ */
+ public int getPitch() {
+ return mPitch;
+ }
+
+ /**
+ * Gets the maximum number of bytes that the TTS engine can pass in a single call of
+ * {@link #audioAvailable}. This does not apply to {@link #completeAudioAvailable}.
+ */
+ public abstract int getMaxBufferSize();
+
+ /**
+ * Checks whether the synthesis request completed successfully.
+ */
+ abstract boolean isDone();
+
+ /**
+ * Aborts the speech request.
+ *
+ * Can be called from multiple threads.
+ */
+ abstract void stop();
+
+ /**
+ * The service should call this when it starts to synthesize audio for this
+ * request.
+ *
+ * This method should only be called on the synthesis thread,
+ * while in {@link TextToSpeechService#onSynthesizeText}.
+ *
+ * @param sampleRateInHz Sample rate in HZ of the generated audio.
+ * @param audioFormat Audio format of the generated audio. Must be one of
+ * the ENCODING_ constants defined in {@link android.media.AudioFormat}.
+ * @param channelCount The number of channels. Must be {@code 1} or {@code 2}.
+ * @return {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}.
+ */
+ public abstract int start(int sampleRateInHz, int audioFormat, int channelCount);
+
+ /**
+ * The service should call this method when synthesized audio is ready for consumption.
+ *
+ * This method should only be called on the synthesis thread,
+ * while in {@link TextToSpeechService#onSynthesizeText}.
+ *
+ * @param buffer The generated audio data. This method will not hold on to {@code buffer},
+ * so the caller is free to modify it after this method returns.
+ * @param offset The offset into {@code buffer} where the audio data starts.
+ * @param length The number of bytes of audio data in {@code buffer}. This must be
+ * less than or equal to the return value of {@link #getMaxBufferSize}.
+ * @return {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}.
+ */
+ public abstract int audioAvailable(byte[] buffer, int offset, int length);
+
+ /**
+ * The service should call this method when all the synthesized audio for a request has
+ * been passed to {@link #audioAvailable}.
+ *
+ * This method should only be called on the synthesis thread,
+ * while in {@link TextToSpeechService#onSynthesizeText}.
+ *
+ * @return {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}.
+ */
+ public abstract int done();
+
+ /**
+ * The service should call this method if the speech synthesis fails.
+ *
+ * This method should only be called on the synthesis thread,
+ * while in {@link TextToSpeechService#onSynthesizeText}.
+ */
+ public abstract void error();
+
+ /**
+ * The service can call this method instead of using {@link #start}, {@link #audioAvailable}
+ * and {@link #done} if all the audio data is available in a single buffer.
+ *
+ * @param sampleRateInHz Sample rate in HZ of the generated audio.
+ * @param audioFormat Audio format of the generated audio. Must be one of
+ * the ENCODING_ constants defined in {@link android.media.AudioFormat}.
+ * @param channelCount The number of channels. Must be {@code 1} or {@code 2}.
+ * @param buffer The generated audio data. This method will not hold on to {@code buffer},
+ * so the caller is free to modify it after this method returns.
+ * @param offset The offset into {@code buffer} where the audio data starts.
+ * @param length The number of bytes of audio data in {@code buffer}.
+ * @return {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}.
+ */
+ public abstract int completeAudioAvailable(int sampleRateInHz, int audioFormat,
+ int channelCount, byte[] buffer, int offset, int length);
+} \ No newline at end of file
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index 95830ecf2947..e247df8dd9f3 100755
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009 Google Inc.
+ * 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
@@ -15,22 +15,31 @@
*/
package android.speech.tts;
-import android.speech.tts.ITts;
-import android.speech.tts.ITtsCallback;
-
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.content.ComponentName;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
import android.media.AudioManager;
+import android.net.Uri;
+import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
+import android.provider.Settings;
+import android.text.TextUtils;
import android.util.Log;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.List;
import java.util.Locale;
+import java.util.Map;
/**
*
@@ -49,11 +58,11 @@ public class TextToSpeech {
/**
* Denotes a successful operation.
*/
- public static final int SUCCESS = 0;
+ public static final int SUCCESS = 0;
/**
* Denotes a generic operation failure.
*/
- public static final int ERROR = -1;
+ public static final int ERROR = -1;
/**
* Queue mode where all entries in the playback queue (media to be played
@@ -65,20 +74,17 @@ public class TextToSpeech {
*/
public static final int QUEUE_ADD = 1;
-
/**
* Denotes the language is available exactly as specified by the locale.
*/
public static final int LANG_COUNTRY_VAR_AVAILABLE = 2;
-
/**
* Denotes the language is available for the language and country specified
* by the locale, but not the variant.
*/
public static final int LANG_COUNTRY_AVAILABLE = 1;
-
/**
* Denotes the language is available for the language by the locale,
* but not the country and variant.
@@ -95,7 +101,6 @@ public class TextToSpeech {
*/
public static final int LANG_NOT_SUPPORTED = -2;
-
/**
* Broadcast Action: The TextToSpeech synthesizer has completed processing
* of all the text in the speech queue.
@@ -104,7 +109,6 @@ public class TextToSpeech {
public static final String ACTION_TTS_QUEUE_PROCESSING_COMPLETED =
"android.speech.tts.TTS_QUEUE_PROCESSING_COMPLETED";
-
/**
* Interface definition of a callback to be invoked indicating the completion of the
* TextToSpeech engine initialization.
@@ -112,103 +116,117 @@ public class TextToSpeech {
public interface OnInitListener {
/**
* Called to signal the completion of the TextToSpeech engine initialization.
+ *
* @param status {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}.
*/
public void onInit(int status);
}
/**
- * Interface definition of a callback to be invoked indicating the TextToSpeech engine has
- * completed synthesizing an utterance with an utterance ID set.
- *
+ * Listener that will be called when the TTS service has
+ * completed synthesizing an utterance. This is only called if the utterance
+ * has an utterance ID (see {@link TextToSpeech.Engine#KEY_PARAM_UTTERANCE_ID}).
*/
public interface OnUtteranceCompletedListener {
/**
- * Called to signal the completion of the synthesis of the utterance that was identified
- * with the string parameter. This identifier is the one originally passed in the
- * parameter hashmap of the synthesis request in
- * {@link TextToSpeech#speak(String, int, HashMap)} or
- * {@link TextToSpeech#synthesizeToFile(String, HashMap, String)} with the
- * {@link TextToSpeech.Engine#KEY_PARAM_UTTERANCE_ID} key.
+ * Called when an utterance has been synthesized.
+ *
* @param utteranceId the identifier of the utterance.
*/
public void onUtteranceCompleted(String utteranceId);
}
-
/**
- * Internal constants for the TextToSpeech functionality
- *
+ * Constants and parameter names for controlling text-to-speech.
*/
public class Engine {
- // default values for a TTS engine when settings are not found in the provider
+
/**
- * {@hide}
+ * Default speech rate.
+ * @hide
*/
- public static final int DEFAULT_RATE = 100; // 1x
+ public static final int DEFAULT_RATE = 100;
+
/**
- * {@hide}
+ * Default pitch.
+ * @hide
*/
- public static final int DEFAULT_PITCH = 100;// 1x
+ public static final int DEFAULT_PITCH = 100;
+
/**
- * {@hide}
+ * Default volume.
+ * @hide
*/
public static final float DEFAULT_VOLUME = 1.0f;
+
/**
- * {@hide}
- */
- protected static final String DEFAULT_VOLUME_STRING = "1.0";
- /**
- * {@hide}
+ * Default pan (centered).
+ * @hide
*/
public static final float DEFAULT_PAN = 0.0f;
- /**
- * {@hide}
- */
- protected static final String DEFAULT_PAN_STRING = "0.0";
/**
- * {@hide}
+ * Default value for {@link Settings.Secure#TTS_USE_DEFAULTS}.
+ * @hide
*/
public static final int USE_DEFAULTS = 0; // false
+
/**
- * {@hide}
+ * Package name of the default TTS engine.
+ *
+ * TODO: This should come from a system property
+ *
+ * @hide
*/
- public static final String DEFAULT_SYNTH = "com.svox.pico";
+ public static final String DEFAULT_ENGINE = "com.svox.pico";
- // default values for rendering
/**
* Default audio stream used when playing synthesized speech.
*/
public static final int DEFAULT_STREAM = AudioManager.STREAM_MUSIC;
- // return codes for a TTS engine's check data activity
/**
* Indicates success when checking the installation status of the resources used by the
* TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
*/
public static final int CHECK_VOICE_DATA_PASS = 1;
+
/**
* Indicates failure when checking the installation status of the resources used by the
* TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
*/
public static final int CHECK_VOICE_DATA_FAIL = 0;
+
/**
* Indicates erroneous data when checking the installation status of the resources used by
* the TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
*/
public static final int CHECK_VOICE_DATA_BAD_DATA = -1;
+
/**
* Indicates missing resources when checking the installation status of the resources used
* by the TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
*/
public static final int CHECK_VOICE_DATA_MISSING_DATA = -2;
+
/**
* Indicates missing storage volume when checking the installation status of the resources
* used by the TextToSpeech engine with the {@link #ACTION_CHECK_TTS_DATA} intent.
*/
public static final int CHECK_VOICE_DATA_MISSING_VOLUME = -3;
+ /**
+ * Intent for starting a TTS service. Services that handle this intent must
+ * extend {@link TextToSpeechService}. Normal applications should not use this intent
+ * directly, instead they should talk to the TTS service using the the methods in this
+ * class.
+ *
+ * @hide Pending API council approval
+ */
+ @SdkConstant(SdkConstantType.SERVICE_ACTION)
+ public static final String INTENT_ACTION_TTS_SERVICE =
+ "android.intent.action.TTS_SERVICE";
+
// intents to ask engine to install data or check its data
/**
* Activity Action: Triggers the platform TextToSpeech engine to
@@ -231,6 +249,7 @@ public class TextToSpeech {
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_TTS_DATA_INSTALLED =
"android.speech.tts.engine.TTS_DATA_INSTALLED";
+
/**
* Activity Action: Starts the activity from the platform TextToSpeech
* engine to verify the proper installation and availability of the
@@ -258,23 +277,36 @@ public class TextToSpeech {
public static final String ACTION_CHECK_TTS_DATA =
"android.speech.tts.engine.CHECK_TTS_DATA";
+ /**
+ * Activity intent for getting some sample text to use for demonstrating TTS.
+ *
+ * @hide This intent was used by engines written against the old API.
+ * Not sure if it should be exposed.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_GET_SAMPLE_TEXT =
+ "android.speech.tts.engine.GET_SAMPLE_TEXT";
+
// extras for a TTS engine's check data activity
/**
* Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where
* the TextToSpeech engine specifies the path to its resources.
*/
public static final String EXTRA_VOICE_DATA_ROOT_DIRECTORY = "dataRoot";
+
/**
* Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where
* the TextToSpeech engine specifies the file names of its resources under the
* resource path.
*/
public static final String EXTRA_VOICE_DATA_FILES = "dataFiles";
+
/**
* Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where
* the TextToSpeech engine specifies the locale associated with each resource file.
*/
public static final String EXTRA_VOICE_DATA_FILES_INFO = "dataFilesInfo";
+
/**
* Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where
* the TextToSpeech engine returns an ArrayList<String> of all the available voices.
@@ -282,6 +314,7 @@ public class TextToSpeech {
* optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE").
*/
public static final String EXTRA_AVAILABLE_VOICES = "availableVoices";
+
/**
* Extra information received with the {@link #ACTION_CHECK_TTS_DATA} intent where
* the TextToSpeech engine returns an ArrayList<String> of all the unavailable voices.
@@ -289,6 +322,7 @@ public class TextToSpeech {
* optional (ie, "eng" or "eng-USA" or "eng-USA-FEMALE").
*/
public static final String EXTRA_UNAVAILABLE_VOICES = "unavailableVoices";
+
/**
* Extra information sent with the {@link #ACTION_CHECK_TTS_DATA} intent where the
* caller indicates to the TextToSpeech engine which specific sets of voice data to
@@ -311,134 +345,87 @@ public class TextToSpeech {
// keys for the parameters passed with speak commands. Hidden keys are used internally
// to maintain engine state for each TextToSpeech instance.
/**
- * {@hide}
+ * @hide
*/
public static final String KEY_PARAM_RATE = "rate";
+
/**
- * {@hide}
+ * @hide
*/
public static final String KEY_PARAM_LANGUAGE = "language";
+
/**
- * {@hide}
+ * @hide
*/
public static final String KEY_PARAM_COUNTRY = "country";
+
/**
- * {@hide}
+ * @hide
*/
public static final String KEY_PARAM_VARIANT = "variant";
+
/**
- * {@hide}
+ * @hide
*/
public static final String KEY_PARAM_ENGINE = "engine";
+
/**
- * {@hide}
+ * @hide
*/
public static final String KEY_PARAM_PITCH = "pitch";
+
/**
* Parameter key to specify the audio stream type to be used when speaking text
- * or playing back a file.
+ * or playing back a file. The value should be one of the STREAM_ constants
+ * defined in {@link AudioManager}.
+ *
* @see TextToSpeech#speak(String, int, HashMap)
* @see TextToSpeech#playEarcon(String, int, HashMap)
*/
public static final String KEY_PARAM_STREAM = "streamType";
+
/**
* Parameter key to identify an utterance in the
* {@link TextToSpeech.OnUtteranceCompletedListener} after text has been
* spoken, a file has been played back or a silence duration has elapsed.
+ *
* @see TextToSpeech#speak(String, int, HashMap)
* @see TextToSpeech#playEarcon(String, int, HashMap)
* @see TextToSpeech#synthesizeToFile(String, HashMap, String)
*/
public static final String KEY_PARAM_UTTERANCE_ID = "utteranceId";
+
/**
* Parameter key to specify the speech volume relative to the current stream type
* volume used when speaking text. Volume is specified as a float ranging from 0 to 1
* where 0 is silence, and 1 is the maximum volume (the default behavior).
+ *
* @see TextToSpeech#speak(String, int, HashMap)
* @see TextToSpeech#playEarcon(String, int, HashMap)
*/
public static final String KEY_PARAM_VOLUME = "volume";
+
/**
* Parameter key to specify how the speech is panned from left to right when speaking text.
* Pan is specified as a float ranging from -1 to +1 where -1 maps to a hard-left pan,
* 0 to center (the default behavior), and +1 to hard-right.
+ *
* @see TextToSpeech#speak(String, int, HashMap)
* @see TextToSpeech#playEarcon(String, int, HashMap)
*/
public static final String KEY_PARAM_PAN = "pan";
- // key positions in the array of cached parameters
- /**
- * {@hide}
- */
- protected static final int PARAM_POSITION_RATE = 0;
- /**
- * {@hide}
- */
- protected static final int PARAM_POSITION_LANGUAGE = 2;
- /**
- * {@hide}
- */
- protected static final int PARAM_POSITION_COUNTRY = 4;
- /**
- * {@hide}
- */
- protected static final int PARAM_POSITION_VARIANT = 6;
- /**
- * {@hide}
- */
- protected static final int PARAM_POSITION_STREAM = 8;
- /**
- * {@hide}
- */
- protected static final int PARAM_POSITION_UTTERANCE_ID = 10;
-
- /**
- * {@hide}
- */
- protected static final int PARAM_POSITION_ENGINE = 12;
-
- /**
- * {@hide}
- */
- protected static final int PARAM_POSITION_PITCH = 14;
-
- /**
- * {@hide}
- */
- protected static final int PARAM_POSITION_VOLUME = 16;
-
- /**
- * {@hide}
- */
- protected static final int PARAM_POSITION_PAN = 18;
-
-
- /**
- * {@hide}
- * Total number of cached speech parameters.
- * This number should be equal to (max param position/2) + 1.
- */
- protected static final int NB_CACHED_PARAMS = 10;
}
- /**
- * Connection needed for the TTS.
- */
- private ServiceConnection mServiceConnection;
-
- private ITts mITts = null;
- private ITtsCallback mITtscallback = null;
- private Context mContext = null;
- private String mPackageName = "";
- private OnInitListener mInitListener = null;
- private boolean mStarted = false;
+ private final Context mContext;
+ private Connection mServiceConnection;
+ private OnInitListener mInitListener;
private final Object mStartLock = new Object();
- /**
- * Used to store the cached parameters sent along with each synthesis request to the
- * TTS service.
- */
- private String[] mCachedParams;
+
+ private String mRequestedEngine;
+ private final Map<String, Uri> mEarcons;
+ private final Map<String, Uri> mUtterances;
+ private final Bundle mParams = new Bundle();
/**
* The constructor for the TextToSpeech class.
@@ -451,84 +438,98 @@ public class TextToSpeech {
* TextToSpeech engine has initialized.
*/
public TextToSpeech(Context context, OnInitListener listener) {
+ this(context, listener, null);
+ }
+
+ /**
+ * @hide pending approval
+ */
+ public TextToSpeech(Context context, OnInitListener listener, String engine) {
mContext = context;
- mPackageName = mContext.getPackageName();
mInitListener = listener;
+ mRequestedEngine = engine;
- mCachedParams = new String[2*Engine.NB_CACHED_PARAMS]; // store key and value
- mCachedParams[Engine.PARAM_POSITION_RATE] = Engine.KEY_PARAM_RATE;
- mCachedParams[Engine.PARAM_POSITION_LANGUAGE] = Engine.KEY_PARAM_LANGUAGE;
- mCachedParams[Engine.PARAM_POSITION_COUNTRY] = Engine.KEY_PARAM_COUNTRY;
- mCachedParams[Engine.PARAM_POSITION_VARIANT] = Engine.KEY_PARAM_VARIANT;
- mCachedParams[Engine.PARAM_POSITION_STREAM] = Engine.KEY_PARAM_STREAM;
- mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID] = Engine.KEY_PARAM_UTTERANCE_ID;
- mCachedParams[Engine.PARAM_POSITION_ENGINE] = Engine.KEY_PARAM_ENGINE;
- mCachedParams[Engine.PARAM_POSITION_PITCH] = Engine.KEY_PARAM_PITCH;
- mCachedParams[Engine.PARAM_POSITION_VOLUME] = Engine.KEY_PARAM_VOLUME;
- mCachedParams[Engine.PARAM_POSITION_PAN] = Engine.KEY_PARAM_PAN;
-
- // Leave all defaults that are shown in Settings uninitialized/at the default
- // so that the values set in Settings will take effect if the application does
- // not try to change these settings itself.
- mCachedParams[Engine.PARAM_POSITION_RATE + 1] = "";
- mCachedParams[Engine.PARAM_POSITION_LANGUAGE + 1] = "";
- mCachedParams[Engine.PARAM_POSITION_COUNTRY + 1] = "";
- mCachedParams[Engine.PARAM_POSITION_VARIANT + 1] = "";
- mCachedParams[Engine.PARAM_POSITION_STREAM + 1] =
- String.valueOf(Engine.DEFAULT_STREAM);
- mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID + 1] = "";
- mCachedParams[Engine.PARAM_POSITION_ENGINE + 1] = "";
- mCachedParams[Engine.PARAM_POSITION_PITCH + 1] = "100";
- mCachedParams[Engine.PARAM_POSITION_VOLUME + 1] = Engine.DEFAULT_VOLUME_STRING;
- mCachedParams[Engine.PARAM_POSITION_PAN + 1] = Engine.DEFAULT_PAN_STRING;
+ mEarcons = new HashMap<String, Uri>();
+ mUtterances = new HashMap<String, Uri>();
initTts();
}
+ private String getPackageName() {
+ return mContext.getPackageName();
+ }
- private void initTts() {
- mStarted = false;
-
- // Initialize the TTS, run the callback after the binding is successful
- mServiceConnection = new ServiceConnection() {
- public void onServiceConnected(ComponentName name, IBinder service) {
- synchronized(mStartLock) {
- mITts = ITts.Stub.asInterface(service);
- mStarted = true;
- // Cache the default engine and current language
- setEngineByPackageName(getDefaultEngine());
- setLanguage(getLanguage());
- if (mInitListener != null) {
- // TODO manage failures and missing resources
- mInitListener.onInit(SUCCESS);
- }
- }
+ private <R> R runActionNoReconnect(Action<R> action, R errorResult, String method) {
+ return runAction(action, errorResult, method, false);
+ }
+
+ private <R> R runAction(Action<R> action, R errorResult, String method) {
+ return runAction(action, errorResult, method, true);
+ }
+
+ private <R> R runAction(Action<R> action, R errorResult, String method, boolean reconnect) {
+ synchronized (mStartLock) {
+ if (mServiceConnection == null) {
+ Log.w(TAG, method + " failed: not bound to TTS engine");
+ return errorResult;
}
+ return mServiceConnection.runAction(action, errorResult, method, reconnect);
+ }
+ }
- public void onServiceDisconnected(ComponentName name) {
- synchronized(mStartLock) {
- mITts = null;
- mInitListener = null;
- mStarted = false;
- }
+ private int initTts() {
+ String defaultEngine = getDefaultEngine();
+ String engine = defaultEngine;
+ if (!areDefaultsEnforced() && !TextUtils.isEmpty(mRequestedEngine)
+ && isEngineEnabled(engine)) {
+ engine = mRequestedEngine;
+ }
+
+ // Try requested engine
+ if (connectToEngine(engine)) {
+ return SUCCESS;
+ }
+
+ // Fall back to user's default engine if different from the already tested one
+ if (!engine.equals(defaultEngine)) {
+ if (connectToEngine(defaultEngine)) {
+ return SUCCESS;
}
- };
+ }
- Intent intent = new Intent("android.intent.action.START_TTS_SERVICE");
- intent.addCategory("android.intent.category.TTS");
- boolean bound = mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
- if (!bound) {
- Log.e("TextToSpeech.java", "initTts() failed to bind to service");
- if (mInitListener != null) {
- mInitListener.onInit(ERROR);
+ // Fall back to the hardcoded default if different from the two above
+ if (!defaultEngine.equals(Engine.DEFAULT_ENGINE)
+ && !engine.equals(Engine.DEFAULT_ENGINE)) {
+ if (connectToEngine(Engine.DEFAULT_ENGINE)) {
+ return SUCCESS;
}
+ }
+
+ return ERROR;
+ }
+
+ private boolean connectToEngine(String engine) {
+ Connection connection = new Connection();
+ Intent intent = new Intent(Engine.INTENT_ACTION_TTS_SERVICE);
+ intent.setPackage(engine);
+ boolean bound = mContext.bindService(intent, connection, Context.BIND_AUTO_CREATE);
+ if (!bound) {
+ Log.e(TAG, "Failed to bind to " + engine);
+ dispatchOnInit(ERROR);
+ return false;
} else {
- // initialization listener will be called inside ServiceConnection
- Log.i("TextToSpeech.java", "initTts() successfully bound to service");
+ return true;
}
- // TODO handle plugin failures
}
+ private void dispatchOnInit(int result) {
+ synchronized (mStartLock) {
+ if (mInitListener != null) {
+ mInitListener.onInit(result);
+ mInitListener = null;
+ }
+ }
+ }
/**
* Releases the resources used by the TextToSpeech engine.
@@ -536,15 +537,17 @@ public class TextToSpeech {
* so the TextToSpeech engine can be cleanly stopped.
*/
public void shutdown() {
- try {
- mContext.unbindService(mServiceConnection);
- } catch (IllegalArgumentException e) {
- // Do nothing and fail silently since an error here indicates that
- // binding never succeeded in the first place.
- }
+ runActionNoReconnect(new Action<Void>() {
+ @Override
+ public Void run(ITextToSpeechService service) throws RemoteException {
+ service.setCallback(getPackageName(), null);
+ service.stop(getPackageName());
+ mServiceConnection.disconnect();
+ return null;
+ }
+ }, null, "shutdown");
}
-
/**
* Adds a mapping between a string of text and a sound resource in a
* package. After a call to this method, subsequent calls to
@@ -573,21 +576,9 @@ public class TextToSpeech {
* @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
*/
public int addSpeech(String text, String packagename, int resourceId) {
- synchronized(mStartLock) {
- if (!mStarted) {
- return ERROR;
- }
- try {
- mITts.addSpeech(mPackageName, text, packagename, resourceId);
- return SUCCESS;
- } catch (RemoteException e) {
- restart("addSpeech", e);
- } catch (NullPointerException e) {
- restart("addSpeech", e);
- } catch (IllegalStateException e) {
- restart("addSpeech", e);
- }
- return ERROR;
+ synchronized (mStartLock) {
+ mUtterances.put(text, makeResourceUri(packagename, resourceId));
+ return SUCCESS;
}
}
@@ -608,20 +599,8 @@ public class TextToSpeech {
*/
public int addSpeech(String text, String filename) {
synchronized (mStartLock) {
- if (!mStarted) {
- return ERROR;
- }
- try {
- mITts.addSpeechFile(mPackageName, text, filename);
- return SUCCESS;
- } catch (RemoteException e) {
- restart("addSpeech", e);
- } catch (NullPointerException e) {
- restart("addSpeech", e);
- } catch (IllegalStateException e) {
- restart("addSpeech", e);
- }
- return ERROR;
+ mUtterances.put(text, Uri.parse(filename));
+ return SUCCESS;
}
}
@@ -653,24 +632,11 @@ public class TextToSpeech {
*/
public int addEarcon(String earcon, String packagename, int resourceId) {
synchronized(mStartLock) {
- if (!mStarted) {
- return ERROR;
- }
- try {
- mITts.addEarcon(mPackageName, earcon, packagename, resourceId);
- return SUCCESS;
- } catch (RemoteException e) {
- restart("addEarcon", e);
- } catch (NullPointerException e) {
- restart("addEarcon", e);
- } catch (IllegalStateException e) {
- restart("addEarcon", e);
- }
- return ERROR;
+ mEarcons.put(earcon, makeResourceUri(packagename, resourceId));
+ return SUCCESS;
}
}
-
/**
* Adds a mapping between a string of text and a sound file.
* Use this to add custom earcons.
@@ -687,312 +653,199 @@ public class TextToSpeech {
* @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
*/
public int addEarcon(String earcon, String filename) {
- synchronized (mStartLock) {
- if (!mStarted) {
- return ERROR;
- }
- try {
- mITts.addEarconFile(mPackageName, earcon, filename);
- return SUCCESS;
- } catch (RemoteException e) {
- restart("addEarcon", e);
- } catch (NullPointerException e) {
- restart("addEarcon", e);
- } catch (IllegalStateException e) {
- restart("addEarcon", e);
- }
- return ERROR;
+ synchronized(mStartLock) {
+ mEarcons.put(earcon, Uri.parse(filename));
+ return SUCCESS;
}
}
+ private Uri makeResourceUri(String packageName, int resourceId) {
+ return new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
+ .encodedAuthority(packageName)
+ .appendEncodedPath(String.valueOf(resourceId))
+ .build();
+ }
/**
* Speaks the string using the specified queuing strategy and speech
* parameters.
*
- * @param text
- * The string of text to be spoken.
- * @param queueMode
- * The queuing strategy to use.
- * {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}.
- * @param params
- * The list of parameters to be used. Can be null if no parameters are given.
- * They are specified using a (key, value) pair, where the key can be
- * {@link Engine#KEY_PARAM_STREAM} or
- * {@link Engine#KEY_PARAM_UTTERANCE_ID}.
+ * @param text The string of text to be spoken.
+ * @param queueMode The queuing strategy to use, {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}.
+ * @param params Parameters for the request. Can be null.
+ * Supported parameter names:
+ * {@link Engine#KEY_PARAM_STREAM},
+ * {@link Engine#KEY_PARAM_UTTERANCE_ID},
+ * {@link Engine#KEY_PARAM_VOLUME},
+ * {@link Engine#KEY_PARAM_PAN}.
*
- * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
+ * @return {@link #ERROR} or {@link #SUCCESS}.
*/
- public int speak(String text, int queueMode, HashMap<String,String> params)
- {
- synchronized (mStartLock) {
- int result = ERROR;
- Log.i("TextToSpeech.java - speak", "speak text of length " + text.length());
- if (!mStarted) {
- Log.e("TextToSpeech.java - speak", "service isn't started");
- return result;
- }
- try {
- if ((params != null) && (!params.isEmpty())) {
- setCachedParam(params, Engine.KEY_PARAM_STREAM, Engine.PARAM_POSITION_STREAM);
- setCachedParam(params, Engine.KEY_PARAM_UTTERANCE_ID,
- Engine.PARAM_POSITION_UTTERANCE_ID);
- setCachedParam(params, Engine.KEY_PARAM_ENGINE, Engine.PARAM_POSITION_ENGINE);
- setCachedParam(params, Engine.KEY_PARAM_VOLUME, Engine.PARAM_POSITION_VOLUME);
- setCachedParam(params, Engine.KEY_PARAM_PAN, Engine.PARAM_POSITION_PAN);
+ public int speak(final String text, final int queueMode, final HashMap<String, String> params) {
+ return runAction(new Action<Integer>() {
+ @Override
+ public Integer run(ITextToSpeechService service) throws RemoteException {
+ Uri utteranceUri = mUtterances.get(text);
+ if (utteranceUri != null) {
+ return service.playAudio(getPackageName(), utteranceUri, queueMode,
+ getParams(params));
+ } else {
+ return service.speak(getPackageName(), text, queueMode, getParams(params));
}
- result = mITts.speak(mPackageName, text, queueMode, mCachedParams);
- } catch (RemoteException e) {
- restart("speak", e);
- } catch (NullPointerException e) {
- restart("speak", e);
- } catch (IllegalStateException e) {
- restart("speak", e);
- } finally {
- resetCachedParams();
}
- return result;
- }
+ }, ERROR, "speak");
}
-
/**
* Plays the earcon using the specified queueing mode and parameters.
+ * The earcon must already have been added with {@link #addEarcon(String, String)} or
+ * {@link #addEarcon(String, String, int)}.
*
- * @param earcon
- * The earcon that should be played
- * @param queueMode
- * {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}.
- * @param params
- * The list of parameters to be used. Can be null if no parameters are given.
- * They are specified using a (key, value) pair, where the key can be
- * {@link Engine#KEY_PARAM_STREAM} or
+ * @param earcon The earcon that should be played
+ * @param queueMode {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}.
+ * @param params Parameters for the request. Can be null.
+ * Supported parameter names:
+ * {@link Engine#KEY_PARAM_STREAM},
* {@link Engine#KEY_PARAM_UTTERANCE_ID}.
*
- * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
+ * @return {@link #ERROR} or {@link #SUCCESS}.
*/
- public int playEarcon(String earcon, int queueMode,
- HashMap<String,String> params) {
- synchronized (mStartLock) {
- int result = ERROR;
- if (!mStarted) {
- return result;
- }
- try {
- if ((params != null) && (!params.isEmpty())) {
- String extra = params.get(Engine.KEY_PARAM_STREAM);
- if (extra != null) {
- mCachedParams[Engine.PARAM_POSITION_STREAM + 1] = extra;
- }
- setCachedParam(params, Engine.KEY_PARAM_STREAM, Engine.PARAM_POSITION_STREAM);
- setCachedParam(params, Engine.KEY_PARAM_UTTERANCE_ID,
- Engine.PARAM_POSITION_UTTERANCE_ID);
+ public int playEarcon(final String earcon, final int queueMode,
+ final HashMap<String, String> params) {
+ return runAction(new Action<Integer>() {
+ @Override
+ public Integer run(ITextToSpeechService service) throws RemoteException {
+ Uri earconUri = mEarcons.get(earcon);
+ if (earconUri == null) {
+ return ERROR;
}
- result = mITts.playEarcon(mPackageName, earcon, queueMode, null);
- } catch (RemoteException e) {
- restart("playEarcon", e);
- } catch (NullPointerException e) {
- restart("playEarcon", e);
- } catch (IllegalStateException e) {
- restart("playEarcon", e);
- } finally {
- resetCachedParams();
+ return service.playAudio(getPackageName(), earconUri, queueMode,
+ getParams(params));
}
- return result;
- }
+ }, ERROR, "playEarcon");
}
/**
* Plays silence for the specified amount of time using the specified
* queue mode.
*
- * @param durationInMs
- * A long that indicates how long the silence should last.
- * @param queueMode
- * {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}.
- * @param params
- * The list of parameters to be used. Can be null if no parameters are given.
- * They are specified using a (key, value) pair, where the key can be
+ * @param durationInMs The duration of the silence.
+ * @param queueMode {@link #QUEUE_ADD} or {@link #QUEUE_FLUSH}.
+ * @param params Parameters for the request. Can be null.
+ * Supported parameter names:
* {@link Engine#KEY_PARAM_UTTERANCE_ID}.
*
- * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
+ * @return {@link #ERROR} or {@link #SUCCESS}.
*/
- public int playSilence(long durationInMs, int queueMode, HashMap<String,String> params) {
- synchronized (mStartLock) {
- int result = ERROR;
- if (!mStarted) {
- return result;
- }
- try {
- if ((params != null) && (!params.isEmpty())) {
- setCachedParam(params, Engine.KEY_PARAM_UTTERANCE_ID,
- Engine.PARAM_POSITION_UTTERANCE_ID);
- }
- result = mITts.playSilence(mPackageName, durationInMs, queueMode, mCachedParams);
- } catch (RemoteException e) {
- restart("playSilence", e);
- } catch (NullPointerException e) {
- restart("playSilence", e);
- } catch (IllegalStateException e) {
- restart("playSilence", e);
- } finally {
- resetCachedParams();
+ public int playSilence(final long durationInMs, final int queueMode,
+ final HashMap<String, String> params) {
+ return runAction(new Action<Integer>() {
+ @Override
+ public Integer run(ITextToSpeechService service) throws RemoteException {
+ return service.playSilence(getPackageName(), durationInMs, queueMode,
+ getParams(params));
}
- return result;
- }
+ }, ERROR, "playSilence");
}
-
/**
- * Returns whether or not the TextToSpeech engine is busy speaking.
+ * Checks whether the TTS engine is busy speaking.
*
- * @return Whether or not the TextToSpeech engine is busy speaking.
+ * @return {@code true} if the TTS engine is speaking.
*/
public boolean isSpeaking() {
- synchronized (mStartLock) {
- if (!mStarted) {
- return false;
- }
- try {
- return mITts.isSpeaking();
- } catch (RemoteException e) {
- restart("isSpeaking", e);
- } catch (NullPointerException e) {
- restart("isSpeaking", e);
- } catch (IllegalStateException e) {
- restart("isSpeaking", e);
+ return runAction(new Action<Boolean>() {
+ @Override
+ public Boolean run(ITextToSpeechService service) throws RemoteException {
+ return service.isSpeaking();
}
- return false;
- }
+ }, false, "isSpeaking");
}
-
/**
* Interrupts the current utterance (whether played or rendered to file) and discards other
* utterances in the queue.
*
- * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
+ * @return {@link #ERROR} or {@link #SUCCESS}.
*/
public int stop() {
- synchronized (mStartLock) {
- int result = ERROR;
- if (!mStarted) {
- return result;
+ return runAction(new Action<Integer>() {
+ @Override
+ public Integer run(ITextToSpeechService service) throws RemoteException {
+ return service.stop(getPackageName());
}
- try {
- result = mITts.stop(mPackageName);
- } catch (RemoteException e) {
- restart("stop", e);
- } catch (NullPointerException e) {
- restart("stop", e);
- } catch (IllegalStateException e) {
- restart("stop", e);
- }
- return result;
- }
+ }, ERROR, "stop");
}
-
/**
- * Sets the speech rate for the TextToSpeech engine.
+ * Sets the speech rate.
*
* This has no effect on any pre-recorded speech.
*
- * @param speechRate
- * The speech rate for the TextToSpeech engine. 1 is the normal speed,
- * lower values slow down the speech (0.5 is half the normal speech rate),
- * greater values accelerate it (2 is twice the normal speech rate).
+ * @param speechRate Speech rate. {@code 1.0} is the normal speech rate,
+ * lower values slow down the speech ({@code 0.5} is half the normal speech rate),
+ * greater values accelerate it ({@code 2.0} is twice the normal speech rate).
*
- * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
+ * @return {@link #ERROR} or {@link #SUCCESS}.
*/
public int setSpeechRate(float speechRate) {
- synchronized (mStartLock) {
- int result = ERROR;
- if (!mStarted) {
- return result;
- }
- try {
- if (speechRate > 0) {
- int rate = (int)(speechRate*100);
- mCachedParams[Engine.PARAM_POSITION_RATE + 1] = String.valueOf(rate);
- // the rate is not set here, instead it is cached so it will be associated
- // with all upcoming utterances.
- if (speechRate > 0.0f) {
- result = SUCCESS;
- } else {
- result = ERROR;
- }
+ if (speechRate > 0.0f) {
+ int intRate = (int)(speechRate * 100);
+ if (intRate > 0) {
+ synchronized (mStartLock) {
+ mParams.putInt(Engine.KEY_PARAM_RATE, intRate);
}
- } catch (NullPointerException e) {
- restart("setSpeechRate", e);
- } catch (IllegalStateException e) {
- restart("setSpeechRate", e);
+ return SUCCESS;
}
- return result;
}
+ return ERROR;
}
-
/**
* Sets the speech pitch for the TextToSpeech engine.
*
* This has no effect on any pre-recorded speech.
*
- * @param pitch
- * The pitch for the TextToSpeech engine. 1 is the normal pitch,
+ * @param pitch Speech pitch. {@code 1.0} is the normal pitch,
* lower values lower the tone of the synthesized voice,
* greater values increase it.
*
- * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
+ * @return {@link #ERROR} or {@link #SUCCESS}.
*/
public int setPitch(float pitch) {
- synchronized (mStartLock) {
- int result = ERROR;
- if (!mStarted) {
- return result;
- }
- try {
- // the pitch is not set here, instead it is cached so it will be associated
- // with all upcoming utterances.
- if (pitch > 0) {
- int p = (int)(pitch*100);
- mCachedParams[Engine.PARAM_POSITION_PITCH + 1] = String.valueOf(p);
- result = SUCCESS;
+ if (pitch > 0.0f) {
+ int intPitch = (int)(pitch * 100);
+ if (intPitch > 0) {
+ synchronized (mStartLock) {
+ mParams.putInt(Engine.KEY_PARAM_PITCH, intPitch);
}
- } catch (NullPointerException e) {
- restart("setPitch", e);
- } catch (IllegalStateException e) {
- restart("setPitch", e);
+ return SUCCESS;
}
- return result;
}
+ return ERROR;
}
-
/**
- * Sets the language for the TextToSpeech engine.
- * The TextToSpeech engine will try to use the closest match to the specified
+ * Sets the text-to-speech language.
+ * The TTS engine will try to use the closest match to the specified
* language as represented by the Locale, but there is no guarantee that the exact same Locale
* will be used. Use {@link #isLanguageAvailable(Locale)} to check the level of support
* before choosing the language to use for the next utterances.
*
- * @param loc
- * The locale describing the language to be used.
+ * @param loc The locale describing the language to be used.
*
- * @return code indicating the support status for the locale. See {@link #LANG_AVAILABLE},
+ * @return Code indicating the support status for the locale. See {@link #LANG_AVAILABLE},
* {@link #LANG_COUNTRY_AVAILABLE}, {@link #LANG_COUNTRY_VAR_AVAILABLE},
* {@link #LANG_MISSING_DATA} and {@link #LANG_NOT_SUPPORTED}.
*/
- public int setLanguage(Locale loc) {
- synchronized (mStartLock) {
- int result = LANG_NOT_SUPPORTED;
- if (!mStarted) {
- return result;
- }
- if (loc == null) {
- return result;
- }
- try {
+ public int setLanguage(final Locale loc) {
+ return runAction(new Action<Integer>() {
+ @Override
+ public Integer run(ITextToSpeechService service) throws RemoteException {
+ if (loc == null) {
+ return LANG_NOT_SUPPORTED;
+ }
String language = loc.getISO3Language();
String country = loc.getISO3Country();
String variant = loc.getVariant();
@@ -1000,294 +853,317 @@ public class TextToSpeech {
// the available parts.
// Note that the language is not actually set here, instead it is cached so it
// will be associated with all upcoming utterances.
- result = mITts.isLanguageAvailable(language, country, variant, mCachedParams);
+ int result = service.loadLanguage(language, country, variant);
if (result >= LANG_AVAILABLE){
- mCachedParams[Engine.PARAM_POSITION_LANGUAGE + 1] = language;
- if (result >= LANG_COUNTRY_AVAILABLE){
- mCachedParams[Engine.PARAM_POSITION_COUNTRY + 1] = country;
- } else {
- mCachedParams[Engine.PARAM_POSITION_COUNTRY + 1] = "";
- }
- if (result >= LANG_COUNTRY_VAR_AVAILABLE){
- mCachedParams[Engine.PARAM_POSITION_VARIANT + 1] = variant;
- } else {
- mCachedParams[Engine.PARAM_POSITION_VARIANT + 1] = "";
+ if (result < LANG_COUNTRY_VAR_AVAILABLE) {
+ variant = "";
+ if (result < LANG_COUNTRY_AVAILABLE) {
+ country = "";
+ }
}
+ mParams.putString(Engine.KEY_PARAM_LANGUAGE, language);
+ mParams.putString(Engine.KEY_PARAM_COUNTRY, country);
+ mParams.putString(Engine.KEY_PARAM_VARIANT, variant);
}
- } catch (RemoteException e) {
- restart("setLanguage", e);
- } catch (NullPointerException e) {
- restart("setLanguage", e);
- } catch (IllegalStateException e) {
- restart("setLanguage", e);
+ return result;
}
- return result;
- }
+ }, LANG_NOT_SUPPORTED, "setLanguage");
}
-
/**
* Returns a Locale instance describing the language currently being used by the TextToSpeech
* engine.
+ *
* @return language, country (if any) and variant (if any) used by the engine stored in a Locale
- * instance, or null is the TextToSpeech engine has failed.
+ * instance, or {@code null} on error.
*/
public Locale getLanguage() {
- synchronized (mStartLock) {
- if (!mStarted) {
- return null;
- }
- try {
- // Only do a call to the native synth if there is nothing in the cached params
- if (mCachedParams[Engine.PARAM_POSITION_LANGUAGE + 1].length() < 1){
- String[] locStrings = mITts.getLanguage();
- if ((locStrings != null) && (locStrings.length == 3)) {
- return new Locale(locStrings[0], locStrings[1], locStrings[2]);
- } else {
- return null;
- }
- } else {
- return new Locale(mCachedParams[Engine.PARAM_POSITION_LANGUAGE + 1],
- mCachedParams[Engine.PARAM_POSITION_COUNTRY + 1],
- mCachedParams[Engine.PARAM_POSITION_VARIANT + 1]);
+ return runAction(new Action<Locale>() {
+ @Override
+ public Locale run(ITextToSpeechService service) throws RemoteException {
+ String[] locStrings = service.getLanguage();
+ if (locStrings != null && locStrings.length == 3) {
+ return new Locale(locStrings[0], locStrings[1], locStrings[2]);
}
- } catch (RemoteException e) {
- restart("getLanguage", e);
- } catch (NullPointerException e) {
- restart("getLanguage", e);
- } catch (IllegalStateException e) {
- restart("getLanguage", e);
+ return null;
}
- return null;
- }
+ }, null, "getLanguage");
}
/**
* Checks if the specified language as represented by the Locale is available and supported.
*
- * @param loc
- * The Locale describing the language to be used.
+ * @param loc The Locale describing the language to be used.
*
- * @return code indicating the support status for the locale. See {@link #LANG_AVAILABLE},
+ * @return Code indicating the support status for the locale. See {@link #LANG_AVAILABLE},
* {@link #LANG_COUNTRY_AVAILABLE}, {@link #LANG_COUNTRY_VAR_AVAILABLE},
* {@link #LANG_MISSING_DATA} and {@link #LANG_NOT_SUPPORTED}.
*/
- public int isLanguageAvailable(Locale loc) {
- synchronized (mStartLock) {
- int result = LANG_NOT_SUPPORTED;
- if (!mStarted) {
- return result;
+ public int isLanguageAvailable(final Locale loc) {
+ return runAction(new Action<Integer>() {
+ @Override
+ public Integer run(ITextToSpeechService service) throws RemoteException {
+ return service.isLanguageAvailable(loc.getISO3Language(),
+ loc.getISO3Country(), loc.getVariant());
}
- try {
- result = mITts.isLanguageAvailable(loc.getISO3Language(),
- loc.getISO3Country(), loc.getVariant(), mCachedParams);
- } catch (RemoteException e) {
- restart("isLanguageAvailable", e);
- } catch (NullPointerException e) {
- restart("isLanguageAvailable", e);
- } catch (IllegalStateException e) {
- restart("isLanguageAvailable", e);
- }
- return result;
- }
+ }, LANG_NOT_SUPPORTED, "isLanguageAvailable");
}
-
/**
* Synthesizes the given text to a file using the specified parameters.
*
- * @param text
- * The String of text that should be synthesized
- * @param params
- * The list of parameters to be used. Can be null if no parameters are given.
- * They are specified using a (key, value) pair, where the key can be
+ * @param text Thetext that should be synthesized
+ * @param params Parameters for the request. Can be null.
+ * Supported parameter names:
* {@link Engine#KEY_PARAM_UTTERANCE_ID}.
- * @param filename
- * The string that gives the full output filename; it should be
+ * @param filename Absolute file filename to write the generated audio data to.It should be
* something like "/sdcard/myappsounds/mysound.wav".
*
- * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
+ * @return {@link #ERROR} or {@link #SUCCESS}.
*/
- public int synthesizeToFile(String text, HashMap<String,String> params,
- String filename) {
- Log.i("TextToSpeech.java", "synthesizeToFile()");
- synchronized (mStartLock) {
- int result = ERROR;
- Log.i("TextToSpeech.java - synthesizeToFile", "synthesizeToFile text of length "
- + text.length());
- if (!mStarted) {
- Log.e("TextToSpeech.java - synthesizeToFile", "service isn't started");
- return result;
+ public int synthesizeToFile(final String text, final HashMap<String, String> params,
+ final String filename) {
+ return runAction(new Action<Integer>() {
+ @Override
+ public Integer run(ITextToSpeechService service) throws RemoteException {
+ return service.synthesizeToFile(getPackageName(), text, filename,
+ getParams(params));
}
- try {
- if ((params != null) && (!params.isEmpty())) {
- // no need to read the stream type here
- setCachedParam(params, Engine.KEY_PARAM_UTTERANCE_ID,
- Engine.PARAM_POSITION_UTTERANCE_ID);
- setCachedParam(params, Engine.KEY_PARAM_ENGINE, Engine.PARAM_POSITION_ENGINE);
- }
- result = mITts.synthesizeToFile(mPackageName, text, mCachedParams, filename) ?
- SUCCESS : ERROR;
- } catch (RemoteException e) {
- restart("synthesizeToFile", e);
- } catch (NullPointerException e) {
- restart("synthesizeToFile", e);
- } catch (IllegalStateException e) {
- restart("synthesizeToFile", e);
- } finally {
- resetCachedParams();
- }
- return result;
+ }, ERROR, "synthesizeToFile");
+ }
+
+ private Bundle getParams(HashMap<String, String> params) {
+ if (params != null && !params.isEmpty()) {
+ Bundle bundle = new Bundle(mParams);
+ copyIntParam(bundle, params, Engine.KEY_PARAM_STREAM);
+ copyStringParam(bundle, params, Engine.KEY_PARAM_UTTERANCE_ID);
+ copyFloatParam(bundle, params, Engine.KEY_PARAM_VOLUME);
+ copyFloatParam(bundle, params, Engine.KEY_PARAM_PAN);
+ return bundle;
+ } else {
+ return mParams;
}
}
+ private void copyStringParam(Bundle bundle, HashMap<String, String> params, String key) {
+ String value = params.get(key);
+ if (value != null) {
+ bundle.putString(key, value);
+ }
+ }
- /**
- * Convenience method to reset the cached parameters to the current default values
- * if they are not persistent between calls to the service.
- */
- private void resetCachedParams() {
- mCachedParams[Engine.PARAM_POSITION_STREAM + 1] =
- String.valueOf(Engine.DEFAULT_STREAM);
- mCachedParams[Engine.PARAM_POSITION_UTTERANCE_ID+ 1] = "";
- mCachedParams[Engine.PARAM_POSITION_VOLUME + 1] = Engine.DEFAULT_VOLUME_STRING;
- mCachedParams[Engine.PARAM_POSITION_PAN + 1] = Engine.DEFAULT_PAN_STRING;
+ private void copyIntParam(Bundle bundle, HashMap<String, String> params, String key) {
+ String valueString = params.get(key);
+ if (!TextUtils.isEmpty(valueString)) {
+ try {
+ int value = Integer.parseInt(valueString);
+ bundle.putInt(key, value);
+ } catch (NumberFormatException ex) {
+ // don't set the value in the bundle
+ }
+ }
}
- /**
- * Convenience method to save a parameter in the cached parameter array, at the given index,
- * for a property saved in the given hashmap.
- */
- private void setCachedParam(HashMap<String,String> params, String key, int keyIndex) {
- String extra = params.get(key);
- if (extra != null) {
- mCachedParams[keyIndex+1] = extra;
+ private void copyFloatParam(Bundle bundle, HashMap<String, String> params, String key) {
+ String valueString = params.get(key);
+ if (!TextUtils.isEmpty(valueString)) {
+ try {
+ float value = Float.parseFloat(valueString);
+ bundle.putFloat(key, value);
+ } catch (NumberFormatException ex) {
+ // don't set the value in the bundle
+ }
}
}
/**
- * Sets the OnUtteranceCompletedListener that will fire when an utterance completes.
+ * Sets the listener that will be notified when synthesis of an utterance completes.
*
- * @param listener
- * The OnUtteranceCompletedListener
+ * @param listener The listener to use.
*
- * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
+ * @return {@link #ERROR} or {@link #SUCCESS}.
*/
- public int setOnUtteranceCompletedListener(
- final OnUtteranceCompletedListener listener) {
- synchronized (mStartLock) {
- int result = ERROR;
- if (!mStarted) {
- return result;
- }
- mITtscallback = new ITtsCallback.Stub() {
- public void utteranceCompleted(String utteranceId) throws RemoteException {
- if (listener != null) {
- listener.onUtteranceCompleted(utteranceId);
+ public int setOnUtteranceCompletedListener(final OnUtteranceCompletedListener listener) {
+ return runAction(new Action<Integer>() {
+ @Override
+ public Integer run(ITextToSpeechService service) throws RemoteException {
+ ITextToSpeechCallback.Stub callback = new ITextToSpeechCallback.Stub() {
+ public void utteranceCompleted(String utteranceId) {
+ if (listener != null) {
+ listener.onUtteranceCompleted(utteranceId);
+ }
}
- }
- };
- try {
- result = mITts.registerCallback(mPackageName, mITtscallback);
- } catch (RemoteException e) {
- restart("registerCallback", e);
- } catch (NullPointerException e) {
- restart("registerCallback", e);
- } catch (IllegalStateException e) {
- restart("registerCallback", e);
+ };
+ service.setCallback(getPackageName(), callback);
+ return SUCCESS;
}
- return result;
- }
+ }, ERROR, "setOnUtteranceCompletedListener");
}
/**
- * Sets the speech synthesis engine to be used by its packagename.
+ * Sets the TTS engine to use.
*
- * @param enginePackageName
- * The packagename for the synthesis engine (ie, "com.svox.pico")
+ * @param enginePackageName The package name for the synthesis engine (e.g. "com.svox.pico")
*
- * @return Code indicating success or failure. See {@link #ERROR} and {@link #SUCCESS}.
+ * @return {@link #ERROR} or {@link #SUCCESS}.
*/
+ // TODO: add @Deprecated{This method does not tell the caller when the new engine
+ // has been initialized. You should create a new TextToSpeech object with the new
+ // engine instead.}
public int setEngineByPackageName(String enginePackageName) {
- synchronized (mStartLock) {
- int result = TextToSpeech.ERROR;
- if (!mStarted) {
- return result;
- }
- try {
- result = mITts.setEngineByPackageName(enginePackageName);
- if (result == TextToSpeech.SUCCESS){
- mCachedParams[Engine.PARAM_POSITION_ENGINE + 1] = enginePackageName;
- }
- } catch (RemoteException e) {
- restart("setEngineByPackageName", e);
- } catch (NullPointerException e) {
- restart("setEngineByPackageName", e);
- } catch (IllegalStateException e) {
- restart("setEngineByPackageName", e);
- }
- return result;
- }
+ mRequestedEngine = enginePackageName;
+ return initTts();
}
-
/**
- * Gets the packagename of the default speech synthesis engine.
+ * Gets the package name of the default speech synthesis engine.
*
- * @return Packagename of the TTS engine that the user has chosen as their default.
+ * @return Package name of the TTS engine that the user has chosen as their default.
*/
public String getDefaultEngine() {
- synchronized (mStartLock) {
- String engineName = "";
- if (!mStarted) {
- return engineName;
- }
- try {
- engineName = mITts.getDefaultEngine();
- } catch (RemoteException e) {
- restart("getDefaultEngine", e);
- } catch (NullPointerException e) {
- restart("getDefaultEngine", e);
- } catch (IllegalStateException e) {
- restart("getDefaultEngine", e);
+ String engine = Settings.Secure.getString(mContext.getContentResolver(),
+ Settings.Secure.TTS_DEFAULT_SYNTH);
+ return engine != null ? engine : Engine.DEFAULT_ENGINE;
+ }
+
+ /**
+ * Checks whether the user's settings should override settings requested by the calling
+ * application.
+ */
+ public boolean areDefaultsEnforced() {
+ return Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.TTS_USE_DEFAULTS, Engine.USE_DEFAULTS) == 1;
+ }
+
+ private boolean isEngineEnabled(String engine) {
+ if (Engine.DEFAULT_ENGINE.equals(engine)) {
+ return true;
+ }
+ for (String enabled : getEnabledEngines()) {
+ if (engine.equals(enabled)) {
+ return true;
}
- return engineName;
}
+ return false;
}
+ private String[] getEnabledEngines() {
+ String str = Settings.Secure.getString(mContext.getContentResolver(),
+ Settings.Secure.TTS_ENABLED_PLUGINS);
+ if (TextUtils.isEmpty(str)) {
+ return new String[0];
+ }
+ return str.split(" ");
+ }
/**
- * Returns whether or not the user is forcing their defaults to override the
- * Text-To-Speech settings set by applications.
+ * Gets a list of all installed TTS engines.
*
- * @return Whether or not defaults are enforced.
+ * @return A list of engine info objects. The list can be empty, but will never by {@code null}.
+ *
+ * @hide Pending approval
*/
- public boolean areDefaultsEnforced() {
- synchronized (mStartLock) {
- boolean defaultsEnforced = false;
- if (!mStarted) {
- return defaultsEnforced;
+ public List<EngineInfo> getEngines() {
+ PackageManager pm = mContext.getPackageManager();
+ Intent intent = new Intent(Engine.INTENT_ACTION_TTS_SERVICE);
+ List<ResolveInfo> resolveInfos =
+ pm.queryIntentServices(intent, PackageManager.MATCH_DEFAULT_ONLY);
+ if (resolveInfos == null) return Collections.emptyList();
+ List<EngineInfo> engines = new ArrayList<EngineInfo>(resolveInfos.size());
+ for (ResolveInfo resolveInfo : resolveInfos) {
+ ServiceInfo service = resolveInfo.serviceInfo;
+ if (service != null) {
+ EngineInfo engine = new EngineInfo();
+ // Using just the package name isn't great, since it disallows having
+ // multiple engines in the same package, but that's what the existing API does.
+ engine.name = service.packageName;
+ CharSequence label = service.loadLabel(pm);
+ engine.label = TextUtils.isEmpty(label) ? engine.name : label.toString();
+ engine.icon = service.getIconResource();
+ engines.add(engine);
}
+ }
+ return engines;
+ }
+
+ private class Connection implements ServiceConnection {
+ private ITextToSpeechService mService;
+
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ Log.i(TAG, "Connected to " + name);
+ synchronized(mStartLock) {
+ if (mServiceConnection != null) {
+ // Disconnect any previous service connection
+ mServiceConnection.disconnect();
+ }
+ mServiceConnection = this;
+ mService = ITextToSpeechService.Stub.asInterface(service);
+ dispatchOnInit(SUCCESS);
+ }
+ }
+
+ public void onServiceDisconnected(ComponentName name) {
+ synchronized(mStartLock) {
+ mService = null;
+ // If this is the active connection, clear it
+ if (mServiceConnection == this) {
+ mServiceConnection = null;
+ }
+ }
+ }
+
+ public void disconnect() {
+ mContext.unbindService(this);
+ }
+
+ public <R> R runAction(Action<R> action, R errorResult, String method, boolean reconnect) {
try {
- defaultsEnforced = mITts.areDefaultsEnforced();
- } catch (RemoteException e) {
- restart("areDefaultsEnforced", e);
- } catch (NullPointerException e) {
- restart("areDefaultsEnforced", e);
- } catch (IllegalStateException e) {
- restart("areDefaultsEnforced", e);
+ synchronized (mStartLock) {
+ if (mService == null) {
+ Log.w(TAG, method + " failed: not connected to TTS engine");
+ return errorResult;
+ }
+ return action.run(mService);
+ }
+ } catch (RemoteException ex) {
+ Log.e(TAG, method + " failed", ex);
+ if (reconnect) {
+ disconnect();
+ initTts();
+ }
+ return errorResult;
}
- return defaultsEnforced;
}
}
+ private interface Action<R> {
+ R run(ITextToSpeechService service) throws RemoteException;
+ }
+
/**
- * Restarts the TTS after a failure.
+ * Information about an installed text-to-speech engine.
+ *
+ * @see TextToSpeech#getEngines
+ * @hide Pending approval
*/
- private void restart(String method, Exception e) {
- // TTS died; restart it.
- Log.e(TAG, method, e);
- mStarted = false;
- initTts();
+ public static class EngineInfo {
+ /**
+ * Engine package name..
+ */
+ public String name;
+ /**
+ * Localized label for the engine.
+ */
+ public String label;
+ /**
+ * Icon for the engine.
+ */
+ public int icon;
+
+ @Override
+ public String toString() {
+ return "EngineInfo{name=" + name + "}";
+ }
+
}
}
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
new file mode 100644
index 000000000000..da97fb4bdf80
--- /dev/null
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -0,0 +1,714 @@
+/*
+ * 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 android.speech.tts;
+
+import android.app.Service;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.ConditionVariable;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.MessageQueue;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.provider.Settings;
+import android.speech.tts.TextToSpeech.Engine;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Locale;
+
+
+/**
+ * Abstract base class for TTS engine implementations.
+ *
+ * @hide Pending approval
+ */
+public abstract class TextToSpeechService extends Service {
+
+ private static final boolean DBG = false;
+ private static final String TAG = "TextToSpeechService";
+
+ private static final int MAX_SPEECH_ITEM_CHAR_LENGTH = 4000;
+ private static final String SYNTH_THREAD_NAME = "SynthThread";
+
+ private SynthHandler mSynthHandler;
+
+ private CallbackMap mCallbacks;
+
+ @Override
+ public void onCreate() {
+ if (DBG) Log.d(TAG, "onCreate()");
+ super.onCreate();
+
+ SynthThread synthThread = new SynthThread();
+ synthThread.start();
+ mSynthHandler = new SynthHandler(synthThread.getLooper());
+
+ mCallbacks = new CallbackMap();
+
+ // Load default language
+ onLoadLanguage(getDefaultLanguage(), getDefaultCountry(), getDefaultVariant());
+ }
+
+ @Override
+ public void onDestroy() {
+ if (DBG) Log.d(TAG, "onDestroy()");
+
+ // Tell the synthesizer to stop
+ mSynthHandler.quit();
+
+ // Unregister all callbacks.
+ mCallbacks.kill();
+
+ super.onDestroy();
+ }
+
+ /**
+ * Checks whether the engine supports a given language.
+ *
+ * Can be called on multiple threads.
+ *
+ * @param lang ISO-3 language code.
+ * @param country ISO-3 country code. May be empty or null.
+ * @param variant Language variant. May be empty or null.
+ * @return Code indicating the support status for the locale.
+ * One of {@link TextToSpeech#LANG_AVAILABLE},
+ * {@link TextToSpeech#LANG_COUNTRY_AVAILABLE},
+ * {@link TextToSpeech#LANG_COUNTRY_VAR_AVAILABLE},
+ * {@link TextToSpeech#LANG_MISSING_DATA}
+ * {@link TextToSpeech#LANG_NOT_SUPPORTED}.
+ */
+ protected abstract int onIsLanguageAvailable(String lang, String country, String variant);
+
+ /**
+ * Returns the language, country and variant currently being used by the TTS engine.
+ *
+ * Can be called on multiple threads.
+ *
+ * @return A 3-element array, containing language (ISO 3-letter code),
+ * country (ISO 3-letter code) and variant used by the engine.
+ * The country and variant may be {@code ""}. If country is empty, then variant must
+ * be empty too.
+ * @see Locale#getISO3Language()
+ * @see Locale#getISO3Country()
+ * @see Locale#getVariant()
+ */
+ protected abstract String[] onGetLanguage();
+
+ /**
+ * Notifies the engine that it should load a speech synthesis language. There is no guarantee
+ * that this method is always called before the language is used for synthesis. It is merely
+ * a hint to the engine that it will probably get some synthesis requests for this language
+ * at some point in the future.
+ *
+ * Can be called on multiple threads.
+ *
+ * @param lang ISO-3 language code.
+ * @param country ISO-3 country code. May be empty or null.
+ * @param variant Language variant. May be empty or null.
+ * @return Code indicating the support status for the locale.
+ * One of {@link TextToSpeech#LANG_AVAILABLE},
+ * {@link TextToSpeech#LANG_COUNTRY_AVAILABLE},
+ * {@link TextToSpeech#LANG_COUNTRY_VAR_AVAILABLE},
+ * {@link TextToSpeech#LANG_MISSING_DATA}
+ * {@link TextToSpeech#LANG_NOT_SUPPORTED}.
+ */
+ protected abstract int onLoadLanguage(String lang, String country, String variant);
+
+ /**
+ * Notifies the service that it should stop any in-progress speech synthesis.
+ * This method can be called even if no speech synthesis is currently in progress.
+ *
+ * Can be called on multiple threads, but not on the synthesis thread.
+ */
+ protected abstract void onStop();
+
+ /**
+ * Tells the service to synthesize speech from the given text. This method should
+ * block until the synthesis is finished.
+ *
+ * Called on the synthesis thread.
+ *
+ * @param request The synthesis request. The method should use the methods in the request
+ * object to communicate the results of the synthesis.
+ */
+ protected abstract void onSynthesizeText(SynthesisRequest request);
+
+ private boolean areDefaultsEnforced() {
+ return getSecureSettingInt(Settings.Secure.TTS_USE_DEFAULTS,
+ TextToSpeech.Engine.USE_DEFAULTS) == 1;
+ }
+
+ private int getDefaultSpeechRate() {
+ return getSecureSettingInt(Settings.Secure.TTS_DEFAULT_RATE, Engine.DEFAULT_RATE);
+ }
+
+ private String getDefaultLanguage() {
+ return getSecureSettingString(Settings.Secure.TTS_DEFAULT_LANG,
+ Locale.getDefault().getISO3Language());
+ }
+
+ private String getDefaultCountry() {
+ return getSecureSettingString(Settings.Secure.TTS_DEFAULT_COUNTRY,
+ Locale.getDefault().getISO3Country());
+ }
+
+ private String getDefaultVariant() {
+ return getSecureSettingString(Settings.Secure.TTS_DEFAULT_VARIANT,
+ Locale.getDefault().getVariant());
+ }
+
+ private int getSecureSettingInt(String name, int defaultValue) {
+ return Settings.Secure.getInt(getContentResolver(), name, defaultValue);
+ }
+
+ private String getSecureSettingString(String name, String defaultValue) {
+ String value = Settings.Secure.getString(getContentResolver(), name);
+ return value != null ? value : defaultValue;
+ }
+
+ /**
+ * Synthesizer thread. This thread is used to run {@link SynthHandler}.
+ */
+ private class SynthThread extends HandlerThread implements MessageQueue.IdleHandler {
+
+ private boolean mFirstIdle = true;
+
+ public SynthThread() {
+ super(SYNTH_THREAD_NAME, android.os.Process.THREAD_PRIORITY_AUDIO);
+ }
+
+ @Override
+ protected void onLooperPrepared() {
+ getLooper().getQueue().addIdleHandler(this);
+ }
+
+ @Override
+ public boolean queueIdle() {
+ if (mFirstIdle) {
+ mFirstIdle = false;
+ } else {
+ broadcastTtsQueueProcessingCompleted();
+ }
+ return true;
+ }
+
+ private void broadcastTtsQueueProcessingCompleted() {
+ Intent i = new Intent(TextToSpeech.ACTION_TTS_QUEUE_PROCESSING_COMPLETED);
+ if (DBG) Log.d(TAG, "Broadcasting: " + i);
+ sendBroadcast(i);
+ }
+ }
+
+ private class SynthHandler extends Handler {
+
+ private SpeechItem mCurrentSpeechItem = null;
+
+ public SynthHandler(Looper looper) {
+ super(looper);
+ }
+
+ private void dispatchUtteranceCompleted(SpeechItem item) {
+ String utteranceId = item.getUtteranceId();
+ if (!TextUtils.isEmpty(utteranceId)) {
+ mCallbacks.dispatchUtteranceCompleted(item.getCallingApp(), utteranceId);
+ }
+ }
+
+ private synchronized SpeechItem getCurrentSpeechItem() {
+ return mCurrentSpeechItem;
+ }
+
+ private synchronized SpeechItem setCurrentSpeechItem(SpeechItem speechItem) {
+ SpeechItem old = mCurrentSpeechItem;
+ mCurrentSpeechItem = speechItem;
+ return old;
+ }
+
+ public boolean isSpeaking() {
+ return getCurrentSpeechItem() != null;
+ }
+
+ public void quit() {
+ // Don't process any more speech items
+ getLooper().quit();
+ // Stop the current speech item
+ SpeechItem current = setCurrentSpeechItem(null);
+ if (current != null) {
+ current.stop();
+ }
+ }
+
+ /**
+ * Adds a speech item to the queue.
+ *
+ * Called on a service binder thread.
+ */
+ public int enqueueSpeechItem(int queueMode, final SpeechItem speechItem) {
+ if (!speechItem.isValid()) {
+ return TextToSpeech.ERROR;
+ }
+ // TODO: The old code also supported the undocumented queueMode == 2,
+ // which clears out all pending items from the calling app, as well as all
+ // non-file items from other apps.
+ if (queueMode == TextToSpeech.QUEUE_FLUSH) {
+ stop(speechItem.getCallingApp());
+ }
+ Runnable runnable = new Runnable() {
+ @Override
+ public void run() {
+ setCurrentSpeechItem(speechItem);
+ if (speechItem.play() == TextToSpeech.SUCCESS) {
+ dispatchUtteranceCompleted(speechItem);
+ }
+ setCurrentSpeechItem(null);
+ }
+ };
+ Message msg = Message.obtain(this, runnable);
+ // The obj is used to remove all callbacks from the given app in stop(String).
+ msg.obj = speechItem.getCallingApp();
+ if (sendMessage(msg)) {
+ return TextToSpeech.SUCCESS;
+ } else {
+ Log.w(TAG, "SynthThread has quit");
+ return TextToSpeech.ERROR;
+ }
+ }
+
+ /**
+ * Stops all speech output and removes any utterances still in the queue for
+ * the calling app.
+ *
+ * Called on a service binder thread.
+ */
+ public int stop(String callingApp) {
+ if (TextUtils.isEmpty(callingApp)) {
+ return TextToSpeech.ERROR;
+ }
+ removeCallbacksAndMessages(callingApp);
+ SpeechItem current = setCurrentSpeechItem(null);
+ if (current != null && TextUtils.equals(callingApp, current.getCallingApp())) {
+ current.stop();
+ }
+ return TextToSpeech.SUCCESS;
+ }
+ }
+
+ /**
+ * An item in the synth thread queue.
+ */
+ private static abstract class SpeechItem {
+ private final String mCallingApp;
+ private final Bundle mParams;
+ private boolean mStarted = false;
+ private boolean mStopped = false;
+
+ public SpeechItem(String callingApp, Bundle params) {
+ mCallingApp = callingApp;
+ mParams = params;
+ }
+
+ public String getCallingApp() {
+ return mCallingApp;
+ }
+
+ /**
+ * Checker whether the item is valid. If this method returns false, the item should not
+ * be played.
+ */
+ public abstract boolean isValid();
+
+ /**
+ * Plays the speech item. Blocks until playback is finished.
+ * Must not be called more than once.
+ *
+ * Only called on the synthesis thread.
+ *
+ * @return {@link TextToSpeech#SUCCESS} or {@link TextToSpeech#ERROR}.
+ */
+ public int play() {
+ synchronized (this) {
+ if (mStarted) {
+ throw new IllegalStateException("play() called twice");
+ }
+ mStarted = true;
+ }
+ return playImpl();
+ }
+
+ /**
+ * Stops the speech item.
+ * Must not be called more than once.
+ *
+ * Can be called on multiple threads, but not on the synthesis thread.
+ */
+ public void stop() {
+ synchronized (this) {
+ if (mStopped) {
+ throw new IllegalStateException("stop() called twice");
+ }
+ mStopped = true;
+ }
+ stopImpl();
+ }
+
+ protected abstract int playImpl();
+
+ protected abstract void stopImpl();
+
+ public int getStreamType() {
+ return getIntParam(Engine.KEY_PARAM_STREAM, Engine.DEFAULT_STREAM);
+ }
+
+ public float getVolume() {
+ return getFloatParam(Engine.KEY_PARAM_VOLUME, Engine.DEFAULT_VOLUME);
+ }
+
+ public float getPan() {
+ return getFloatParam(Engine.KEY_PARAM_PAN, Engine.DEFAULT_PAN);
+ }
+
+ public String getUtteranceId() {
+ return getStringParam(Engine.KEY_PARAM_UTTERANCE_ID, null);
+ }
+
+ protected String getStringParam(String key, String defaultValue) {
+ return mParams == null ? defaultValue : mParams.getString(key, defaultValue);
+ }
+
+ protected int getIntParam(String key, int defaultValue) {
+ return mParams == null ? defaultValue : mParams.getInt(key, defaultValue);
+ }
+
+ protected float getFloatParam(String key, float defaultValue) {
+ return mParams == null ? defaultValue : mParams.getFloat(key, defaultValue);
+ }
+ }
+
+ private class SynthesisSpeechItem extends SpeechItem {
+ private final String mText;
+ private SynthesisRequest mSynthesisRequest;
+
+ public SynthesisSpeechItem(String callingApp, Bundle params, String text) {
+ super(callingApp, params);
+ mText = text;
+ }
+
+ public String getText() {
+ return mText;
+ }
+
+ @Override
+ public boolean isValid() {
+ if (TextUtils.isEmpty(mText)) {
+ Log.w(TAG, "Got empty text");
+ return false;
+ }
+ if (mText.length() >= MAX_SPEECH_ITEM_CHAR_LENGTH){
+ Log.w(TAG, "Text too long: " + mText.length() + " chars");
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ protected int playImpl() {
+ SynthesisRequest synthesisRequest;
+ synchronized (this) {
+ mSynthesisRequest = createSynthesisRequest();
+ synthesisRequest = mSynthesisRequest;
+ }
+ setRequestParams(synthesisRequest);
+ TextToSpeechService.this.onSynthesizeText(synthesisRequest);
+ return synthesisRequest.isDone() ? TextToSpeech.SUCCESS : TextToSpeech.ERROR;
+ }
+
+ protected SynthesisRequest createSynthesisRequest() {
+ return new PlaybackSynthesisRequest(mText, getStreamType(), getVolume(), getPan());
+ }
+
+ private void setRequestParams(SynthesisRequest request) {
+ if (areDefaultsEnforced()) {
+ request.setLanguage(getDefaultLanguage(), getDefaultCountry(), getDefaultVariant());
+ request.setSpeechRate(getDefaultSpeechRate());
+ } else {
+ request.setLanguage(getLanguage(), getCountry(), getVariant());
+ request.setSpeechRate(getSpeechRate());
+ }
+ request.setPitch(getPitch());
+ }
+
+ @Override
+ protected void stopImpl() {
+ SynthesisRequest synthesisRequest;
+ synchronized (this) {
+ synthesisRequest = mSynthesisRequest;
+ }
+ synthesisRequest.stop();
+ TextToSpeechService.this.onStop();
+ }
+
+ public String getLanguage() {
+ return getStringParam(Engine.KEY_PARAM_LANGUAGE, getDefaultLanguage());
+ }
+
+ private boolean hasLanguage() {
+ return !TextUtils.isEmpty(getStringParam(Engine.KEY_PARAM_LANGUAGE, null));
+ }
+
+ private String getCountry() {
+ if (!hasLanguage()) return getDefaultCountry();
+ return getStringParam(Engine.KEY_PARAM_COUNTRY, "");
+ }
+
+ private String getVariant() {
+ if (!hasLanguage()) return getDefaultVariant();
+ return getStringParam(Engine.KEY_PARAM_VARIANT, "");
+ }
+
+ private int getSpeechRate() {
+ return getIntParam(Engine.KEY_PARAM_RATE, getDefaultSpeechRate());
+ }
+
+ private int getPitch() {
+ return getIntParam(Engine.KEY_PARAM_PITCH, Engine.DEFAULT_PITCH);
+ }
+ }
+
+ private class SynthesisToFileSpeechItem extends SynthesisSpeechItem {
+ private final File mFile;
+
+ public SynthesisToFileSpeechItem(String callingApp, Bundle params, String text,
+ File file) {
+ super(callingApp, params, text);
+ mFile = file;
+ }
+
+ @Override
+ public boolean isValid() {
+ if (!super.isValid()) {
+ return false;
+ }
+ return checkFile(mFile);
+ }
+
+ @Override
+ protected SynthesisRequest createSynthesisRequest() {
+ return new FileSynthesisRequest(getText(), mFile);
+ }
+
+ /**
+ * Checks that the given file can be used for synthesis output.
+ */
+ private boolean checkFile(File file) {
+ try {
+ if (file.exists()) {
+ Log.v(TAG, "File " + file + " exists, deleting.");
+ if (!file.delete()) {
+ Log.e(TAG, "Failed to delete " + file);
+ return false;
+ }
+ }
+ if (!file.createNewFile()) {
+ Log.e(TAG, "Can't create file " + file);
+ return false;
+ }
+ if (!file.delete()) {
+ Log.e(TAG, "Failed to delete " + file);
+ return false;
+ }
+ return true;
+ } catch (IOException e) {
+ Log.e(TAG, "Can't use " + file + " due to exception " + e);
+ return false;
+ }
+ }
+ }
+
+ private class AudioSpeechItem extends SpeechItem {
+
+ private final BlockingMediaPlayer mPlayer;
+
+ public AudioSpeechItem(String callingApp, Bundle params, Uri uri) {
+ super(callingApp, params);
+ mPlayer = new BlockingMediaPlayer(TextToSpeechService.this, uri, getStreamType());
+ }
+
+ @Override
+ public boolean isValid() {
+ return true;
+ }
+
+ @Override
+ protected int playImpl() {
+ return mPlayer.startAndWait() ? TextToSpeech.SUCCESS : TextToSpeech.ERROR;
+ }
+
+ @Override
+ protected void stopImpl() {
+ mPlayer.stop();
+ }
+ }
+
+ private class SilenceSpeechItem extends SpeechItem {
+ private final long mDuration;
+ private final ConditionVariable mDone;
+
+ public SilenceSpeechItem(String callingApp, Bundle params, long duration) {
+ super(callingApp, params);
+ mDuration = duration;
+ mDone = new ConditionVariable();
+ }
+
+ @Override
+ public boolean isValid() {
+ return true;
+ }
+
+ @Override
+ protected int playImpl() {
+ boolean aborted = mDone.block(mDuration);
+ return aborted ? TextToSpeech.ERROR : TextToSpeech.SUCCESS;
+ }
+
+ @Override
+ protected void stopImpl() {
+ mDone.open();
+ }
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ if (TextToSpeech.Engine.INTENT_ACTION_TTS_SERVICE.equals(intent.getAction())) {
+ return mBinder;
+ }
+ return null;
+ }
+
+ /**
+ * Binder returned from {@code #onBind(Intent)}. The methods in this class can be
+ * called called from several different threads.
+ */
+ private final ITextToSpeechService.Stub mBinder = new ITextToSpeechService.Stub() {
+
+ public int speak(String callingApp, String text, int queueMode, Bundle params) {
+ SpeechItem item = new SynthesisSpeechItem(callingApp, params, text);
+ return mSynthHandler.enqueueSpeechItem(queueMode, item);
+ }
+
+ public int synthesizeToFile(String callingApp, String text, String filename,
+ Bundle params) {
+ File file = new File(filename);
+ SpeechItem item = new SynthesisToFileSpeechItem(callingApp, params, text, file);
+ return mSynthHandler.enqueueSpeechItem(TextToSpeech.QUEUE_ADD, item);
+ }
+
+ public int playAudio(String callingApp, Uri audioUri, int queueMode, Bundle params) {
+ SpeechItem item = new AudioSpeechItem(callingApp, params, audioUri);
+ return mSynthHandler.enqueueSpeechItem(queueMode, item);
+ }
+
+ public int playSilence(String callingApp, long duration, int queueMode, Bundle params) {
+ SpeechItem item = new SilenceSpeechItem(callingApp, params, duration);
+ return mSynthHandler.enqueueSpeechItem(queueMode, item);
+ }
+
+ public boolean isSpeaking() {
+ return mSynthHandler.isSpeaking();
+ }
+
+ public int stop(String callingApp) {
+ return mSynthHandler.stop(callingApp);
+ }
+
+ public String[] getLanguage() {
+ return onGetLanguage();
+ }
+
+ public int isLanguageAvailable(String lang, String country, String variant) {
+ return onIsLanguageAvailable(lang, country, variant);
+ }
+
+ public int loadLanguage(String lang, String country, String variant) {
+ return onLoadLanguage(lang, country, variant);
+ }
+
+ public void setCallback(String packageName, ITextToSpeechCallback cb) {
+ mCallbacks.setCallback(packageName, cb);
+ }
+ };
+
+ private class CallbackMap extends RemoteCallbackList<ITextToSpeechCallback> {
+
+ private final HashMap<String, ITextToSpeechCallback> mAppToCallback
+ = new HashMap<String, ITextToSpeechCallback>();
+
+ public void setCallback(String packageName, ITextToSpeechCallback cb) {
+ synchronized (mAppToCallback) {
+ ITextToSpeechCallback old;
+ if (cb != null) {
+ register(cb, packageName);
+ old = mAppToCallback.put(packageName, cb);
+ } else {
+ old = mAppToCallback.remove(packageName);
+ }
+ if (old != null && old != cb) {
+ unregister(old);
+ }
+ }
+ }
+
+ public void dispatchUtteranceCompleted(String packageName, String utteranceId) {
+ ITextToSpeechCallback cb;
+ synchronized (mAppToCallback) {
+ cb = mAppToCallback.get(packageName);
+ }
+ if (cb == null) return;
+ try {
+ cb.utteranceCompleted(utteranceId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Callback failed: " + e);
+ }
+ }
+
+ @Override
+ public void onCallbackDied(ITextToSpeechCallback callback, Object cookie) {
+ String packageName = (String) cookie;
+ synchronized (mAppToCallback) {
+ mAppToCallback.remove(packageName);
+ }
+ mSynthHandler.stop(packageName);
+ }
+
+ @Override
+ public void kill() {
+ synchronized (mAppToCallback) {
+ mAppToCallback.clear();
+ super.kill();
+ }
+ }
+
+ }
+
+}
diff --git a/core/java/android/text/CharSequenceIterator.java b/core/java/android/text/CharSequenceIterator.java
index 4946406948af..4b8ac10d725c 100644
--- a/core/java/android/text/CharSequenceIterator.java
+++ b/core/java/android/text/CharSequenceIterator.java
@@ -16,22 +16,18 @@
package android.text;
-import android.util.MathUtils;
-
import java.text.CharacterIterator;
/** {@hide} */
public class CharSequenceIterator implements CharacterIterator {
private final CharSequence mValue;
- private final int mStart;
- private final int mEnd;
+ private final int mLength;
private int mIndex;
public CharSequenceIterator(CharSequence value) {
mValue = value;
- mStart = 0;
- mEnd = value.length();
+ mLength = value.length();
mIndex = 0;
}
@@ -46,7 +42,7 @@ public class CharSequenceIterator implements CharacterIterator {
/** {@inheritDoc} */
public char current() {
- if (mIndex == mEnd) {
+ if (mIndex == mLength) {
return DONE;
}
return mValue.charAt(mIndex);
@@ -54,12 +50,12 @@ public class CharSequenceIterator implements CharacterIterator {
/** {@inheritDoc} */
public int getBeginIndex() {
- return mStart;
+ return 0;
}
/** {@inheritDoc} */
public int getEndIndex() {
- return mEnd;
+ return mLength;
}
/** {@inheritDoc} */
@@ -69,27 +65,36 @@ public class CharSequenceIterator implements CharacterIterator {
/** {@inheritDoc} */
public char first() {
- return setIndex(mStart);
+ return setIndex(0);
}
/** {@inheritDoc} */
public char last() {
- return setIndex(mEnd - 1);
+ return setIndex(mLength - 1);
}
/** {@inheritDoc} */
public char next() {
+ if (mIndex == mLength) {
+ return DONE;
+ }
return setIndex(mIndex + 1);
}
/** {@inheritDoc} */
public char previous() {
+ if (mIndex == 0) {
+ return DONE;
+ }
return setIndex(mIndex - 1);
}
/** {@inheritDoc} */
public char setIndex(int index) {
- mIndex = MathUtils.constrain(index, mStart, mEnd);
+ if ((index < 0) || (index > mLength)) {
+ throw new IllegalArgumentException("Valid range is [" + 0 + "..." + mLength + "]");
+ }
+ mIndex = index;
return current();
}
}
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index ee6342a524a5..ac5db625790c 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -37,6 +37,7 @@ import android.text.style.ScaleXSpan;
import android.text.style.StrikethroughSpan;
import android.text.style.StyleSpan;
import android.text.style.SubscriptSpan;
+import android.text.style.SuggestionSpan;
import android.text.style.SuperscriptSpan;
import android.text.style.TextAppearanceSpan;
import android.text.style.TypefaceSpan;
@@ -566,7 +567,7 @@ public class TextUtils {
/** @hide */
public static final int ANNOTATION = 18;
/** @hide */
- public static final int CORRECTION_SPAN = 19;
+ public static final int SUGGESTION_SPAN = 19;
/**
* Flatten a CharSequence and whatever styles can be copied across processes
@@ -712,6 +713,10 @@ public class TextUtils {
readSpan(p, sp, new Annotation(p));
break;
+ case SUGGESTION_SPAN:
+ readSpan(p, sp, new SuggestionSpan(p));
+ break;
+
default:
throw new RuntimeException("bogus span encoding " + kind);
}
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index 80c010638256..b25ba8d31a64 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -390,7 +390,7 @@ public class ArrowKeyMovementMethod extends BaseMovementMethod implements Moveme
}
private boolean isValidOffset(int offset) {
- return offset >= 0 && offset < mCurrent.length();
+ return offset >= 0 && offset <= mCurrent.length();
}
private boolean isLetterOrDigit(int offset) {
@@ -404,7 +404,7 @@ public class ArrowKeyMovementMethod extends BaseMovementMethod implements Moveme
/** {@inheritDoc} */
public int preceding(int offset) {
// always round cursor index into valid string index
- offset = MathUtils.constrain(offset, 0, mCurrent.length() - 1);
+ offset = MathUtils.constrain(offset, 0, mCurrent.length());
do {
offset = mIterator.preceding(offset);
@@ -417,7 +417,7 @@ public class ArrowKeyMovementMethod extends BaseMovementMethod implements Moveme
/** {@inheritDoc} */
public int following(int offset) {
// always round cursor index into valid string index
- offset = MathUtils.constrain(offset, 0, mCurrent.length() - 1);
+ offset = MathUtils.constrain(offset, 0, mCurrent.length());
do {
offset = mIterator.following(offset);
diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java
index 5091c9e5bfa1..70836414c9a0 100644
--- a/core/java/android/text/style/SuggestionSpan.java
+++ b/core/java/android/text/style/SuggestionSpan.java
@@ -26,7 +26,7 @@ import java.util.Arrays;
import java.util.Locale;
/**
- * Sets correction candidates of words under this span.
+ * Holds suggestion candidates of words under this span.
*/
public class SuggestionSpan implements ParcelableSpan {
@@ -139,7 +139,7 @@ public class SuggestionSpan implements ParcelableSpan {
@Override
public int getSpanTypeId() {
- return TextUtils.CORRECTION_SPAN;
+ return TextUtils.SUGGESTION_SPAN;
}
public static final Parcelable.Creator<SuggestionSpan> CREATOR =
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index a39c7c70042d..eef2a33bb44d 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -505,6 +505,13 @@ public final class InputMethodManager {
}
}
+ /**
+ * Returns a list of enabled input method subtypes for the specified input method info.
+ * @param imi An input method info whose subtypes list will be returned.
+ * @param allowsImplicitlySelectedSubtypes A boolean flag to allow to return the implicitly
+ * selected subtypes. If an input method info doesn't have enabled subtypes, the framework
+ * will implicitly enable subtypes according to the current system language.
+ */
public List<InputMethodSubtype> getEnabledInputMethodSubtypeList(InputMethodInfo imi,
boolean allowsImplicitlySelectedSubtypes) {
try {
@@ -1429,16 +1436,26 @@ public final class InputMethodManager {
}
}
- public void showInputMethodAndSubtypeEnabler(String topId) {
+ /**
+ * Show the settings for enabling subtypes of the specified input method.
+ * @param imiId An input method, whose subtypes settings will be shown. If imiId is null,
+ * subtypes of all input methods will be shown.
+ */
+ public void showInputMethodAndSubtypeEnabler(String imiId) {
synchronized (mH) {
try {
- mService.showInputMethodAndSubtypeEnablerFromClient(mClient, topId);
+ mService.showInputMethodAndSubtypeEnablerFromClient(mClient, imiId);
} catch (RemoteException e) {
Log.w(TAG, "IME died: " + mCurId, e);
}
}
}
+ /**
+ * Returns the current input method subtype. This subtype is one of the subtypes in
+ * the current input method. This method returns null when the current input method doesn't
+ * have any input method subtype.
+ */
public InputMethodSubtype getCurrentInputMethodSubtype() {
synchronized (mH) {
try {
@@ -1450,6 +1467,12 @@ public final class InputMethodManager {
}
}
+ /**
+ * Switch to a new input method subtype of the current input method.
+ * @param subtype A new input method subtype to switch.
+ * @return true if the current subtype was successfully switched. When the specified subtype is
+ * null, this method returns false.
+ */
public boolean setCurrentInputMethodSubtype(InputMethodSubtype subtype) {
synchronized (mH) {
try {
@@ -1461,6 +1484,9 @@ public final class InputMethodManager {
}
}
+ /**
+ * Returns a map of all shortcut input method info and their subtypes.
+ */
public Map<InputMethodInfo, List<InputMethodSubtype>> getShortcutInputMethodsAndSubtypes() {
synchronized (mH) {
HashMap<InputMethodInfo, List<InputMethodSubtype>> ret =
@@ -1493,6 +1519,15 @@ public final class InputMethodManager {
}
}
+ /**
+ * Force switch to the last used input method and subtype. If the last input method didn't have
+ * any subtypes, the framework will simply switch to the last input method with no subtype
+ * specified.
+ * @param imeToken Supplies the identifying token given to an input method when it was started,
+ * which allows it to perform this operation on itself.
+ * @return true if the current input method and subtype was successfully switched to the last
+ * used input method and subtype.
+ */
public boolean switchToLastInputMethod(IBinder imeToken) {
synchronized (mH) {
try {
@@ -1504,6 +1539,17 @@ public final class InputMethodManager {
}
}
+ public InputMethodSubtype getLastInputMethodSubtype() {
+ synchronized (mH) {
+ try {
+ return mService.getLastInputMethodSubtype();
+ } catch (RemoteException e) {
+ Log.w(TAG, "IME died: " + mCurId, e);
+ return null;
+ }
+ }
+ }
+
void doDump(FileDescriptor fd, PrintWriter fout, String[] args) {
final Printer p = new PrintWriterPrinter(fout);
p.println("Input method client state for " + this + ":");
diff --git a/core/java/android/webkit/webdriver/By.java b/core/java/android/webkit/webdriver/By.java
new file mode 100644
index 000000000000..b40351db0213
--- /dev/null
+++ b/core/java/android/webkit/webdriver/By.java
@@ -0,0 +1,209 @@
+/*
+ * 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 android.webkit.webdriver;
+
+/**
+ * Mechanism to locate elements within the DOM of the page.
+ * @hide
+ */
+public abstract class By {
+ public abstract WebElement findElement(WebElement element);
+
+ /**
+ * Locates an element by its HTML id attribute.
+ *
+ * @param id The HTML id attribute to look for.
+ * @return A By instance that locates elements by their HTML id attributes.
+ */
+ public static By id(final String id) {
+ throwIfNull(id);
+ return new By() {
+ @Override
+ public WebElement findElement(WebElement element) {
+ return element.findElementById(id);
+ }
+
+ @Override
+ public String toString() {
+ return "By.id: " + id;
+ }
+ };
+ }
+
+ /**
+ * Locates an element by the matching the exact text on the HTML link.
+ *
+ * @param linkText The exact text to match against.
+ * @return A By instance that locates elements by the text displayed by
+ * the link.
+ */
+ public static By linkText(final String linkText) {
+ throwIfNull(linkText);
+ return new By() {
+ @Override
+ public WebElement findElement(WebElement element) {
+ return element.findElementByLinkText(linkText);
+ }
+
+ @Override
+ public String toString() {
+ return "By.linkText: " + linkText;
+ }
+ };
+ }
+
+ /**
+ * Locates an element by matching partial part of the text displayed by an
+ * HTML link.
+ *
+ * @param linkText The text that should be contained by the text displayed
+ * on the link.
+ * @return A By instance that locates elements that contain the given link
+ * text.
+ */
+ public static By partialLinkText(final String linkText) {
+ throwIfNull(linkText);
+ return new By() {
+ @Override
+ public WebElement findElement(WebElement element) {
+ return element.findElementByPartialLinkText(linkText);
+ }
+
+ @Override
+ public String toString() {
+ return "By.partialLinkText: " + linkText;
+ }
+ };
+ }
+
+ /**
+ * Locates an element by matching its HTML name attribute.
+ *
+ * @param name The value of the HTML name attribute.
+ * @return A By instance that locates elements by the HTML name attribute.
+ */
+ public static By name(final String name) {
+ throwIfNull(name);
+ return new By() {
+ @Override
+ public WebElement findElement(WebElement element) {
+ return element.findElementByName(name);
+ }
+
+ @Override
+ public String toString() {
+ return "By.name: " + name;
+ }
+ };
+ }
+
+ /**
+ * Locates an element by matching its class name.
+ * @param className The class name
+ * @return A By instance that locates elements by their class name attribute.
+ */
+ public static By className(final String className) {
+ throwIfNull(className);
+ return new By() {
+ @Override
+ public WebElement findElement(WebElement element) {
+ return element.findElementByClassName(className);
+ }
+
+ @Override
+ public String toString() {
+ return "By.className: " + className;
+ }
+ };
+ }
+
+ /**
+ * Locates an element by matching its css property.
+ *
+ * @param css The css property.
+ * @return A By instance that locates elements by their css property.
+ */
+ public static By css(final String css) {
+ throwIfNull(css);
+ return new By() {
+ @Override
+ public WebElement findElement(WebElement element) {
+ return element.findElementByCss(css);
+ }
+
+ @Override
+ public String toString() {
+ return "By.css: " + css;
+ }
+ };
+ }
+
+ /**
+ * Locates an element by matching its HTML tag name.
+ *
+ * @param tagName The HTML tag name to look for.
+ * @return A By instance that locates elements using the name of the
+ * HTML tag.
+ */
+ public static By tagName(final String tagName) {
+ throwIfNull(tagName);
+ return new By() {
+ @Override
+ public WebElement findElement(WebElement element) {
+ return element.findElementByTagName(tagName);
+ }
+
+ @Override
+ public String toString() {
+ return "By.tagName: " + tagName;
+ }
+ };
+ }
+
+ /**
+ * Locates an element using an XPath expression.
+ *
+ * <p>When using XPath, be aware that this follows standard conventions: a
+ * search prefixed with "//" will search the entire document, not just the
+ * children of the current node. Use ".//" to limit your search to the
+ * children of this {@link android.webkit.webdriver.WebElement}.
+ *
+ * @param xpath The XPath expression to use.
+ * @return A By instance that locates elements using the given XPath.
+ */
+ public static By xpath(final String xpath) {
+ throwIfNull(xpath);
+ return new By() {
+ @Override
+ public WebElement findElement(WebElement element) {
+ return element.findElementByXPath(xpath);
+ }
+
+ @Override
+ public String toString() {
+ return "By.xpath: " + xpath;
+ }
+ };
+ }
+
+ private static void throwIfNull(String argument) {
+ if (argument == null) {
+ throw new IllegalArgumentException(
+ "Cannot find elements with null locator.");
+ }
+ }
+}
diff --git a/core/java/android/webkit/webdriver/WebDriver.java b/core/java/android/webkit/webdriver/WebDriver.java
new file mode 100644
index 000000000000..90e701f99b47
--- /dev/null
+++ b/core/java/android/webkit/webdriver/WebDriver.java
@@ -0,0 +1,526 @@
+/*
+ * 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 android.webkit.webdriver;
+
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
+
+import com.android.internal.R;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.os.Handler;
+import android.os.Message;
+import android.webkit.WebView;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Drives a web application by controlling the WebView. This class
+ * provides a DOM-like API allowing to get information about the page,
+ * navigate, and interact with the web application. This is particularly useful
+ * for testing a web application.
+ *
+ * <p/>{@link android.webkit.webdriver.WebDriver} should be created in the main
+ * thread, and invoked from another thread. Here is a sample usage:
+ *
+ * public class WebDriverStubActivity extends Activity {
+ * private WebDriver mDriver;
+ *
+ * public void onCreate(Bundle savedInstanceState) {
+ * super.onCreate(savedInstanceState);
+ * WebView view = new WebView(this);
+ * mDriver = new WebDriver(view);
+ * setContentView(view);
+ * }
+ *
+ *
+ * public WebDriver getDriver() {
+ * return mDriver;
+ * }
+ *}
+ *
+ * public class WebDriverTest extends
+ * ActivityInstrumentationTestCase2<WebDriverStubActivity>{
+ * private WebDriver mDriver;
+ *
+ * public WebDriverTest() {
+ * super(WebDriverStubActivity.class);
+ * }
+ *
+ * protected void setUp() throws Exception {
+ * super.setUp();
+ * mDriver = getActivity().getDriver();
+ * }
+ *
+ * public void testGoogle() {
+ * mDriver.get("http://google.com");
+ * WebElement searchBox = mDriver.findElement(By.name("q"));
+ * q.sendKeys("Cheese!");
+ * q.submit();
+ * assertTrue(mDriver.findElements(By.partialLinkText("Cheese")).size() > 0);
+ * }
+ *}
+ *
+ * @hide
+ */
+public class WebDriver {
+ // Timeout for page load in milliseconds.
+ private static final int LOADING_TIMEOUT = 30000;
+ // Timeout for executing JavaScript in the WebView in milliseconds.
+ private static final int JS_EXECUTION_TIMEOUT = 10000;
+
+ // Commands posted to the handler
+ private static final int CMD_GET_URL = 1;
+ private static final int CMD_EXECUTE_SCRIPT = 2;
+
+ private static final String ELEMENT_KEY = "ELEMENT";
+ private static final String STATUS = "status";
+ private static final String VALUE = "value";
+
+ private static final long MAIN_THREAD = Thread.currentThread().getId();
+
+ // This is updated by a callabck from JavaScript when the result is ready.
+ private String mJsResult;
+
+ // Used for synchronization
+ private final Object mSyncObject;
+
+ // Updated when the command is done executing in the main thread.
+ private volatile boolean mCommandDone;
+
+ private WebView mWebView;
+
+ // This WebElement represents the object document.documentElement
+ private WebElement mDocumentElement;
+
+ // This Handler runs in the main UI thread.
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == CMD_GET_URL) {
+ final String url = (String) msg.obj;
+ mWebView.loadUrl(url);
+ } else if (msg.what == CMD_EXECUTE_SCRIPT) {
+ mWebView.loadUrl("javascript:" + (String) msg.obj);
+ }
+ }
+ };
+
+ /**
+ * Error codes from the WebDriver wire protocol
+ * http://code.google.com/p/selenium/wiki/JsonWireProtocol#Response_Status_Codes
+ */
+ private enum ErrorCode {
+ SUCCESS(0),
+ NO_SUCH_ELEMENT(7),
+ NO_SUCH_FRAME(8),
+ UNKNOWN_COMMAND(9),
+ UNSUPPORTED_OPERATION(9), // Alias
+ STALE_ELEMENT_REFERENCE(10),
+ ELEMENT_NOT_VISISBLE(11),
+ INVALID_ELEMENT_STATE(12),
+ UNKNOWN_ERROR(13),
+ ELEMENT_NOT_SELECTABLE(15),
+ XPATH_LOOKUP_ERROR(19),
+ NO_SUCH_WINDOW(23),
+ INVALID_COOKIE_DOMAIN(24),
+ UNABLE_TO_SET_COOKIE(25),
+ MODAL_DIALOG_OPENED(26),
+ MODAL_DIALOG_OPEN(27),
+ SCRIPT_TIMEOUT(28);
+
+ private final int mCode;
+ private static ErrorCode[] values = ErrorCode.values();
+
+ ErrorCode(int code) {
+ this.mCode = code;
+ }
+
+ public int getCode() {
+ return mCode;
+ }
+
+ public static ErrorCode get(final int intValue) {
+ for (int i = 0; i < values.length; i++) {
+ if (values[i].getCode() == intValue) {
+ return values[i];
+ }
+ }
+ throw new IllegalArgumentException(intValue
+ + " does not map to any ErrorCode.");
+ }
+ }
+
+ public WebDriver(WebView webview) {
+ this.mWebView = webview;
+ if (mWebView == null) {
+ throw new IllegalArgumentException("WebView cannot be null");
+ }
+ if (!mWebView.getSettings().getJavaScriptEnabled()) {
+ throw new RuntimeException("Javascript is disabled in the WebView. "
+ + "Enable it to use WebDriver");
+ }
+ shouldRunInMainThread(true);
+
+ mSyncObject = new Object();
+ this.mWebView = webview;
+ WebchromeClientWrapper chromeWrapper = new WebchromeClientWrapper(
+ webview.getWebChromeClient(), this);
+ mWebView.setWebChromeClient(chromeWrapper);
+ mDocumentElement = new WebElement(this, "");
+ mWebView.addJavascriptInterface(new JavascriptResultReady(),
+ "webdriver");
+ }
+
+ /**
+ * Loads a URL in the WebView. This function is blocking and will return
+ * when the page has finished loading.
+ *
+ * @param url The URL to load.
+ */
+ public void get(String url) {
+ executeCommand(CMD_GET_URL, url, LOADING_TIMEOUT);
+ }
+
+ /**
+ * @return The source page of the currently loaded page in WebView.
+ */
+ public String getPageSource() {
+ return (String) executeScript("return new XMLSerializer()."
+ + "serializeToString(document);");
+ }
+
+ /**
+ * Find the first {@link android.webkit.webdriver.WebElement} using the
+ * given method.
+ *
+ * @param by The locating mechanism to use.
+ * @return The first matching element on the current context.
+ * @throws {@link android.webkit.webdriver.WebElementNotFoundException} if
+ * no matching element was found.
+ */
+ public WebElement findElement(By by) {
+ return by.findElement(mDocumentElement);
+ }
+
+ /**
+ * Clears the WebView.
+ */
+ public void quit() {
+ mWebView.clearCache(true);
+ mWebView.clearFormData();
+ mWebView.clearHistory();
+ mWebView.clearSslPreferences();
+ mWebView.clearView();
+ }
+
+ /**
+ * Executes javascript in the context of the main frame.
+ *
+ * If the script has a return value the following happens:
+ * <ul>
+ * <li>For an HTML element, this method returns a WebElement</li>
+ * <li>For a decimal, a Double is returned</li>
+ * <li>For non-decimal number, a Long is returned</li>
+ * <li>For a boolean, a Boolean is returned</li>
+ * <li>For all other cases, a String is returned</li>
+ * <li>For an array, this returns a List<Object> with each object
+ * following the rules above.</li>
+ * <li>For an object literal this returns a Map<String, Object>. Note that
+ * Object literals keys can only be Strings. Non Strings keys will
+ * be filtered out.</li>
+ * </ul>
+ *
+ * <p> Arguments must be a number, a boolean, a string a WebElement or
+ * a list of any combination of the above. The arguments will be made
+ * available to the javascript via the "arguments" magic variable,
+ * as if the function was called via "Function.apply".
+ *
+ * @param script The JavaScript to execute.
+ * @param args The arguments to the script. Can be any of a number, boolean,
+ * string, WebElement or a List of those.
+ * @return A Boolean, Long, Double, String, WebElement, List or null.
+ */
+ public Object executeScript(final String script, final Object... args) {
+ String scriptArgs = "[" + convertToJsArgs(args) + "]";
+ String injectScriptJs = getResourceAsString(R.raw.execute_script_android);
+ return executeRawJavascript("(" + injectScriptJs +
+ ")(" + escapeAndQuote(script) + ", " + scriptArgs + ", true)");
+ }
+
+ /**
+ * Converts the arguments passed to a JavaScript friendly format.
+ *
+ * @param args The arguments to convert.
+ * @return Comma separated Strings containing the arguments.
+ */
+ /*package*/ String convertToJsArgs(final Object... args) {
+ StringBuilder toReturn = new StringBuilder();
+ int length = args.length;
+ for (int i = 0; i < length; i++) {
+ toReturn.append((i > 0) ? "," : "");
+ if (args[i] instanceof List<?>) {
+ toReturn.append("[");
+ List<Object> aList = (List<Object>) args[i];
+ for (int j = 0 ; j < aList.size(); j++) {
+ String comma = ((j == 0) ? "" : ",");
+ toReturn.append(comma + convertToJsArgs(aList.get(j)));
+ }
+ toReturn.append("]");
+ } else if (args[i] instanceof Map<?, ?>) {
+ Map<Object, Object> aMap = (Map<Object, Object>) args[i];
+ String toAdd = "{";
+ for (Object key: aMap.keySet()) {
+ toAdd += key + ":"
+ + convertToJsArgs(aMap.get(key)) + ",";
+ }
+ toReturn.append(toAdd.substring(0, toAdd.length() -1) + "}");
+ } else if (args[i] instanceof WebElement) {
+ // WebElement are represented in JavaScript by Objects as
+ // follow: {ELEMENT:"id"}
+ toReturn.append("{" + ELEMENT_KEY + ":\""
+ + ((WebElement) args[i]).getId() + "\"}");
+ } else if (args[i] instanceof Number || args[i] instanceof Boolean) {
+ toReturn.append(String.valueOf(args[i]));
+ } else if (args[i] instanceof String) {
+ toReturn.append(escapeAndQuote((String) args[i]));
+ } else {
+ throw new IllegalArgumentException(
+ "Javascript arguments can be "
+ + "a Number, a Boolean, a String, a WebElement, "
+ + "or a List or a Map of those. Got: "
+ + ((args[i] == null) ? "null" : args[i].toString()));
+ }
+ }
+ return toReturn.toString();
+ }
+
+ /*package*/ Object executeRawJavascript(final String script) {
+ String result = executeCommand(CMD_EXECUTE_SCRIPT,
+ "window.webdriver.resultReady(" + script + ")",
+ JS_EXECUTION_TIMEOUT);
+ try {
+ JSONObject json = new JSONObject(result);
+ throwIfError(json);
+ Object value = json.get(VALUE);
+ return convertJsonToJavaObject(value);
+ } catch (JSONException e) {
+ throw new RuntimeException("Failed to parse JavaScript result: "
+ + result.toString(), e);
+ }
+ }
+
+ /*package*/ String getResourceAsString(final int resourceId) {
+ InputStream is = mWebView.getResources().openRawResource(resourceId);
+ BufferedReader br = new BufferedReader(new InputStreamReader(is));
+ StringBuilder sb = new StringBuilder();
+ String line = null;
+ try {
+ while ((line = br.readLine()) != null) {
+ sb.append(line);
+ }
+ br.close();
+ is.close();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to open JavaScript resource.", e);
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Wraps the given string into quotes and escape existing quotes
+ * and backslashes.
+ * "foo" -> "\"foo\""
+ * "foo\"" -> "\"foo\\\"\""
+ * "fo\o" -> "\"fo\\o\""
+ *
+ * @param toWrap The String to wrap in quotes
+ * @return a String wrapping the original String in quotes
+ */
+ private static String escapeAndQuote(final String toWrap) {
+ StringBuilder toReturn = new StringBuilder("\"");
+ for (int i = 0; i < toWrap.length(); i++) {
+ char c = toWrap.charAt(i);
+ if (c == '\"') {
+ toReturn.append("\\\"");
+ } else if (c == '\\') {
+ toReturn.append("\\\\");
+ } else {
+ toReturn.append(c);
+ }
+ }
+ toReturn.append("\"");
+ return toReturn.toString();
+ }
+
+ private Object convertJsonToJavaObject(final Object toConvert) {
+ try {
+ if (toConvert == null
+ || toConvert.equals(null)
+ || "undefined".equals(toConvert)
+ || "null".equals(toConvert)) {
+ return null;
+ } else if (toConvert instanceof Boolean) {
+ return toConvert;
+ } else if (toConvert instanceof Double
+ || toConvert instanceof Float) {
+ return Double.valueOf(String.valueOf(toConvert));
+ } else if (toConvert instanceof Integer
+ || toConvert instanceof Long) {
+ return Long.valueOf(String.valueOf(toConvert));
+ } else if (toConvert instanceof JSONArray) { // List
+ return convertJsonArrayToList((JSONArray) toConvert);
+ } else if (toConvert instanceof JSONObject) { // Map or WebElment
+ JSONObject map = (JSONObject) toConvert;
+ if (map.opt(ELEMENT_KEY) != null) { // WebElement
+ return new WebElement(this, (String) map.get(ELEMENT_KEY));
+ } else { // Map
+ return convertJsonObjectToMap(map);
+ }
+ } else {
+ return toConvert.toString();
+ }
+ } catch (JSONException e) {
+ throw new RuntimeException("Failed to parse JavaScript result: "
+ + toConvert.toString(), e);
+ }
+ }
+
+ private List<Object> convertJsonArrayToList(final JSONArray json) {
+ List<Object> toReturn = Lists.newArrayList();
+ for (int i = 0; i < json.length(); i++) {
+ try {
+ toReturn.add(convertJsonToJavaObject(json.get(i)));
+ } catch (JSONException e) {
+ throw new RuntimeException("Failed to parse JSON: "
+ + json.toString(), e);
+ }
+ }
+ return toReturn;
+ }
+
+ private Map<Object, Object> convertJsonObjectToMap(final JSONObject json) {
+ Map<Object, Object> toReturn = Maps.newHashMap();
+ for (Iterator it = json.keys(); it.hasNext();) {
+ String key = (String) it.next();
+ try {
+ Object value = json.get(key);
+ toReturn.put(convertJsonToJavaObject(key),
+ convertJsonToJavaObject(value));
+ } catch (JSONException e) {
+ throw new RuntimeException("Failed to parse JSON:"
+ + json.toString(), e);
+ }
+ }
+ return toReturn;
+ }
+
+ private void throwIfError(final JSONObject jsonObject) {
+ ErrorCode status;
+ String errorMsg;
+ try {
+ status = ErrorCode.get((Integer) jsonObject.get(STATUS));
+ errorMsg = String.valueOf(jsonObject.get(VALUE));
+ } catch (JSONException e) {
+ throw new RuntimeException("Failed to parse JSON Object: "
+ + jsonObject, e);
+ }
+ switch (status) {
+ case SUCCESS:
+ return;
+ case NO_SUCH_ELEMENT:
+ throw new WebElementNotFoundException("Could not find "
+ + "WebElement.");
+ case STALE_ELEMENT_REFERENCE:
+ throw new WebElementStaleException("WebElement is stale.");
+ default:
+ throw new RuntimeException("Error: " + errorMsg);
+ }
+ }
+
+ private void shouldRunInMainThread(boolean value) {
+ assert (value == (MAIN_THREAD == Thread.currentThread().getId()));
+ }
+
+ /**
+ * Interface called from JavaScript when the result is ready.
+ */
+ private class JavascriptResultReady {
+
+ /**
+ * A callback from JavaScript to Java that passes the result as a
+ * parameter. This method is available from the WebView's
+ * JavaScript DOM as window.webdriver.resultReady().
+ *
+ * @param result The result that should be sent to Java from Javascript.
+ */
+ public void resultReady(final String result) {
+ synchronized (mSyncObject) {
+ mJsResult = result;
+ mCommandDone = true;
+ mSyncObject.notify();
+ }
+ }
+ }
+
+ /* package */ void notifyCommandDone() {
+ synchronized (mSyncObject) {
+ mCommandDone = true;
+ mSyncObject.notify();
+ }
+ }
+
+ /**
+ * Executes the given command by posting a message to mHandler. This thread
+ * will block until the command which runs in the main thread is done.
+ *
+ * @param command The command to run.
+ * @param arg The argument for that command.
+ * @param timeout A timeout in milliseconds.
+ */
+ private String executeCommand(int command, final Object arg, long timeout) {
+ shouldRunInMainThread(false);
+ synchronized (mSyncObject) {
+ mCommandDone = false;
+ Message msg = mHandler.obtainMessage(command);
+ msg.obj = arg;
+ mHandler.sendMessage(msg);
+
+ long end = System.currentTimeMillis() + timeout;
+ while (!mCommandDone) {
+ if (System.currentTimeMillis() >= end) {
+ throw new RuntimeException("Timeout executing command.");
+ }
+ try {
+ mSyncObject.wait(timeout);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+ return mJsResult;
+ }
+}
diff --git a/core/java/android/webkit/webdriver/WebElement.java b/core/java/android/webkit/webdriver/WebElement.java
new file mode 100644
index 000000000000..384d55f4b552
--- /dev/null
+++ b/core/java/android/webkit/webdriver/WebElement.java
@@ -0,0 +1,136 @@
+/*
+ * 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 android.webkit.webdriver;
+
+import com.android.internal.R;
+
+/**
+ * Represents an HTML element. Typically most interactions with a web page
+ * will be performed through this class.
+ *
+ * @hide
+ */
+public class WebElement {
+ private final String mId;
+ private final WebDriver mDriver;
+
+ /**
+ * Package constructor to prevent clients from creating a new WebElement
+ * instance.
+ *
+ * <p> A WebElement represents an HTML element on the page.
+ * The corresponding HTML element is stored in a JS cache in the page
+ * that can be accessed through JavaScript using "bot.inject.cache".
+ *
+ * @param driver The WebDriver instance to use.
+ * @param id The index of the HTML element in the JavaSctipt cache. Pass
+ * an empty String to indicate that this is the
+ * document.documentElement object.
+ */
+ /* Package */ WebElement(final WebDriver driver, final String id) {
+ this.mId = id;
+ this.mDriver = driver;
+ }
+
+ /**
+ * Finds the first {@link android.webkit.webdriver.WebElement} using the
+ * given method.
+ *
+ * @param by The locating mechanism to use.
+ * @return The first matching element on the current context.
+ */
+ public WebElement findElement(final By by) {
+ return by.findElement(this);
+ }
+
+ /**
+ * Gets the visisble (i.e. not hidden by CSS) innerText of this element,
+ * inlcuding sub-elements.
+ *
+ * @return the innerText of this element.
+ * @throws {@link android.webkit.webdriver.WebElementStaleException} if this
+ * element is stale, i.e. not on the current DOM.
+ */
+ public String getText() {
+ String getText = mDriver.getResourceAsString(R.raw.get_text_android);
+ if (mId.equals("")) {
+ return null;
+ }
+ return (String) executeAtom(getText, this);
+ }
+
+ /*package*/ String getId() {
+ return mId;
+ }
+
+ /* package */ WebElement findElementById(final String locator) {
+ return findElement("id", locator);
+ }
+
+ /* package */ WebElement findElementByLinkText(final String linkText) {
+ return findElement("linkText", linkText);
+ }
+
+ /* package */ WebElement findElementByPartialLinkText(
+ final String linkText) {
+ return findElement("partialLinkText", linkText);
+ }
+
+ /* package */ WebElement findElementByName(final String name) {
+ return findElement("name", name);
+ }
+
+ /* package */ WebElement findElementByClassName(final String className) {
+ return findElement("className", className);
+ }
+
+ /* package */ WebElement findElementByCss(final String css) {
+ return findElement("css", css);
+ }
+
+ /* package */ WebElement findElementByTagName(final String tagName) {
+ return findElement("tagName", tagName);
+ }
+
+ /* package */ WebElement findElementByXPath(final String xpath) {
+ return findElement("xpath", xpath);
+ }
+
+ private Object executeAtom(final String atom, final Object... args) {
+ String scriptArgs = mDriver.convertToJsArgs(args);
+ return mDriver.executeRawJavascript("(" +
+ atom + ")(" + scriptArgs + ")");
+ }
+
+ private WebElement findElement(String strategy, String locator) {
+ String findElement = mDriver.getResourceAsString(
+ R.raw.find_element_android);
+ WebElement el;
+ if (mId.equals("")) {
+ // Use default as root which is the document object
+ el = (WebElement) executeAtom(findElement, strategy, locator);
+ } else {
+ // Use this as root
+ el = (WebElement) executeAtom(findElement, strategy, locator, this);
+ }
+ if (el == null) {
+ throw new WebElementNotFoundException("Could not find element "
+ + "with " + strategy + ": " + locator);
+ }
+ return el;
+ }
+}
diff --git a/core/java/android/webkit/webdriver/WebElementNotFoundException.java b/core/java/android/webkit/webdriver/WebElementNotFoundException.java
new file mode 100644
index 000000000000..e66d279f0a04
--- /dev/null
+++ b/core/java/android/webkit/webdriver/WebElementNotFoundException.java
@@ -0,0 +1,41 @@
+/*
+ * 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 android.webkit.webdriver;
+
+/**
+ * Thrown when a {@link android.webkit.webdriver.WebElement} is not found in the
+ * DOM of the page.
+ * @hide
+ */
+public class WebElementNotFoundException extends RuntimeException {
+
+ public WebElementNotFoundException() {
+ super();
+ }
+
+ public WebElementNotFoundException(String reason) {
+ super(reason);
+ }
+
+ public WebElementNotFoundException(String reason, Throwable cause) {
+ super(reason, cause);
+ }
+
+ public WebElementNotFoundException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/core/java/android/webkit/webdriver/WebElementStaleException.java b/core/java/android/webkit/webdriver/WebElementStaleException.java
new file mode 100644
index 000000000000..c59e7945b4fa
--- /dev/null
+++ b/core/java/android/webkit/webdriver/WebElementStaleException.java
@@ -0,0 +1,42 @@
+/*
+ * 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 android.webkit.webdriver;
+
+/**
+ * Thrown when trying to access a {@link android.webkit.webdriver.WebElement}
+ * that is stale. This mean that the {@link android.webkit.webdriver.WebElement}
+ * is no longer present on the DOM of the page.
+ * @hide
+ */
+public class WebElementStaleException extends RuntimeException {
+
+ public WebElementStaleException() {
+ super();
+ }
+
+ public WebElementStaleException(String reason) {
+ super(reason);
+ }
+
+ public WebElementStaleException(String reason, Throwable cause) {
+ super(reason, cause);
+ }
+
+ public WebElementStaleException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/core/java/android/webkit/webdriver/WebchromeClientWrapper.java b/core/java/android/webkit/webdriver/WebchromeClientWrapper.java
new file mode 100644
index 000000000000..ea33c5b48dbe
--- /dev/null
+++ b/core/java/android/webkit/webdriver/WebchromeClientWrapper.java
@@ -0,0 +1,193 @@
+/*
+ * 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 android.webkit.webdriver;
+
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.os.Message;
+import android.view.View;
+import android.webkit.ConsoleMessage;
+import android.webkit.GeolocationPermissions;
+import android.webkit.JsPromptResult;
+import android.webkit.JsResult;
+import android.webkit.ValueCallback;
+import android.webkit.WebChromeClient;
+import android.webkit.WebStorage;
+import android.webkit.WebView;
+
+/* package */ class WebchromeClientWrapper extends WebChromeClient {
+
+ private final WebChromeClient mDelegate;
+ private final WebDriver mDriver;
+
+ public WebchromeClientWrapper(WebChromeClient delegate, WebDriver driver) {
+ if (delegate == null) {
+ this.mDelegate = new WebChromeClient();
+ } else {
+ this.mDelegate = delegate;
+ }
+ this.mDriver = driver;
+ }
+
+ @Override
+ public void onProgressChanged(WebView view, int newProgress) {
+ if (newProgress == 100) {
+ mDriver.notifyCommandDone();
+ }
+ mDelegate.onProgressChanged(view, newProgress);
+ }
+
+ @Override
+ public void onReceivedTitle(WebView view, String title) {
+ mDelegate.onReceivedTitle(view, title);
+ }
+
+ @Override
+ public void onReceivedIcon(WebView view, Bitmap icon) {
+ mDelegate.onReceivedIcon(view, icon);
+ }
+
+ @Override
+ public void onReceivedTouchIconUrl(WebView view, String url,
+ boolean precomposed) {
+ mDelegate.onReceivedTouchIconUrl(view, url, precomposed);
+ }
+
+ @Override
+ public void onShowCustomView(View view,
+ CustomViewCallback callback) {
+ mDelegate.onShowCustomView(view, callback);
+ }
+
+ @Override
+ public void onHideCustomView() {
+ mDelegate.onHideCustomView();
+ }
+
+ @Override
+ public boolean onCreateWindow(WebView view, boolean dialog,
+ boolean userGesture, Message resultMsg) {
+ return mDelegate.onCreateWindow(view, dialog, userGesture, resultMsg);
+ }
+
+ @Override
+ public void onRequestFocus(WebView view) {
+ mDelegate.onRequestFocus(view);
+ }
+
+ @Override
+ public void onCloseWindow(WebView window) {
+ mDelegate.onCloseWindow(window);
+ }
+
+ @Override
+ public boolean onJsAlert(WebView view, String url, String message,
+ JsResult result) {
+ return mDelegate.onJsAlert(view, url, message, result);
+ }
+
+ @Override
+ public boolean onJsConfirm(WebView view, String url, String message,
+ JsResult result) {
+ return mDelegate.onJsConfirm(view, url, message, result);
+ }
+
+ @Override
+ public boolean onJsPrompt(WebView view, String url, String message,
+ String defaultValue, JsPromptResult result) {
+ return mDelegate.onJsPrompt(view, url, message, defaultValue, result);
+ }
+
+ @Override
+ public boolean onJsBeforeUnload(WebView view, String url, String message,
+ JsResult result) {
+ return mDelegate.onJsBeforeUnload(view, url, message, result);
+ }
+
+ @Override
+ public void onExceededDatabaseQuota(String url, String databaseIdentifier,
+ long currentQuota, long estimatedSize, long totalUsedQuota,
+ WebStorage.QuotaUpdater quotaUpdater) {
+ mDelegate.onExceededDatabaseQuota(url, databaseIdentifier, currentQuota,
+ estimatedSize, totalUsedQuota, quotaUpdater);
+ }
+
+ @Override
+ public void onReachedMaxAppCacheSize(long spaceNeeded, long totalUsedQuota,
+ WebStorage.QuotaUpdater quotaUpdater) {
+ mDelegate.onReachedMaxAppCacheSize(spaceNeeded, totalUsedQuota,
+ quotaUpdater);
+ }
+
+ @Override
+ public void onGeolocationPermissionsShowPrompt(String origin,
+ GeolocationPermissions.Callback callback) {
+ mDelegate.onGeolocationPermissionsShowPrompt(origin, callback);
+ }
+
+ @Override
+ public void onGeolocationPermissionsHidePrompt() {
+ mDelegate.onGeolocationPermissionsHidePrompt();
+ }
+
+ @Override
+ public boolean onJsTimeout() {
+ return mDelegate.onJsTimeout();
+ }
+
+ @Override
+ public void onConsoleMessage(String message, int lineNumber,
+ String sourceID) {
+ mDelegate.onConsoleMessage(message, lineNumber, sourceID);
+ }
+
+ @Override
+ public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
+ return mDelegate.onConsoleMessage(consoleMessage);
+ }
+
+ @Override
+ public Bitmap getDefaultVideoPoster() {
+ return mDelegate.getDefaultVideoPoster();
+ }
+
+ @Override
+ public View getVideoLoadingProgressView() {
+ return mDelegate.getVideoLoadingProgressView();
+ }
+
+ @Override
+ public void getVisitedHistory(ValueCallback<String[]> callback) {
+ mDelegate.getVisitedHistory(callback);
+ }
+
+ @Override
+ public void openFileChooser(ValueCallback<Uri> uploadFile,
+ String acceptType) {
+ mDelegate.openFileChooser(uploadFile, acceptType);
+ }
+
+ @Override
+ public void setInstallableWebApp() {
+ mDelegate.setInstallableWebApp();
+ }
+
+ @Override
+ public void setupAutoFill(Message msg) {
+ mDelegate.setupAutoFill(msg);
+ }
+}
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index f659eadaadbe..590a76820bc3 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -39,7 +39,7 @@ import java.util.ArrayList;
* Children are drawn in a stack, with the most recently added child on top.
* The size of the frame layout is the size of its largest child (plus padding), visible
* or not (if the FrameLayout's parent permits). Views that are GONE are used for sizing
- * only if {@link #setMeasureAllChildren(boolean) setConsiderGoneChildrenWhenMeasuring()}
+ * only if {@link #setMeasureAllChildren(boolean) setMeasureAllChildren()}
* is set to true.
*
* @attr ref android.R.styleable#FrameLayout_foreground
@@ -566,4 +566,3 @@ public class FrameLayout extends ViewGroup {
}
}
}
-
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index d86504d0cd50..7cf33fcee754 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -36,6 +36,7 @@ import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.util.Log;
+import android.util.LogWriter;
import android.util.PrintWriterPrinter;
import android.util.Printer;
import android.util.Slog;
@@ -70,7 +71,7 @@ public final class BatteryStatsImpl extends BatteryStats {
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 54;
+ private static final int VERSION = 60;
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -154,11 +155,27 @@ public final class BatteryStatsImpl extends BatteryStats {
boolean mHaveBatteryLevel = false;
boolean mRecordingHistory = true;
int mNumHistoryItems;
+
+ static final int MAX_HISTORY_BUFFER = 128*1024; // 128KB
+ static final int MAX_MAX_HISTORY_BUFFER = 144*1024; // 144KB
+ final Parcel mHistoryBuffer = Parcel.obtain();
+ final HistoryItem mHistoryLastWritten = new HistoryItem();
+ final HistoryItem mHistoryLastLastWritten = new HistoryItem();
+ final HistoryItem mHistoryReadTmp = new HistoryItem();
+ int mHistoryBufferLastPos = -1;
+ boolean mHistoryOverflow = false;
+ long mLastHistoryTime = 0;
+
+ final HistoryItem mHistoryCur = new HistoryItem();
+
HistoryItem mHistory;
HistoryItem mHistoryEnd;
HistoryItem mHistoryLastEnd;
HistoryItem mHistoryCache;
- final HistoryItem mHistoryCur = new HistoryItem();
+
+ private HistoryItem mHistoryIterator;
+ private boolean mReadOverflow;
+ private boolean mIteratingHistory;
int mStartCount;
@@ -1189,9 +1206,84 @@ public final class BatteryStatsImpl extends BatteryStats {
mBtHeadset = headset;
}
+ int mChangedBufferStates = 0;
+
+ void addHistoryBufferLocked(long curTime) {
+ if (!mHaveBatteryLevel || !mRecordingHistory) {
+ return;
+ }
+
+ final long timeDiff = (mHistoryBaseTime+curTime) - mHistoryLastWritten.time;
+ if (mHistoryBufferLastPos >= 0 && mHistoryLastWritten.cmd == HistoryItem.CMD_UPDATE
+ && timeDiff < 2000
+ && ((mHistoryLastWritten.states^mHistoryCur.states)&mChangedBufferStates) == 0) {
+ // If the current is the same as the one before, then we no
+ // longer need the entry.
+ mHistoryBuffer.setDataSize(mHistoryBufferLastPos);
+ mHistoryBuffer.setDataPosition(mHistoryBufferLastPos);
+ mHistoryBufferLastPos = -1;
+ if (mHistoryLastLastWritten.cmd == HistoryItem.CMD_UPDATE
+ && timeDiff < 500 && mHistoryLastLastWritten.same(mHistoryCur)) {
+ // If this results in us returning to the state written
+ // prior to the last one, then we can just delete the last
+ // written one and drop the new one. Nothing more to do.
+ mHistoryLastWritten.setTo(mHistoryLastLastWritten);
+ mHistoryLastLastWritten.cmd = HistoryItem.CMD_NULL;
+ return;
+ }
+ mChangedBufferStates |= mHistoryLastWritten.states^mHistoryCur.states;
+ curTime = mHistoryLastWritten.time - mHistoryBaseTime;
+ mHistoryLastWritten.setTo(mHistoryLastLastWritten);
+ } else {
+ mChangedBufferStates = 0;
+ }
+
+ final int dataSize = mHistoryBuffer.dataSize();
+ if (dataSize >= MAX_HISTORY_BUFFER) {
+ if (!mHistoryOverflow) {
+ mHistoryOverflow = true;
+ addHistoryBufferLocked(curTime, HistoryItem.CMD_OVERFLOW);
+ }
+
+ // Once we've reached the maximum number of items, we only
+ // record changes to the battery level and the most interesting states.
+ // Once we've reached the maximum maximum number of items, we only
+ // record changes to the battery level.
+ if (mHistoryLastWritten.batteryLevel == mHistoryCur.batteryLevel &&
+ (dataSize >= MAX_MAX_HISTORY_BUFFER
+ || ((mHistoryEnd.states^mHistoryCur.states)
+ & HistoryItem.MOST_INTERESTING_STATES) == 0)) {
+ return;
+ }
+ }
+
+ addHistoryBufferLocked(curTime, HistoryItem.CMD_UPDATE);
+ }
+
+ void addHistoryBufferLocked(long curTime, byte cmd) {
+ int origPos = 0;
+ if (mIteratingHistory) {
+ origPos = mHistoryBuffer.dataPosition();
+ mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
+ }
+ mHistoryBufferLastPos = mHistoryBuffer.dataPosition();
+ mHistoryLastLastWritten.setTo(mHistoryLastWritten);
+ mHistoryLastWritten.setTo(mHistoryBaseTime + curTime, cmd, mHistoryCur);
+ mHistoryLastWritten.writeDelta(mHistoryBuffer, mHistoryLastLastWritten);
+ mLastHistoryTime = curTime;
+ if (DEBUG_HISTORY) Slog.i(TAG, "Writing history buffer: was " + mHistoryBufferLastPos
+ + " now " + mHistoryBuffer.dataPosition()
+ + " size is now " + mHistoryBuffer.dataSize());
+ if (mIteratingHistory) {
+ mHistoryBuffer.setDataPosition(origPos);
+ }
+ }
+
int mChangedStates = 0;
void addHistoryRecordLocked(long curTime) {
+ addHistoryBufferLocked(curTime);
+
if (!mHaveBatteryLevel || !mRecordingHistory) {
return;
}
@@ -1206,6 +1298,7 @@ public final class BatteryStatsImpl extends BatteryStats {
// If the current is the same as the one before, then we no
// longer need the entry.
if (mHistoryLastEnd != null && mHistoryLastEnd.cmd == HistoryItem.CMD_UPDATE
+ && (mHistoryBaseTime+curTime) < (mHistoryEnd.time+500)
&& mHistoryLastEnd.same(mHistoryCur)) {
mHistoryLastEnd.next = null;
mHistoryEnd.next = mHistoryCache;
@@ -1268,6 +1361,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
void clearHistoryLocked() {
+ if (DEBUG_HISTORY) Slog.i(TAG, "********** CLEARING HISTORY!");
if (mHistory != null) {
mHistoryEnd.next = mHistoryCache;
mHistoryCache = mHistory;
@@ -1275,6 +1369,15 @@ public final class BatteryStatsImpl extends BatteryStats {
}
mNumHistoryItems = 0;
mHistoryBaseTime = 0;
+ mLastHistoryTime = 0;
+
+ mHistoryBuffer.setDataSize(0);
+ mHistoryBuffer.setDataPosition(0);
+ mHistoryBuffer.setDataCapacity(MAX_HISTORY_BUFFER/2);
+ mHistoryLastLastWritten.cmd = HistoryItem.CMD_NULL;
+ mHistoryLastWritten.cmd = HistoryItem.CMD_NULL;
+ mHistoryBufferLastPos = -1;
+ mHistoryOverflow = false;
}
public void doUnplugLocked(long batteryUptime, long batteryRealtime) {
@@ -3910,11 +4013,13 @@ public final class BatteryStatsImpl extends BatteryStats {
mDischargeUnplugLevel = 0;
mDischargeCurrentLevel = 0;
initDischarge();
+ clearHistoryLocked();
}
public BatteryStatsImpl(Parcel p) {
mFile = null;
mHandler = null;
+ clearHistoryLocked();
readFromParcel(p);
}
@@ -3932,25 +4037,84 @@ public final class BatteryStatsImpl extends BatteryStats {
}
}
- private HistoryItem mHistoryIterator;
-
- public boolean startIteratingHistoryLocked() {
+ @Override
+ public boolean startIteratingOldHistoryLocked() {
+ if (DEBUG_HISTORY) Slog.i(TAG, "ITERATING: buff size=" + mHistoryBuffer.dataSize()
+ + " pos=" + mHistoryBuffer.dataPosition());
+ mHistoryBuffer.setDataPosition(0);
+ mHistoryReadTmp.clear();
+ mReadOverflow = false;
+ mIteratingHistory = true;
return (mHistoryIterator = mHistory) != null;
}
- public boolean getNextHistoryLocked(HistoryItem out) {
+ @Override
+ public boolean getNextOldHistoryLocked(HistoryItem out) {
+ boolean end = mHistoryBuffer.dataPosition() >= mHistoryBuffer.dataSize();
+ if (!end) {
+ mHistoryReadTmp.readDelta(mHistoryBuffer);
+ mReadOverflow |= mHistoryReadTmp.cmd == HistoryItem.CMD_OVERFLOW;
+ }
HistoryItem cur = mHistoryIterator;
if (cur == null) {
+ if (!mReadOverflow && !end) {
+ Slog.w(TAG, "Old history ends before new history!");
+ }
return false;
}
out.setTo(cur);
mHistoryIterator = cur.next;
+ if (!mReadOverflow) {
+ if (end) {
+ Slog.w(TAG, "New history ends before old history!");
+ } else if (!out.same(mHistoryReadTmp)) {
+ long now = getHistoryBaseTime() + SystemClock.elapsedRealtime();
+ PrintWriter pw = new PrintWriter(new LogWriter(android.util.Log.WARN, TAG));
+ pw.println("Histories differ!");
+ pw.println("Old history:");
+ (new HistoryPrinter()).printNextItem(pw, out, now);
+ pw.println("New history:");
+ (new HistoryPrinter()).printNextItem(pw, mHistoryReadTmp, now);
+ }
+ }
return true;
}
@Override
- public HistoryItem getHistory() {
- return mHistory;
+ public void finishIteratingOldHistoryLocked() {
+ mIteratingHistory = false;
+ mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
+ }
+
+ @Override
+ public boolean startIteratingHistoryLocked() {
+ if (DEBUG_HISTORY) Slog.i(TAG, "ITERATING: buff size=" + mHistoryBuffer.dataSize()
+ + " pos=" + mHistoryBuffer.dataPosition());
+ mHistoryBuffer.setDataPosition(0);
+ mReadOverflow = false;
+ mIteratingHistory = true;
+ return mHistoryBuffer.dataSize() > 0;
+ }
+
+ @Override
+ public boolean getNextHistoryLocked(HistoryItem out) {
+ final int pos = mHistoryBuffer.dataPosition();
+ if (pos == 0) {
+ out.clear();
+ }
+ boolean end = pos >= mHistoryBuffer.dataSize();
+ if (end) {
+ return false;
+ }
+
+ out.readDelta(mHistoryBuffer);
+ return true;
+ }
+
+ @Override
+ public void finishIteratingHistoryLocked() {
+ mIteratingHistory = false;
+ mHistoryBuffer.setDataPosition(mHistoryBuffer.dataSize());
}
@Override
@@ -4697,7 +4861,9 @@ public final class BatteryStatsImpl extends BatteryStats {
Slog.e("BatteryStats", "Error reading battery statistics", e);
}
- addHistoryRecordLocked(SystemClock.elapsedRealtime(), HistoryItem.CMD_START);
+ long now = SystemClock.elapsedRealtime();
+ addHistoryRecordLocked(now, HistoryItem.CMD_START);
+ addHistoryBufferLocked(now, HistoryItem.CMD_START);
}
public int describeContents() {
@@ -4705,30 +4871,54 @@ public final class BatteryStatsImpl extends BatteryStats {
}
void readHistory(Parcel in) {
- mHistory = mHistoryEnd = mHistoryCache = null;
- mHistoryBaseTime = 0;
- long time;
- while ((time=in.readLong()) >= 0) {
- HistoryItem rec = new HistoryItem(time, in);
- addHistoryRecordLocked(rec);
- if (rec.time > mHistoryBaseTime) {
- mHistoryBaseTime = rec.time;
- }
+ mHistoryBaseTime = in.readLong();
+
+ mHistoryBuffer.setDataSize(0);
+ mHistoryBuffer.setDataPosition(0);
+
+ int bufSize = in.readInt();
+ int curPos = in.dataPosition();
+ if (bufSize >= (MAX_MAX_HISTORY_BUFFER*3)) {
+ Slog.w(TAG, "File corrupt: history data buffer too large " + bufSize);
+ } else if ((bufSize&~3) != bufSize) {
+ Slog.w(TAG, "File corrupt: history data buffer not aligned " + bufSize);
+ } else {
+ if (DEBUG_HISTORY) Slog.i(TAG, "***************** READING NEW HISTORY: " + bufSize
+ + " bytes at " + curPos);
+ mHistoryBuffer.appendFrom(in, curPos, bufSize);
+ in.setDataPosition(curPos + bufSize);
}
- long oldnow = SystemClock.elapsedRealtime() - (5*60*100);
+ long oldnow = SystemClock.elapsedRealtime() - (5*60*1000);
if (oldnow > 0) {
// If the system process has restarted, but not the entire
// system, then the mHistoryBaseTime already accounts for
// much of the elapsed time. We thus want to adjust it back,
// to avoid large gaps in the data. We determine we are
// in this case by arbitrarily saying it is so if at this
- // point in boot the elapsed time is already more than 5 seconds.
+ // point in boot the elapsed time is already more than 5 minutes.
mHistoryBaseTime -= oldnow;
}
}
+ void readOldHistory(Parcel in) {
+ mHistory = mHistoryEnd = mHistoryCache = null;
+ long time;
+ while ((time=in.readLong()) >= 0) {
+ HistoryItem rec = new HistoryItem(time, in);
+ addHistoryRecordLocked(rec);
+ }
+ }
+
void writeHistory(Parcel out) {
+ out.writeLong(mLastHistoryTime);
+ out.writeInt(mHistoryBuffer.dataSize());
+ if (DEBUG_HISTORY) Slog.i(TAG, "***************** WRITING HISTORY: "
+ + mHistoryBuffer.dataSize() + " bytes at " + out.dataPosition());
+ out.appendFrom(mHistoryBuffer, 0, mHistoryBuffer.dataSize());
+ }
+
+ void writeOldHistory(Parcel out) {
HistoryItem rec = mHistory;
while (rec != null) {
if (rec.time >= 0) rec.writeToParcel(out, 0);
@@ -4746,6 +4936,7 @@ public final class BatteryStatsImpl extends BatteryStats {
}
readHistory(in);
+ readOldHistory(in);
mStartCount = in.readInt();
mBatteryUptime = in.readLong();
@@ -4935,6 +5126,9 @@ public final class BatteryStatsImpl extends BatteryStats {
* @param out the Parcel to be written to.
*/
public void writeSummaryToParcel(Parcel out) {
+ // Need to update with current kernel wake lock counts.
+ updateKernelWakelocksLocked();
+
final long NOW_SYS = SystemClock.uptimeMillis() * 1000;
final long NOWREAL_SYS = SystemClock.elapsedRealtime() * 1000;
final long NOW = getBatteryUptimeLocked(NOW_SYS);
@@ -4943,6 +5137,7 @@ public final class BatteryStatsImpl extends BatteryStats {
out.writeInt(VERSION);
writeHistory(out);
+ writeOldHistory(out);
out.writeInt(mStartCount);
out.writeLong(computeBatteryUptime(NOW_SYS, STATS_SINCE_CHARGED));
@@ -5256,6 +5451,9 @@ public final class BatteryStatsImpl extends BatteryStats {
@SuppressWarnings("unused")
void writeToParcelLocked(Parcel out, boolean inclUids, int flags) {
+ // Need to update with current kernel wake lock counts.
+ updateKernelWakelocksLocked();
+
final long uSecUptime = SystemClock.uptimeMillis() * 1000;
final long uSecRealtime = SystemClock.elapsedRealtime() * 1000;
final long batteryUptime = getBatteryUptimeLocked(uSecUptime);
@@ -5358,6 +5556,11 @@ public final class BatteryStatsImpl extends BatteryStats {
}
};
+ public void prepareForDumpLocked() {
+ // Need to retrieve current kernel wake lock stats before printing.
+ updateKernelWakelocksLocked();
+ }
+
public void dumpLocked(PrintWriter pw) {
if (DEBUG) {
Printer pr = new PrintWriterPrinter(pw);
diff --git a/core/java/com/android/internal/util/HierarchicalState.java b/core/java/com/android/internal/util/IState.java
index b37f46c1fe43..056f8e9b0424 100644
--- a/core/java/com/android/internal/util/HierarchicalState.java
+++ b/core/java/com/android/internal/util/IState.java
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2009 The Android Open Source Project
+ * 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.
@@ -21,21 +21,29 @@ import android.os.Message;
/**
* {@hide}
*
- * The class for implementing states in a HierarchicalStateMachine
+ * The interface for implementing states in a {@link StateMachine}
*/
-public class HierarchicalState {
+public interface IState {
/**
- * Constructor
+ * Returned by processMessage to indicate the the message was processed.
*/
- protected HierarchicalState() {
- }
+ static final boolean HANDLED = true;
+
+ /**
+ * Returned by processMessage to indicate the the message was NOT processed.
+ */
+ static final boolean NOT_HANDLED = false;
/**
* Called when a state is entered.
*/
- protected void enter() {
- }
+ void enter();
+
+ /**
+ * Called when a state is exited.
+ */
+ void exit();
/**
* Called when a message is to be processed by the
@@ -49,28 +57,15 @@ public class HierarchicalState {
* be processed until this routine returns.
*
* @param msg to process
- * @return true if processing has completed and false
- * if the parent state's processMessage should
- * be invoked.
- */
- protected boolean processMessage(Message msg) {
- return false;
- }
-
- /**
- * Called when a state is exited.
+ * @return HANDLED if processing has completed and NOT_HANDLED
+ * if the message wasn't processed.
*/
- protected void exit() {
- }
+ boolean processMessage(Message msg);
/**
- * @return name of state, but default returns the states
- * class name. An instance name would be better but requiring
- * it seems unnecessary.
+ * Name of State for debugging purposes.
+ *
+ * @return name of state.
*/
- public String getName() {
- String name = getClass().getName();
- int lastDollar = name.lastIndexOf('$');
- return name.substring(lastDollar + 1);
- }
+ String getName();
}
diff --git a/core/java/com/android/internal/util/State.java b/core/java/com/android/internal/util/State.java
new file mode 100644
index 000000000000..3eadff58bc09
--- /dev/null
+++ b/core/java/com/android/internal/util/State.java
@@ -0,0 +1,74 @@
+/**
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import android.os.Message;
+
+/**
+ * {@hide}
+ *
+ * The class for implementing states in a StateMachine
+ */
+public class State implements IState {
+
+ /**
+ * Constructor
+ */
+ protected State() {
+ }
+
+ /* (non-Javadoc)
+ * @see com.android.internal.util.IState#enter()
+ */
+ @Override
+ public void enter() {
+ }
+
+ /* (non-Javadoc)
+ * @see com.android.internal.util.IState#exit()
+ */
+ @Override
+ public void exit() {
+ }
+
+ /* (non-Javadoc)
+ * @see com.android.internal.util.IState#processMessage(android.os.Message)
+ */
+ @Override
+ public boolean processMessage(Message msg) {
+ return false;
+ }
+
+ /**
+ * Name of State for debugging purposes.
+ *
+ * This default implementation returns the class name, returning
+ * the instance name would better in cases where a State class
+ * is used for multiple states. But normally there is one class per
+ * state and the class name is sufficient and easy to get. You may
+ * want to provide a setName or some other mechanism for setting
+ * another name if the class name is not appropriate.
+ *
+ * @see com.android.internal.util.IState#processMessage(android.os.Message)
+ */
+ @Override
+ public String getName() {
+ String name = getClass().getName();
+ int lastDollar = name.lastIndexOf('$');
+ return name.substring(lastDollar + 1);
+ }
+}
diff --git a/core/java/com/android/internal/util/HierarchicalStateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index f6aa1847d6af..cbe72dd2ada4 100644
--- a/core/java/com/android/internal/util/HierarchicalStateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -29,10 +29,10 @@ import java.util.Vector;
/**
* {@hide}
*
- * <p>A hierarchical state machine is a state machine which processes messages
+ * <p>The state machine defined here is a hierarchical state machine which processes messages
* and can have states arranged hierarchically.</p>
*
- * <p>A state is a <code>HierarchicalState</code> object and must implement
+ * <p>A state is a <code>State</code> object and must implement
* <code>processMessage</code> and optionally <code>enter/exit/getName</code>.
* The enter/exit methods are equivalent to the construction and destruction
* in Object Oriented programming and are used to perform initialization and
@@ -76,7 +76,7 @@ import java.util.Vector;
* will exit the current state and its parent and then exit from the controlling thread
* and no further messages will be processed.</p>
*
- * <p>In addition to <code>processMessage</code> each <code>HierarchicalState</code> has
+ * <p>In addition to <code>processMessage</code> each <code>State</code> has
* an <code>enter</code> method and <code>exit</exit> method which may be overridden.</p>
*
* <p>Since the states are arranged in a hierarchy transitioning to a new state
@@ -122,11 +122,11 @@ import java.util.Vector;
* mS4.enter. The new list of active states is mP0, mP1, mS2 and mS4. So
* when the next message is received mS4.processMessage will be invoked.</p>
*
- * <p>Now for some concrete examples, here is the canonical HelloWorld as an HSM.
+ * <p>Now for some concrete examples, here is the canonical HelloWorld as a state machine.
* It responds with "Hello World" being printed to the log for every message.</p>
<code>
-class HelloWorld extends HierarchicalStateMachine {
- Hsm1(String name) {
+class HelloWorld extends StateMachine {
+ HelloWorld(String name) {
super(name);
addState(mState1);
setInitialState(mState1);
@@ -138,7 +138,7 @@ class HelloWorld extends HierarchicalStateMachine {
return hw;
}
- class State1 extends HierarchicalState {
+ class State1 extends State {
&#64;Override public boolean processMessage(Message message) {
Log.d(TAG, "Hello World");
return HANDLED;
@@ -221,9 +221,9 @@ state mP2 {
}
}
</code>
- * <p>The implementation is below and also in HierarchicalStateMachineTest:</p>
+ * <p>The implementation is below and also in StateMachineTest:</p>
<code>
-class Hsm1 extends HierarchicalStateMachine {
+class Hsm1 extends StateMachine {
private static final String TAG = "hsm1";
public static final int CMD_1 = 1;
@@ -255,7 +255,7 @@ class Hsm1 extends HierarchicalStateMachine {
Log.d(TAG, "ctor X");
}
- class P1 extends HierarchicalState {
+ class P1 extends State {
&#64;Override public void enter() {
Log.d(TAG, "mP1.enter");
}
@@ -282,7 +282,7 @@ class Hsm1 extends HierarchicalStateMachine {
}
}
- class S1 extends HierarchicalState {
+ class S1 extends State {
&#64;Override public void enter() {
Log.d(TAG, "mS1.enter");
}
@@ -302,7 +302,7 @@ class Hsm1 extends HierarchicalStateMachine {
}
}
- class S2 extends HierarchicalState {
+ class S2 extends State {
&#64;Override public void enter() {
Log.d(TAG, "mS2.enter");
}
@@ -330,7 +330,7 @@ class Hsm1 extends HierarchicalStateMachine {
}
}
- class P2 extends HierarchicalState {
+ class P2 extends State {
&#64;Override public void enter() {
Log.d(TAG, "mP2.enter");
sendMessage(obtainMessage(CMD_5));
@@ -409,16 +409,16 @@ D/hsm1 ( 1999): mP2.exit
D/hsm1 ( 1999): halting
</code>
*/
-public class HierarchicalStateMachine {
+public class StateMachine {
- private static final String TAG = "HierarchicalStateMachine";
+ private static final String TAG = "StateMachine";
private String mName;
/** Message.what value when quitting */
- public static final int HSM_QUIT_CMD = -1;
+ public static final int SM_QUIT_CMD = -1;
/** Message.what value when initializing */
- public static final int HSM_INIT_CMD = -1;
+ public static final int SM_INIT_CMD = -1;
/**
* Convenience constant that maybe returned by processMessage
@@ -441,8 +441,8 @@ public class HierarchicalStateMachine {
*/
public static class ProcessedMessageInfo {
private int what;
- private HierarchicalState state;
- private HierarchicalState orgState;
+ private State state;
+ private State orgState;
/**
* Constructor
@@ -451,7 +451,7 @@ public class HierarchicalStateMachine {
* @param orgState is the first state the received the message but
* did not processes the message.
*/
- ProcessedMessageInfo(Message message, HierarchicalState state, HierarchicalState orgState) {
+ ProcessedMessageInfo(Message message, State state, State orgState) {
update(message, state, orgState);
}
@@ -461,7 +461,7 @@ public class HierarchicalStateMachine {
* @param orgState is the first state the received the message but
* did not processes the message.
*/
- public void update(Message message, HierarchicalState state, HierarchicalState orgState) {
+ public void update(Message message, State state, State orgState) {
this.what = message.what;
this.state = state;
this.orgState = orgState;
@@ -477,14 +477,14 @@ public class HierarchicalStateMachine {
/**
* @return the state that handled this message
*/
- public HierarchicalState getState() {
+ public State getState() {
return state;
}
/**
* @return the original state that received the message.
*/
- public HierarchicalState getOriginalState() {
+ public State getOriginalState() {
return orgState;
}
@@ -593,7 +593,7 @@ public class HierarchicalStateMachine {
* @param orgState is the first state the received the message but
* did not processes the message.
*/
- void add(Message message, HierarchicalState state, HierarchicalState orgState) {
+ void add(Message message, State state, State orgState) {
mCount += 1;
if (mMessages.size() < mMaxSize) {
mMessages.add(new ProcessedMessageInfo(message, state, orgState));
@@ -608,7 +608,7 @@ public class HierarchicalStateMachine {
}
}
- private static class HsmHandler extends Handler {
+ private static class SmHandler extends Handler {
/** The debug flag */
private boolean mDbg = false;
@@ -643,8 +643,8 @@ public class HierarchicalStateMachine {
/** State used when state machine is quitting */
private QuittingState mQuittingState = new QuittingState();
- /** Reference to the HierarchicalStateMachine */
- private HierarchicalStateMachine mHsm;
+ /** Reference to the StateMachine */
+ private StateMachine mSm;
/**
* Information about a state.
@@ -652,7 +652,7 @@ public class HierarchicalStateMachine {
*/
private class StateInfo {
/** The state */
- HierarchicalState state;
+ State state;
/** The parent of this state, null if there is no parent */
StateInfo parentStateInfo;
@@ -672,14 +672,14 @@ public class HierarchicalStateMachine {
}
/** The map of all of the states in the state machine */
- private HashMap<HierarchicalState, StateInfo> mStateInfo =
- new HashMap<HierarchicalState, StateInfo>();
+ private HashMap<State, StateInfo> mStateInfo =
+ new HashMap<State, StateInfo>();
/** The initial state that will process the first message */
- private HierarchicalState mInitialState;
+ private State mInitialState;
/** The destination state when transitionTo has been invoked */
- private HierarchicalState mDestState;
+ private State mDestState;
/** The list of deferred messages */
private ArrayList<Message> mDeferredMessages = new ArrayList<Message>();
@@ -687,10 +687,10 @@ public class HierarchicalStateMachine {
/**
* State entered when transitionToHaltingState is called.
*/
- private class HaltingState extends HierarchicalState {
+ private class HaltingState extends State {
@Override
public boolean processMessage(Message msg) {
- mHsm.haltedProcessMessage(msg);
+ mSm.haltedProcessMessage(msg);
return true;
}
}
@@ -698,7 +698,7 @@ public class HierarchicalStateMachine {
/**
* State entered when a valid quit message is handled.
*/
- private class QuittingState extends HierarchicalState {
+ private class QuittingState extends State {
@Override
public boolean processMessage(Message msg) {
return NOT_HANDLED;
@@ -745,7 +745,7 @@ public class HierarchicalStateMachine {
* the appropriate states. We loop on this to allow
* enter and exit methods to use transitionTo.
*/
- HierarchicalState destState = null;
+ State destState = null;
while (mDestState != null) {
if (mDbg) Log.d(TAG, "handleMessage: new destination call exit");
@@ -785,11 +785,11 @@ public class HierarchicalStateMachine {
/**
* We are quitting so ignore all messages.
*/
- mHsm.quitting();
- if (mHsm.mHsmThread != null) {
+ mSm.quitting();
+ if (mSm.mSmThread != null) {
// If we made the thread then quit looper which stops the thread.
getLooper().quit();
- mHsm.mHsmThread = null;
+ mSm.mSmThread = null;
}
} else if (destState == mHaltingState) {
/**
@@ -797,7 +797,7 @@ public class HierarchicalStateMachine {
* state. All subsequent messages will be processed in
* in the halting state which invokes haltedProcessMessage(msg);
*/
- mHsm.halting();
+ mSm.halting();
}
}
}
@@ -833,7 +833,7 @@ public class HierarchicalStateMachine {
* starting at the first entry.
*/
mIsConstructionCompleted = true;
- mMsg = obtainMessage(HSM_INIT_CMD);
+ mMsg = obtainMessage(SM_INIT_CMD);
invokeEnterMethods(0);
/**
@@ -863,7 +863,7 @@ public class HierarchicalStateMachine {
/**
* No parents left so it's not handled
*/
- mHsm.unhandledMessage(msg);
+ mSm.unhandledMessage(msg);
if (isQuit(msg)) {
transitionTo(mQuittingState);
}
@@ -878,7 +878,7 @@ public class HierarchicalStateMachine {
* Record that we processed the message
*/
if (curStateInfo != null) {
- HierarchicalState orgState = mStateStack[mStateStackTopIndex].state;
+ State orgState = mStateStack[mStateStackTopIndex].state;
mProcessedMessages.add(msg, curStateInfo.state, orgState);
} else {
mProcessedMessages.add(msg, null, null);
@@ -892,7 +892,7 @@ public class HierarchicalStateMachine {
private final void invokeExitMethods(StateInfo commonStateInfo) {
while ((mStateStackTopIndex >= 0) &&
(mStateStack[mStateStackTopIndex] != commonStateInfo)) {
- HierarchicalState curState = mStateStack[mStateStackTopIndex].state;
+ State curState = mStateStack[mStateStackTopIndex].state;
if (mDbg) Log.d(TAG, "invokeExitMethods: " + curState.getName());
curState.exit();
mStateStack[mStateStackTopIndex].active = false;
@@ -934,7 +934,7 @@ public class HierarchicalStateMachine {
* reversing the order of the items on the temporary stack as
* they are moved.
*
- * @return index into mStateState where entering needs to start
+ * @return index into mStateStack where entering needs to start
*/
private final int moveTempStateStackToStateStack() {
int startingIndex = mStateStackTopIndex + 1;
@@ -967,7 +967,7 @@ public class HierarchicalStateMachine {
* @return StateInfo of the common ancestor for the destState and
* current state or null if there is no common parent.
*/
- private final StateInfo setupTempStateStackWithStatesToEnter(HierarchicalState destState) {
+ private final StateInfo setupTempStateStackWithStatesToEnter(State destState) {
/**
* Search up the parent list of the destination state for an active
* state. Use a do while() loop as the destState must always be entered
@@ -1019,7 +1019,7 @@ public class HierarchicalStateMachine {
/**
* @return current state
*/
- private final HierarchicalState getCurrentState() {
+ private final IState getCurrentState() {
return mStateStack[mStateStackTopIndex].state;
}
@@ -1032,7 +1032,7 @@ public class HierarchicalStateMachine {
* @param parent the parent of state
* @return stateInfo for this state
*/
- private final StateInfo addState(HierarchicalState state, HierarchicalState parent) {
+ private final StateInfo addState(State state, State parent) {
if (mDbg) {
Log.d(TAG, "addStateInternal: E state=" + state.getName()
+ ",parent=" + ((parent == null) ? "" : parent.getName()));
@@ -1067,29 +1067,29 @@ public class HierarchicalStateMachine {
* Constructor
*
* @param looper for dispatching messages
- * @param hsm the hierarchical state machine
+ * @param sm the hierarchical state machine
*/
- private HsmHandler(Looper looper, HierarchicalStateMachine hsm) {
+ private SmHandler(Looper looper, StateMachine sm) {
super(looper);
- mHsm = hsm;
+ mSm = sm;
addState(mHaltingState, null);
addState(mQuittingState, null);
}
- /** @see HierarchicalStateMachine#setInitialState(HierarchicalState) */
- private final void setInitialState(HierarchicalState initialState) {
+ /** @see StateMachine#setInitialState(State) */
+ private final void setInitialState(State initialState) {
if (mDbg) Log.d(TAG, "setInitialState: initialState" + initialState.getName());
mInitialState = initialState;
}
- /** @see HierarchicalStateMachine#transitionTo(HierarchicalState) */
- private final void transitionTo(HierarchicalState destState) {
- if (mDbg) Log.d(TAG, "StateMachine.transitionTo EX destState" + destState.getName());
- mDestState = destState;
+ /** @see StateMachine#transitionTo(IState) */
+ private final void transitionTo(IState destState) {
+ mDestState = (State) destState;
+ if (mDbg) Log.d(TAG, "StateMachine.transitionTo EX destState" + mDestState.getName());
}
- /** @see HierarchicalStateMachine#deferMessage(Message) */
+ /** @see StateMachine#deferMessage(Message) */
private final void deferMessage(Message msg) {
if (mDbg) Log.d(TAG, "deferMessage: msg=" + msg.what);
@@ -1100,51 +1100,51 @@ public class HierarchicalStateMachine {
mDeferredMessages.add(newMsg);
}
- /** @see HierarchicalStateMachine#deferMessage(Message) */
+ /** @see StateMachine#deferMessage(Message) */
private final void quit() {
if (mDbg) Log.d(TAG, "quit:");
- sendMessage(obtainMessage(HSM_QUIT_CMD, mQuitObj));
+ sendMessage(obtainMessage(SM_QUIT_CMD, mQuitObj));
}
- /** @see HierarchicalStateMachine#isQuit(Message) */
+ /** @see StateMachine#isQuit(Message) */
private final boolean isQuit(Message msg) {
- return (msg.what == HSM_QUIT_CMD) && (msg.obj == mQuitObj);
+ return (msg.what == SM_QUIT_CMD) && (msg.obj == mQuitObj);
}
- /** @see HierarchicalStateMachine#isDbg() */
+ /** @see StateMachine#isDbg() */
private final boolean isDbg() {
return mDbg;
}
- /** @see HierarchicalStateMachine#setDbg(boolean) */
+ /** @see StateMachine#setDbg(boolean) */
private final void setDbg(boolean dbg) {
mDbg = dbg;
}
- /** @see HierarchicalStateMachine#setProcessedMessagesSize(int) */
+ /** @see StateMachine#setProcessedMessagesSize(int) */
private final void setProcessedMessagesSize(int maxSize) {
mProcessedMessages.setSize(maxSize);
}
- /** @see HierarchicalStateMachine#getProcessedMessagesSize() */
+ /** @see StateMachine#getProcessedMessagesSize() */
private final int getProcessedMessagesSize() {
return mProcessedMessages.size();
}
- /** @see HierarchicalStateMachine#getProcessedMessagesCount() */
+ /** @see StateMachine#getProcessedMessagesCount() */
private final int getProcessedMessagesCount() {
return mProcessedMessages.count();
}
- /** @see HierarchicalStateMachine#getProcessedMessageInfo(int) */
+ /** @see StateMachine#getProcessedMessageInfo(int) */
private final ProcessedMessageInfo getProcessedMessageInfo(int index) {
return mProcessedMessages.get(index);
}
}
- private HsmHandler mHsmHandler;
- private HandlerThread mHsmThread;
+ private SmHandler mSmHandler;
+ private HandlerThread mSmThread;
/**
* Initialize.
@@ -1154,28 +1154,28 @@ public class HierarchicalStateMachine {
*/
private void initStateMachine(String name, Looper looper) {
mName = name;
- mHsmHandler = new HsmHandler(looper, this);
+ mSmHandler = new SmHandler(looper, this);
}
/**
- * Constructor creates an HSM with its own thread.
+ * Constructor creates a StateMachine with its own thread.
*
* @param name of the state machine
*/
- protected HierarchicalStateMachine(String name) {
- mHsmThread = new HandlerThread(name);
- mHsmThread.start();
- Looper looper = mHsmThread.getLooper();
+ protected StateMachine(String name) {
+ mSmThread = new HandlerThread(name);
+ mSmThread.start();
+ Looper looper = mSmThread.getLooper();
initStateMachine(name, looper);
}
/**
- * Constructor creates an HSMStateMachine using the looper.
+ * Constructor creates an StateMachine using the looper.
*
* @param name of the state machine
*/
- protected HierarchicalStateMachine(String name, Looper looper) {
+ protected StateMachine(String name, Looper looper) {
initStateMachine(name, looper);
}
@@ -1184,30 +1184,30 @@ public class HierarchicalStateMachine {
* @param state the state to add
* @param parent the parent of state
*/
- protected final void addState(HierarchicalState state, HierarchicalState parent) {
- mHsmHandler.addState(state, parent);
+ protected final void addState(State state, State parent) {
+ mSmHandler.addState(state, parent);
}
/**
* @return current message
*/
protected final Message getCurrentMessage() {
- return mHsmHandler.getCurrentMessage();
+ return mSmHandler.getCurrentMessage();
}
/**
* @return current state
*/
- protected final HierarchicalState getCurrentState() {
- return mHsmHandler.getCurrentState();
+ protected final IState getCurrentState() {
+ return mSmHandler.getCurrentState();
}
/**
* Add a new state to the state machine, parent will be null
* @param state to add
*/
- protected final void addState(HierarchicalState state) {
- mHsmHandler.addState(state, null);
+ protected final void addState(State state) {
+ mSmHandler.addState(state, null);
}
/**
@@ -1216,8 +1216,8 @@ public class HierarchicalStateMachine {
*
* @param initialState is the state which will receive the first message.
*/
- protected final void setInitialState(HierarchicalState initialState) {
- mHsmHandler.setInitialState(initialState);
+ protected final void setInitialState(State initialState) {
+ mSmHandler.setInitialState(initialState);
}
/**
@@ -1228,8 +1228,8 @@ public class HierarchicalStateMachine {
*
* @param destState will be the state that receives the next message.
*/
- protected final void transitionTo(HierarchicalState destState) {
- mHsmHandler.transitionTo(destState);
+ protected final void transitionTo(IState destState) {
+ mSmHandler.transitionTo(destState);
}
/**
@@ -1240,7 +1240,7 @@ public class HierarchicalStateMachine {
* will be called.
*/
protected final void transitionToHaltingState() {
- mHsmHandler.transitionTo(mHsmHandler.mHaltingState);
+ mSmHandler.transitionTo(mSmHandler.mHaltingState);
}
/**
@@ -1253,7 +1253,7 @@ public class HierarchicalStateMachine {
* @param msg is deferred until the next transition.
*/
protected final void deferMessage(Message msg) {
- mHsmHandler.deferMessage(msg);
+ mSmHandler.deferMessage(msg);
}
@@ -1263,7 +1263,7 @@ public class HierarchicalStateMachine {
* @param msg that couldn't be handled.
*/
protected void unhandledMessage(Message msg) {
- if (mHsmHandler.mDbg) Log.e(TAG, mName + " - unhandledMessage: msg.what=" + msg.what);
+ if (mSmHandler.mDbg) Log.e(TAG, mName + " - unhandledMessage: msg.what=" + msg.what);
}
/**
@@ -1276,15 +1276,15 @@ public class HierarchicalStateMachine {
/**
* This will be called once after handling a message that called
* transitionToHalting. All subsequent messages will invoke
- * {@link HierarchicalStateMachine#haltedProcessMessage(Message)}
+ * {@link StateMachine#haltedProcessMessage(Message)}
*/
protected void halting() {
}
/**
* This will be called once after a quit message that was NOT handled by
- * the derived HSM. The HSM will stop and any subsequent messages will be
- * ignored. In addition, if this HSM created the thread, the thread will
+ * the derived StateMachine. The StateMachine will stop and any subsequent messages will be
+ * ignored. In addition, if this StateMachine created the thread, the thread will
* be stopped after this method returns.
*/
protected void quitting() {
@@ -1303,35 +1303,35 @@ public class HierarchicalStateMachine {
* @param maxSize number of messages to maintain at anyone time.
*/
public final void setProcessedMessagesSize(int maxSize) {
- mHsmHandler.setProcessedMessagesSize(maxSize);
+ mSmHandler.setProcessedMessagesSize(maxSize);
}
/**
* @return number of messages processed
*/
public final int getProcessedMessagesSize() {
- return mHsmHandler.getProcessedMessagesSize();
+ return mSmHandler.getProcessedMessagesSize();
}
/**
* @return the total number of messages processed
*/
public final int getProcessedMessagesCount() {
- return mHsmHandler.getProcessedMessagesCount();
+ return mSmHandler.getProcessedMessagesCount();
}
/**
* @return a processed message information
*/
public final ProcessedMessageInfo getProcessedMessageInfo(int index) {
- return mHsmHandler.getProcessedMessageInfo(index);
+ return mSmHandler.getProcessedMessageInfo(index);
}
/**
* @return Handler
*/
public final Handler getHandler() {
- return mHsmHandler;
+ return mSmHandler;
}
/**
@@ -1341,7 +1341,7 @@ public class HierarchicalStateMachine {
*/
public final Message obtainMessage()
{
- return Message.obtain(mHsmHandler);
+ return Message.obtain(mSmHandler);
}
/**
@@ -1351,7 +1351,7 @@ public class HierarchicalStateMachine {
* @return message
*/
public final Message obtainMessage(int what) {
- return Message.obtain(mHsmHandler, what);
+ return Message.obtain(mSmHandler, what);
}
/**
@@ -1364,7 +1364,7 @@ public class HierarchicalStateMachine {
*/
public final Message obtainMessage(int what, Object obj)
{
- return Message.obtain(mHsmHandler, what, obj);
+ return Message.obtain(mSmHandler, what, obj);
}
/**
@@ -1378,7 +1378,7 @@ public class HierarchicalStateMachine {
*/
public final Message obtainMessage(int what, int arg1, int arg2)
{
- return Message.obtain(mHsmHandler, what, arg1, arg2);
+ return Message.obtain(mSmHandler, what, arg1, arg2);
}
/**
@@ -1393,107 +1393,107 @@ public class HierarchicalStateMachine {
*/
public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
{
- return Message.obtain(mHsmHandler, what, arg1, arg2, obj);
+ return Message.obtain(mSmHandler, what, arg1, arg2, obj);
}
/**
* Enqueue a message to this state machine.
*/
public final void sendMessage(int what) {
- mHsmHandler.sendMessage(obtainMessage(what));
+ mSmHandler.sendMessage(obtainMessage(what));
}
/**
* Enqueue a message to this state machine.
*/
public final void sendMessage(int what, Object obj) {
- mHsmHandler.sendMessage(obtainMessage(what,obj));
+ mSmHandler.sendMessage(obtainMessage(what,obj));
}
/**
* Enqueue a message to this state machine.
*/
public final void sendMessage(Message msg) {
- mHsmHandler.sendMessage(msg);
+ mSmHandler.sendMessage(msg);
}
/**
* Enqueue a message to this state machine after a delay.
*/
public final void sendMessageDelayed(int what, long delayMillis) {
- mHsmHandler.sendMessageDelayed(obtainMessage(what), delayMillis);
+ mSmHandler.sendMessageDelayed(obtainMessage(what), delayMillis);
}
/**
* Enqueue a message to this state machine after a delay.
*/
public final void sendMessageDelayed(int what, Object obj, long delayMillis) {
- mHsmHandler.sendMessageDelayed(obtainMessage(what, obj), delayMillis);
+ mSmHandler.sendMessageDelayed(obtainMessage(what, obj), delayMillis);
}
/**
* Enqueue a message to this state machine after a delay.
*/
public final void sendMessageDelayed(Message msg, long delayMillis) {
- mHsmHandler.sendMessageDelayed(msg, delayMillis);
+ mSmHandler.sendMessageDelayed(msg, delayMillis);
}
/**
* Enqueue a message to the front of the queue for this state machine.
- * Protected, may only be called by instances of HierarchicalStateMachine.
+ * Protected, may only be called by instances of StateMachine.
*/
protected final void sendMessageAtFrontOfQueue(int what, Object obj) {
- mHsmHandler.sendMessageAtFrontOfQueue(obtainMessage(what, obj));
+ mSmHandler.sendMessageAtFrontOfQueue(obtainMessage(what, obj));
}
/**
* Enqueue a message to the front of the queue for this state machine.
- * Protected, may only be called by instances of HierarchicalStateMachine.
+ * Protected, may only be called by instances of StateMachine.
*/
protected final void sendMessageAtFrontOfQueue(int what) {
- mHsmHandler.sendMessageAtFrontOfQueue(obtainMessage(what));
+ mSmHandler.sendMessageAtFrontOfQueue(obtainMessage(what));
}
/**
* Enqueue a message to the front of the queue for this state machine.
- * Protected, may only be called by instances of HierarchicalStateMachine.
+ * Protected, may only be called by instances of StateMachine.
*/
protected final void sendMessageAtFrontOfQueue(Message msg) {
- mHsmHandler.sendMessageAtFrontOfQueue(msg);
+ mSmHandler.sendMessageAtFrontOfQueue(msg);
}
/**
* Removes a message from the message queue.
- * Protected, may only be called by instances of HierarchicalStateMachine.
+ * Protected, may only be called by instances of StateMachine.
*/
protected final void removeMessages(int what) {
- mHsmHandler.removeMessages(what);
+ mSmHandler.removeMessages(what);
}
/**
* Conditionally quit the looper and stop execution.
*
- * This sends the HSM_QUIT_MSG to the state machine and
+ * This sends the SM_QUIT_MSG to the state machine and
* if not handled by any state's processMessage then the
* state machine will be stopped and no further messages
* will be processed.
*/
public final void quit() {
- mHsmHandler.quit();
+ mSmHandler.quit();
}
/**
* @return ture if msg is quit
*/
protected final boolean isQuit(Message msg) {
- return mHsmHandler.isQuit(msg);
+ return mSmHandler.isQuit(msg);
}
/**
* @return if debugging is enabled
*/
public boolean isDbg() {
- return mHsmHandler.isDbg();
+ return mSmHandler.isDbg();
}
/**
@@ -1502,7 +1502,7 @@ public class HierarchicalStateMachine {
* @param dbg is true to enable debugging.
*/
public void setDbg(boolean dbg) {
- mHsmHandler.setDbg(dbg);
+ mSmHandler.setDbg(dbg);
}
/**
@@ -1510,6 +1510,6 @@ public class HierarchicalStateMachine {
*/
public void start() {
/** Send the complete construction message */
- mHsmHandler.completeConstruction();
+ mSmHandler.completeConstruction();
}
}
diff --git a/core/java/com/android/internal/view/IInputMethodManager.aidl b/core/java/com/android/internal/view/IInputMethodManager.aidl
index 611d9875d2cf..4ffa4e1dfbec 100644
--- a/core/java/com/android/internal/view/IInputMethodManager.aidl
+++ b/core/java/com/android/internal/view/IInputMethodManager.aidl
@@ -33,6 +33,7 @@ interface IInputMethodManager {
List<InputMethodInfo> getEnabledInputMethodList();
List<InputMethodSubtype> getEnabledInputMethodSubtypeList(in InputMethodInfo imi,
boolean allowsImplicitlySelectedSubtypes);
+ InputMethodSubtype getLastInputMethodSubtype();
// TODO: We should change the return type from List to List<Parcelable>
// Currently there is a bug that aidl doesn't accept List<Parcelable>
List getShortcutInputMethodsAndSubtypes();
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f29d83e493cd..b628b9dc8caf 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -1,19 +1,18 @@
-/* //device/libs/android_runtime/AndroidRuntime.cpp
-**
-** Copyright 2006, 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.
-*/
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
#define LOG_TAG "AndroidRuntime"
//#define LOG_NDEBUG 0
@@ -212,7 +211,7 @@ static jint com_android_internal_os_RuntimeInit_getQwertyKeyboard(JNIEnv* env, j
if (value != NULL && strcmp(value, "true") == 0) {
return 1;
}
-
+
return 0;
}
@@ -227,7 +226,7 @@ static JNINativeMethod gMethods[] = {
{ "isComputerOn", "()I",
(void*) com_android_internal_os_RuntimeInit_isComputerOn },
{ "turnComputerOn", "()V",
- (void*) com_android_internal_os_RuntimeInit_turnComputerOn },
+ (void*) com_android_internal_os_RuntimeInit_turnComputerOn },
{ "getQwertyKeyboard", "()I",
(void*) com_android_internal_os_RuntimeInit_getQwertyKeyboard },
};
@@ -278,51 +277,16 @@ AndroidRuntime::~AndroidRuntime()
return jniRegisterNativeMethods(env, className, gMethods, numMethods);
}
-/*
- * Call a static Java Programming Language function that takes no arguments and returns void.
- */
-status_t AndroidRuntime::callStatic(const char* className, const char* methodName)
+status_t AndroidRuntime::callMain(const char* className,
+ jclass clazz, int argc, const char* const argv[])
{
JNIEnv* env;
- jclass clazz;
- jmethodID methodId;
-
- env = getJNIEnv();
- if (env == NULL)
- return UNKNOWN_ERROR;
-
- clazz = findClass(env, className);
- if (clazz == NULL) {
- LOGE("ERROR: could not find class '%s'\n", className);
- return UNKNOWN_ERROR;
- }
- methodId = env->GetStaticMethodID(clazz, methodName, "()V");
- if (methodId == NULL) {
- LOGE("ERROR: could not find method %s.%s\n", className, methodName);
- return UNKNOWN_ERROR;
- }
-
- env->CallStaticVoidMethod(clazz, methodId);
-
- return NO_ERROR;
-}
-
-status_t AndroidRuntime::callMain(
- const char* className, int argc, const char* const argv[])
-{
- JNIEnv* env;
- jclass clazz;
jmethodID methodId;
LOGD("Calling main entry %s", className);
env = getJNIEnv();
- if (env == NULL)
- return UNKNOWN_ERROR;
-
- clazz = findClass(env, className);
- if (clazz == NULL) {
- LOGE("ERROR: could not find class '%s'\n", className);
+ if (clazz == NULL || env == NULL) {
return UNKNOWN_ERROR;
}
@@ -352,70 +316,6 @@ status_t AndroidRuntime::callMain(
}
/*
- * Find the named class.
- */
-jclass AndroidRuntime::findClass(JNIEnv* env, const char* className)
-{
- if (env->ExceptionCheck()) {
- LOGE("ERROR: exception pending on entry to findClass()");
- return NULL;
- }
-
- /*
- * This is a little awkward because the JNI FindClass call uses the
- * class loader associated with the native method we're executing in.
- * Because this native method is part of a "boot" class, JNI doesn't
- * look for the class in CLASSPATH, which unfortunately is a likely
- * location for it. (Had we issued the FindClass call before calling
- * into the VM -- at which point there isn't a native method frame on
- * the stack -- the VM would have checked CLASSPATH. We have to do
- * this because we call into Java Programming Language code and
- * bounce back out.)
- *
- * JNI lacks a "find class in a specific class loader" operation, so we
- * have to do things the hard way.
- */
- jclass cls = NULL;
-
- jclass javaLangClassLoader;
- jmethodID getSystemClassLoader, loadClass;
- jobject systemClassLoader;
- jstring strClassName;
-
- /* find the "system" class loader; none of this is expected to fail */
- javaLangClassLoader = env->FindClass("java/lang/ClassLoader");
- assert(javaLangClassLoader != NULL);
- getSystemClassLoader = env->GetStaticMethodID(javaLangClassLoader,
- "getSystemClassLoader", "()Ljava/lang/ClassLoader;");
- loadClass = env->GetMethodID(javaLangClassLoader,
- "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
- assert(getSystemClassLoader != NULL && loadClass != NULL);
- systemClassLoader = env->CallStaticObjectMethod(javaLangClassLoader,
- getSystemClassLoader);
- assert(systemClassLoader != NULL);
-
- /* create an object for the class name string; alloc could fail */
- strClassName = env->NewStringUTF(className);
- if (env->ExceptionCheck()) {
- LOGE("ERROR: unable to convert '%s' to string", className);
- return NULL;
- }
- LOGV("system class loader is %p, loading %p (%s)",
- systemClassLoader, strClassName, className);
-
- /* try to find the named class */
- cls = (jclass) env->CallObjectMethod(systemClassLoader, loadClass,
- strClassName);
- if (env->ExceptionCheck()) {
- LOGE("ERROR: unable to load class '%s' from %p",
- className, systemClassLoader);
- return NULL;
- }
-
- return cls;
-}
-
-/*
* The VM calls this through the "exit" hook.
*/
static void runtime_exit(int code)
@@ -457,7 +357,7 @@ static bool runtime_isSensitiveThread() {
int AndroidRuntime::addVmArguments(int argc, const char* const argv[])
{
int i;
-
+
for (i = 0; i<argc; i++) {
if (argv[i][0] != '-') {
return i;
@@ -890,6 +790,17 @@ bail:
return result;
}
+char* AndroidRuntime::toSlashClassName(const char* className)
+{
+ char* result = strdup(className);
+ for (char* cp = result; *cp != '\0'; cp++) {
+ if (*cp == '.') {
+ *cp = '/';
+ }
+ }
+ return result;
+}
+
/*
* Start the Android runtime. This involves starting the virtual machine
* and calling the "static void main(String[] args)" method in the class
@@ -900,20 +811,16 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
LOGD("\n>>>>>> AndroidRuntime START %s <<<<<<\n",
className != NULL ? className : "(unknown)");
- char* slashClassName = NULL;
- char* cp;
- JNIEnv* env;
-
blockSigpipe();
- /*
- * 'startSystemServer == true' means runtime is obsolete and not run from
+ /*
+ * 'startSystemServer == true' means runtime is obsolete and not run from
* init.rc anymore, so we print out the boot start event here.
*/
if (startSystemServer) {
/* track our progress through the boot sequence */
const int LOG_BOOT_PROGRESS_START = 3000;
- LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,
+ LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,
ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
}
@@ -922,7 +829,7 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
rootDir = "/system";
if (!hasDir("/system")) {
LOG_FATAL("No root directory specified, and /android does not exist.");
- goto bail;
+ return;
}
setenv("ANDROID_ROOT", rootDir, 1);
}
@@ -931,15 +838,18 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
//LOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);
/* start the virtual machine */
- if (startVm(&mJavaVM, &env) != 0)
- goto bail;
+ JNIEnv* env;
+ if (startVm(&mJavaVM, &env) != 0) {
+ return;
+ }
+ onVmCreated(env);
/*
* Register android functions.
*/
if (startReg(env) < 0) {
LOGE("Unable to register all android natives\n");
- goto bail;
+ return;
}
/*
@@ -959,7 +869,7 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
classNameStr = env->NewStringUTF(className);
assert(classNameStr != NULL);
env->SetObjectArrayElement(strArray, 0, classNameStr);
- startSystemServerStr = env->NewStringUTF(startSystemServer ?
+ startSystemServerStr = env->NewStringUTF(startSystemServer ?
"true" : "false");
env->SetObjectArrayElement(strArray, 1, startSystemServerStr);
@@ -967,20 +877,13 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
* Start VM. This thread becomes the main thread of the VM, and will
* not return until the VM exits.
*/
- jclass startClass;
- jmethodID startMeth;
-
- slashClassName = strdup(className);
- for (cp = slashClassName; *cp != '\0'; cp++)
- if (*cp == '.')
- *cp = '/';
-
- startClass = env->FindClass(slashClassName);
+ char* slashClassName = toSlashClassName(className);
+ jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
LOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
- startMeth = env->GetStaticMethodID(startClass, "main",
+ jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
LOGE("JavaVM unable to find main() in '%s'\n", className);
@@ -994,15 +897,13 @@ void AndroidRuntime::start(const char* className, const bool startSystemServer)
#endif
}
}
+ free(slashClassName);
LOGD("Shutting down VM\n");
if (mJavaVM->DetachCurrentThread() != JNI_OK)
LOGW("Warning: unable to detach main thread\n");
if (mJavaVM->DestroyJavaVM() != 0)
LOGW("Warning: VM did not shut down cleanly\n");
-
-bail:
- free(slashClassName);
}
void AndroidRuntime::start()
@@ -1017,6 +918,11 @@ void AndroidRuntime::onExit(int code)
exit(code);
}
+void AndroidRuntime::onVmCreated(JNIEnv* env)
+{
+ // If AndroidRuntime had anything to do here, we'd have done it in 'start'.
+}
+
/*
* Get the JNIEnv pointer for this thread.
*
@@ -1111,7 +1017,7 @@ static int javaDetachThread(void)
* into the VM before it really starts executing.
*/
/*static*/ int AndroidRuntime::javaCreateThreadEtc(
- android_thread_func_t entryFunction,
+ android_thread_func_t entryFunction,
void* userData,
const char* threadName,
int32_t threadPriority,
@@ -1299,7 +1205,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_backup_BackupDataOutput),
REG_JNI(register_android_backup_FileBackupHelperBase),
REG_JNI(register_android_backup_BackupHelperDispatcher),
-
+
REG_JNI(register_android_app_ActivityThread),
REG_JNI(register_android_app_NativeActivity),
REG_JNI(register_android_view_InputChannel),
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 05a46a8ce439..1b22e2d02563 100644
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -655,7 +655,6 @@ static JNINativeMethod gBitmapMethods[] = {
#define kClassPathName "android/graphics/Bitmap"
-int register_android_graphics_Bitmap(JNIEnv* env);
int register_android_graphics_Bitmap(JNIEnv* env)
{
return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 1034fbde5052..258ffa5ae6e1 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -12,6 +12,7 @@
#include "CreateJavaOutputStreamAdaptor.h"
#include "AutoDecodeCancel.h"
#include "Utils.h"
+#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
#include <utils/Asset.h>
@@ -20,7 +21,6 @@
#include <sys/mman.h>
#include <sys/stat.h>
-jclass gOptions_class;
jfieldID gOptions_justBoundsFieldID;
jfieldID gOptions_sampleSizeFieldID;
jfieldID gOptions_configFieldID;
@@ -34,12 +34,8 @@ jfieldID gOptions_heightFieldID;
jfieldID gOptions_mimeFieldID;
jfieldID gOptions_mCancelID;
jfieldID gOptions_bitmapFieldID;
-jclass gBitmap_class;
jfieldID gBitmap_nativeBitmapFieldID;
-static jclass gFileDescriptor_class;
-static jfieldID gFileDescriptor_descriptor;
-
#if 0
#define TRACE_BITMAP(code) code
#else
@@ -66,7 +62,7 @@ jstring getMimeTypeString(JNIEnv* env, SkImageDecoder::Format format) {
{ SkImageDecoder::kPNG_Format, "image/png" },
{ SkImageDecoder::kWBMP_Format, "image/vnd.wap.wbmp" }
};
-
+
const char* cstr = NULL;
for (size_t i = 0; i < SK_ARRAY_COUNT(gMimeTypes); i++) {
if (gMimeTypes[i].fFormat == format) {
@@ -127,7 +123,7 @@ static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding,
(allowPurgeable && optionsPurgeable(env, options));
bool preferQualityOverSpeed = false;
jobject javaBitmap = NULL;
-
+
if (NULL != options) {
sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
if (optionsJustBounds(env, options)) {
@@ -137,7 +133,7 @@ static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding,
env->SetIntField(options, gOptions_widthFieldID, -1);
env->SetIntField(options, gOptions_heightFieldID, -1);
env->SetObjectField(options, gOptions_mimeFieldID, 0);
-
+
jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
prefConfig = GraphicsJNI::getNativeBitmapConfig(env, jconfig);
isMutable = env->GetBooleanField(options, gOptions_mutableFieldID);
@@ -151,7 +147,7 @@ static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding,
if (NULL == decoder) {
return nullObjectReturn("SkImageDecoder::Factory returned null");
}
-
+
decoder->setSampleSize(sampleSize);
decoder->setDitherImage(doDither);
decoder->setPreferQualityOverSpeed(preferQualityOverSpeed);
@@ -298,8 +294,7 @@ static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz,
jobject bitmapFactoryOptions) {
NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
- jint descriptor = env->GetIntField(fileDescriptor,
- gFileDescriptor_descriptor);
+ jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
bool isPurgeable = optionsPurgeable(env, bitmapFactoryOptions);
bool isShareable = optionsShareable(env, bitmapFactoryOptions);
@@ -424,7 +419,7 @@ static jbyteArray nativeScaleNinePatch(JNIEnv* env, jobject, jbyteArray chunkObj
}
for (int i = 0; i < chunk->numYDivs; i++) {
- chunk->yDivs[i] = int(chunk->yDivs[i] * scale + 0.5f);
+ chunk->yDivs[i] = int(chunk->yDivs[i] * scale + 0.5f);
if (i > 0 && chunk->yDivs[i] == chunk->yDivs[i - 1]) {
chunk->yDivs[i]++;
}
@@ -460,7 +455,7 @@ static void nativeSetDefaultConfig(JNIEnv* env, jobject, int nativeConfig) {
}
static jboolean nativeIsSeekable(JNIEnv* env, jobject, jobject fileDescriptor) {
- jint descriptor = env->GetIntField(fileDescriptor, gFileDescriptor_descriptor);
+ jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
return ::lseek64(descriptor, 0, SEEK_CUR) != -1 ? JNI_TRUE : JNI_FALSE;
}
@@ -504,12 +499,6 @@ static JNINativeMethod gOptionsMethods[] = {
{ "requestCancel", "()V", (void*)nativeRequestCancel }
};
-static jclass make_globalref(JNIEnv* env, const char classname[]) {
- jclass c = env->FindClass(classname);
- SkASSERT(c);
- return (jclass)env->NewGlobalRef(c);
-}
-
static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
const char fieldname[], const char type[]) {
jfieldID id = env->GetFieldID(clazz, fieldname, type);
@@ -517,35 +506,29 @@ static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
return id;
}
-#define kClassPathName "android/graphics/BitmapFactory"
-
-#define RETURN_ERR_IF_NULL(value) \
- do { if (!(value)) { assert(0); return -1; } } while (false)
-
-int register_android_graphics_BitmapFactory(JNIEnv* env);
int register_android_graphics_BitmapFactory(JNIEnv* env) {
- gOptions_class = make_globalref(env, "android/graphics/BitmapFactory$Options");
- gOptions_bitmapFieldID = getFieldIDCheck(env, gOptions_class, "inBitmap",
+ jclass options_class = env->FindClass("android/graphics/BitmapFactory$Options");
+ SkASSERT(options_class);
+ gOptions_bitmapFieldID = getFieldIDCheck(env, options_class, "inBitmap",
"Landroid/graphics/Bitmap;");
- gOptions_justBoundsFieldID = getFieldIDCheck(env, gOptions_class, "inJustDecodeBounds", "Z");
- gOptions_sampleSizeFieldID = getFieldIDCheck(env, gOptions_class, "inSampleSize", "I");
- gOptions_configFieldID = getFieldIDCheck(env, gOptions_class, "inPreferredConfig",
+ gOptions_justBoundsFieldID = getFieldIDCheck(env, options_class, "inJustDecodeBounds", "Z");
+ gOptions_sampleSizeFieldID = getFieldIDCheck(env, options_class, "inSampleSize", "I");
+ gOptions_configFieldID = getFieldIDCheck(env, options_class, "inPreferredConfig",
"Landroid/graphics/Bitmap$Config;");
- gOptions_mutableFieldID = getFieldIDCheck(env, gOptions_class, "inMutable", "Z");
- gOptions_ditherFieldID = getFieldIDCheck(env, gOptions_class, "inDither", "Z");
- gOptions_purgeableFieldID = getFieldIDCheck(env, gOptions_class, "inPurgeable", "Z");
- gOptions_shareableFieldID = getFieldIDCheck(env, gOptions_class, "inInputShareable", "Z");
- gOptions_preferQualityOverSpeedFieldID = getFieldIDCheck(env, gOptions_class,
+ gOptions_mutableFieldID = getFieldIDCheck(env, options_class, "inMutable", "Z");
+ gOptions_ditherFieldID = getFieldIDCheck(env, options_class, "inDither", "Z");
+ gOptions_purgeableFieldID = getFieldIDCheck(env, options_class, "inPurgeable", "Z");
+ gOptions_shareableFieldID = getFieldIDCheck(env, options_class, "inInputShareable", "Z");
+ gOptions_preferQualityOverSpeedFieldID = getFieldIDCheck(env, options_class,
"inPreferQualityOverSpeed", "Z");
- gOptions_widthFieldID = getFieldIDCheck(env, gOptions_class, "outWidth", "I");
- gOptions_heightFieldID = getFieldIDCheck(env, gOptions_class, "outHeight", "I");
- gOptions_mimeFieldID = getFieldIDCheck(env, gOptions_class, "outMimeType", "Ljava/lang/String;");
- gOptions_mCancelID = getFieldIDCheck(env, gOptions_class, "mCancel", "Z");
+ gOptions_widthFieldID = getFieldIDCheck(env, options_class, "outWidth", "I");
+ gOptions_heightFieldID = getFieldIDCheck(env, options_class, "outHeight", "I");
+ gOptions_mimeFieldID = getFieldIDCheck(env, options_class, "outMimeType", "Ljava/lang/String;");
+ gOptions_mCancelID = getFieldIDCheck(env, options_class, "mCancel", "Z");
- gBitmap_class = make_globalref(env, "android/graphics/Bitmap");
- gBitmap_nativeBitmapFieldID = getFieldIDCheck(env, gBitmap_class, "mNativeBitmap", "I");
- gFileDescriptor_class = make_globalref(env, "java/io/FileDescriptor");
- gFileDescriptor_descriptor = getFieldIDCheck(env, gFileDescriptor_class, "descriptor", "I");
+ jclass bitmap_class = env->FindClass("android/graphics/Bitmap");
+ SkASSERT(bitmap_class);
+ gBitmap_nativeBitmapFieldID = getFieldIDCheck(env, bitmap_class, "mNativeBitmap", "I");
int ret = AndroidRuntime::registerNativeMethods(env,
"android/graphics/BitmapFactory$Options",
@@ -554,6 +537,6 @@ int register_android_graphics_BitmapFactory(JNIEnv* env) {
if (ret) {
return ret;
}
- return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
+ return android::AndroidRuntime::registerNativeMethods(env, "android/graphics/BitmapFactory",
gMethods, SK_ARRAY_COUNT(gMethods));
}
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
index ee3e2094267f..d43792939e72 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -28,6 +28,7 @@
#include "SkBitmapRegionDecoder.h"
#include "CreateJavaOutputStreamAdaptor.h"
#include "Utils.h"
+#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
#include "android_util_Binder.h"
@@ -39,9 +40,6 @@
#include <utils/Asset.h>
#include <sys/stat.h>
-static jclass gFileDescriptor_class;
-static jfieldID gFileDescriptor_descriptor;
-
#if 0
#define TRACE_BITMAP(code) code
#else
@@ -111,8 +109,7 @@ static jobject nativeNewInstanceFromFileDescriptor(JNIEnv* env, jobject clazz,
jobject fileDescriptor, jboolean isShareable) {
NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
- jint descriptor = env->GetIntField(fileDescriptor,
- gFileDescriptor_descriptor);
+ jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
SkStream *stream = NULL;
struct stat fdStat;
int newFD;
@@ -300,25 +297,8 @@ static JNINativeMethod gBitmapRegionDecoderMethods[] = {
#define kClassPathName "android/graphics/BitmapRegionDecoder"
-static jclass make_globalref(JNIEnv* env, const char classname[]) {
- jclass c = env->FindClass(classname);
- SkASSERT(c);
- return (jclass)env->NewGlobalRef(c);
-}
-
-static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
- const char fieldname[], const char type[]) {
- jfieldID id = env->GetFieldID(clazz, fieldname, type);
- SkASSERT(id);
- return id;
-}
-
-int register_android_graphics_BitmapRegionDecoder(JNIEnv* env);
int register_android_graphics_BitmapRegionDecoder(JNIEnv* env)
{
-
- gFileDescriptor_class = make_globalref(env, "java/io/FileDescriptor");
- gFileDescriptor_descriptor = getFieldIDCheck(env, gFileDescriptor_class, "descriptor", "I");
return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
gBitmapRegionDecoderMethods, SK_ARRAY_COUNT(gBitmapRegionDecoderMethods));
}
diff --git a/core/jni/android/graphics/Camera.cpp b/core/jni/android/graphics/Camera.cpp
index 0d715fd92045..76d415a19560 100644
--- a/core/jni/android/graphics/Camera.cpp
+++ b/core/jni/android/graphics/Camera.cpp
@@ -98,7 +98,6 @@ static JNINativeMethod gCameraMethods[] = {
{ "dotWithNormal", "(FFF)F", (void*)Camera_dotWithNormal }
};
-int register_android_graphics_Camera(JNIEnv* env);
int register_android_graphics_Camera(JNIEnv* env) {
jclass clazz = env->FindClass("android/graphics/Camera");
if (clazz == 0) {
@@ -113,4 +112,3 @@ int register_android_graphics_Camera(JNIEnv* env) {
gCameraMethods,
SK_ARRAY_COUNT(gCameraMethods));
}
-
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index b2caa98a98cf..207c72fa173e 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -756,26 +756,36 @@ public:
env->ReleaseStringChars(text, textArray);
}
+ static void logGlyphs(sp<TextLayoutCacheValue> value) {
+ LOGD("drawTextWithGlyphs -- got glyphs - count=%d", value->getGlyphsCount());
+ for (size_t i = 0; i < value->getGlyphsCount(); i++) {
+ LOGD(" glyphs[%d]=%d", i, value->getGlyphs()[i]);
+ }
+ }
+
+ static void drawTextWithGlyphs(SkCanvas* canvas, const jchar* textArray,
+ int start, int end,
+ jfloat x, jfloat y, int flags, SkPaint* paint) {
+
+ jint count = end - start;
+ sp<TextLayoutCacheValue> value = gTextLayoutCache.getValue(
+ paint, textArray, start, count, count, flags);
+ if (value == NULL) {
+ LOGE("drawTextWithGlyphs -- cannot get Cache value");
+ return ;
+ }
+#if DEBUG_GLYPHS
+ logGlyphs(value);
+#endif
+ doDrawGlyphs(canvas, value->getGlyphs(), 0, value->getGlyphsCount(),
+ x, y, flags, paint);
+ }
+
static void drawTextWithGlyphs___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas,
jcharArray text, int index, int count,
jfloat x, jfloat y, int flags, SkPaint* paint) {
jchar* textArray = env->GetCharArrayElements(text, NULL);
-#if RTL_USE_HARFBUZZ && USE_TEXT_LAYOUT_CACHE
- sp<TextLayoutCacheValue> value = gTextLayoutCache.getValue(
- paint, textArray + index, 0, count, count, flags);
- if (value != NULL) {
-#if DEBUG_GLYPHS
- LOGD("drawTextWithGlyphs -- got glyphs - count=%d", value->getGlyphsCount());
- for (size_t i = 0; i < value->getGlyphsCount(); i++) {
- LOGD(" glyphs[%d]=%d", i, value->getGlyphs()[i]);
- }
-#endif
- doDrawGlyphs(canvas, value->getGlyphs(), 0, value->getGlyphsCount(),
- x, y, flags, paint);
- }
-#else
- TextLayout::drawText(paint, textArray + index, count, flags, x, y, canvas);
-#endif
+ drawTextWithGlyphs(canvas, textArray + index, 0, count, x, y, flags, paint);
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
}
@@ -785,23 +795,7 @@ public:
jfloat x, jfloat y, int flags, SkPaint* paint) {
const jchar* textArray = env->GetStringChars(text, NULL);
-#if RTL_USE_HARFBUZZ && USE_TEXT_LAYOUT_CACHE
- size_t count = end - start;
- sp<TextLayoutCacheValue> value = gTextLayoutCache.getValue(
- paint, textArray, start, count, count, flags);
- if (value != NULL) {
-#if DEBUG_GLYPHS
- LOGD("drawTextWithGlyphs -- got glyphs - count=%d", value->getGlyphsCount());
- for (size_t i = 0; i < value->getGlyphsCount(); i++) {
- LOGD(" glyphs[%d]=%d", i, value->getGlyphs()[i]);
- }
-#endif
- doDrawGlyphs(canvas, value->getGlyphs(), 0, value->getGlyphsCount(),
- x, y, flags, paint);
- }
-#else
- TextLayout::drawText(paint, textArray + start, end - start, flags, x, y, canvas);
-#endif
+ drawTextWithGlyphs(canvas, textArray, start, end, x, y, flags, paint);
env->ReleaseStringChars(text, textArray);
}
diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
index 137acc612cbf..6ce3f51925ac 100644
--- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
+++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp
@@ -3,7 +3,6 @@
#define RETURN_NULL_IF_NULL(value) \
do { if (!(value)) { SkASSERT(0); return NULL; } } while (false)
-static jclass gInputStream_Clazz;
static jmethodID gInputStream_resetMethodID;
static jmethodID gInputStream_markMethodID;
static jmethodID gInputStream_availableMethodID;
@@ -19,10 +18,10 @@ public:
SkASSERT(fCapacity > 0);
fBytesRead = 0;
}
-
+
virtual bool rewind() {
JNIEnv* env = fEnv;
-
+
fBytesRead = 0;
env->CallVoidMethod(fJavaInputStream, gInputStream_resetMethodID);
@@ -34,7 +33,7 @@ public:
}
return true;
}
-
+
size_t doRead(void* buffer, size_t size) {
JNIEnv* env = fEnv;
size_t bytesRead = 0;
@@ -43,7 +42,7 @@ public:
size_t requested = size;
if (requested > fCapacity)
requested = fCapacity;
-
+
jint n = env->CallIntMethod(fJavaInputStream,
gInputStream_readMethodID, fJavaByteArray, 0, requested);
if (env->ExceptionCheck()) {
@@ -52,11 +51,11 @@ public:
SkDebugf("---- read threw an exception\n");
return 0;
}
-
+
if (n < 0) { // n == 0 should not be possible, see InputStream read() specifications.
break; // eof
}
-
+
env->GetByteArrayRegion(fJavaByteArray, 0, n,
reinterpret_cast<jbyte*>(buffer));
if (env->ExceptionCheck()) {
@@ -65,16 +64,16 @@ public:
SkDebugf("---- read:GetByteArrayRegion threw an exception\n");
return 0;
}
-
+
buffer = (void*)((char*)buffer + n);
bytesRead += n;
size -= n;
fBytesRead += n;
} while (size != 0);
-
+
return bytesRead;
}
-
+
size_t doSkip(size_t size) {
JNIEnv* env = fEnv;
@@ -92,7 +91,7 @@ public:
return (size_t)skipped;
}
-
+
size_t doSize() {
JNIEnv* env = fEnv;
jint avail = env->CallIntMethod(fJavaInputStream,
@@ -105,7 +104,7 @@ public:
}
return avail;
}
-
+
virtual size_t read(void* buffer, size_t size) {
JNIEnv* env = fEnv;
if (NULL == buffer) {
@@ -134,7 +133,7 @@ public:
}
return this->doRead(buffer, size);
}
-
+
private:
JNIEnv* fEnv;
jobject fJavaInputStream; // the caller owns this object
@@ -148,19 +147,18 @@ SkStream* CreateJavaInputStreamAdaptor(JNIEnv* env, jobject stream,
static bool gInited;
if (!gInited) {
- gInputStream_Clazz = env->FindClass("java/io/InputStream");
- RETURN_NULL_IF_NULL(gInputStream_Clazz);
- gInputStream_Clazz = (jclass)env->NewGlobalRef(gInputStream_Clazz);
+ jclass inputStream_Clazz = env->FindClass("java/io/InputStream");
+ RETURN_NULL_IF_NULL(inputStream_Clazz);
- gInputStream_resetMethodID = env->GetMethodID(gInputStream_Clazz,
+ gInputStream_resetMethodID = env->GetMethodID(inputStream_Clazz,
"reset", "()V");
- gInputStream_markMethodID = env->GetMethodID(gInputStream_Clazz,
+ gInputStream_markMethodID = env->GetMethodID(inputStream_Clazz,
"mark", "(I)V");
- gInputStream_availableMethodID = env->GetMethodID(gInputStream_Clazz,
+ gInputStream_availableMethodID = env->GetMethodID(inputStream_Clazz,
"available", "()I");
- gInputStream_readMethodID = env->GetMethodID(gInputStream_Clazz,
+ gInputStream_readMethodID = env->GetMethodID(inputStream_Clazz,
"read", "([BII)I");
- gInputStream_skipMethodID = env->GetMethodID(gInputStream_Clazz,
+ gInputStream_skipMethodID = env->GetMethodID(inputStream_Clazz,
"skip", "(J)J");
RETURN_NULL_IF_NULL(gInputStream_resetMethodID);
@@ -181,7 +179,6 @@ SkStream* CreateJavaInputStreamAdaptor(JNIEnv* env, jobject stream,
///////////////////////////////////////////////////////////////////////////////
-static jclass gOutputStream_Clazz;
static jmethodID gOutputStream_writeMethodID;
static jmethodID gOutputStream_flushMethodID;
@@ -191,11 +188,11 @@ public:
: fEnv(env), fJavaOutputStream(stream), fJavaByteArray(storage) {
fCapacity = env->GetArrayLength(storage);
}
-
+
virtual bool write(const void* buffer, size_t size) {
JNIEnv* env = fEnv;
jbyteArray storage = fJavaByteArray;
-
+
while (size > 0) {
size_t requested = size;
if (requested > fCapacity) {
@@ -210,7 +207,7 @@ public:
SkDebugf("--- write:SetByteArrayElements threw an exception\n");
return false;
}
-
+
fEnv->CallVoidMethod(fJavaOutputStream, gOutputStream_writeMethodID,
storage, 0, requested);
if (env->ExceptionCheck()) {
@@ -219,17 +216,17 @@ public:
SkDebugf("------- write threw an exception\n");
return false;
}
-
+
buffer = (void*)((char*)buffer + requested);
size -= requested;
}
return true;
}
-
+
virtual void flush() {
fEnv->CallVoidMethod(fJavaOutputStream, gOutputStream_flushMethodID);
}
-
+
private:
JNIEnv* fEnv;
jobject fJavaOutputStream; // the caller owns this object
@@ -242,14 +239,13 @@ SkWStream* CreateJavaOutputStreamAdaptor(JNIEnv* env, jobject stream,
static bool gInited;
if (!gInited) {
- gOutputStream_Clazz = env->FindClass("java/io/OutputStream");
- RETURN_NULL_IF_NULL(gOutputStream_Clazz);
- gOutputStream_Clazz = (jclass)env->NewGlobalRef(gOutputStream_Clazz);
+ jclass outputStream_Clazz = env->FindClass("java/io/OutputStream");
+ RETURN_NULL_IF_NULL(outputStream_Clazz);
- gOutputStream_writeMethodID = env->GetMethodID(gOutputStream_Clazz,
+ gOutputStream_writeMethodID = env->GetMethodID(outputStream_Clazz,
"write", "([BII)V");
RETURN_NULL_IF_NULL(gOutputStream_writeMethodID);
- gOutputStream_flushMethodID = env->GetMethodID(gOutputStream_Clazz,
+ gOutputStream_flushMethodID = env->GetMethodID(outputStream_Clazz,
"flush", "()V");
RETURN_NULL_IF_NULL(gOutputStream_flushMethodID);
@@ -258,4 +254,3 @@ SkWStream* CreateJavaOutputStreamAdaptor(JNIEnv* env, jobject stream,
return new SkJavaOutputStream(env, stream, storage);
}
-
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 6c28e65e11f7..64bd20775ac1 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -350,14 +350,10 @@ jobject GraphicsJNI::createBitmap(JNIEnv* env, SkBitmap* bitmap, jbyteArray buff
SkASSERT(bitmap);
SkASSERT(bitmap->pixelRef());
- jobject obj = env->AllocObject(gBitmap_class);
- if (obj) {
- env->CallVoidMethod(obj, gBitmap_constructorMethodID,
- (jint)bitmap, buffer, isMutable, ninepatch, density);
- if (hasException(env)) {
- obj = NULL;
- }
- }
+ jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID,
+ static_cast<jint>(reinterpret_cast<uintptr_t>(bitmap)),
+ buffer, isMutable, ninepatch, density);
+ hasException(env); // For the side effect of logging.
return obj;
}
@@ -372,30 +368,19 @@ jobject GraphicsJNI::createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecode
{
SkASSERT(bitmap != NULL);
- jobject obj = env->AllocObject(gBitmapRegionDecoder_class);
- if (hasException(env)) {
- obj = NULL;
- return obj;
- }
- if (obj) {
- env->CallVoidMethod(obj, gBitmapRegionDecoder_constructorMethodID, (jint)bitmap);
- if (hasException(env)) {
- obj = NULL;
- }
- }
+ jobject obj = env->NewObject(gBitmapRegionDecoder_class,
+ gBitmapRegionDecoder_constructorMethodID,
+ static_cast<jint>(reinterpret_cast<uintptr_t>(bitmap)));
+ hasException(env); // For the side effect of logging.
return obj;
}
jobject GraphicsJNI::createRegion(JNIEnv* env, SkRegion* region)
{
SkASSERT(region != NULL);
- jobject obj = env->AllocObject(gRegion_class);
- if (obj) {
- env->CallVoidMethod(obj, gRegion_constructorMethodID, (jint)region, 0);
- if (hasException(env)) {
- obj = NULL;
- }
- }
+ jobject obj = env->NewObject(gRegion_class, gRegion_constructorMethodID,
+ static_cast<jint>(reinterpret_cast<uintptr_t>(region)), 0);
+ hasException(env); // For the side effect of logging.
return obj;
}
diff --git a/core/jni/android/graphics/Interpolator.cpp b/core/jni/android/graphics/Interpolator.cpp
index beec351c4f26..aa33c3dcbc11 100644
--- a/core/jni/android/graphics/Interpolator.cpp
+++ b/core/jni/android/graphics/Interpolator.cpp
@@ -61,7 +61,7 @@ static int Interpolator_timeToValues(JNIEnv* env, jobject clazz, SkInterpolator*
float* values = valueArray ? env->GetFloatArrayElements(valueArray, NULL) : NULL;
result = interp->timeToValues(msec, (SkScalar*)values);
-
+
if (valueArray) {
int n = env->GetArrayLength(valueArray);
for (int i = 0; i < n; i++) {
@@ -69,7 +69,7 @@ static int Interpolator_timeToValues(JNIEnv* env, jobject clazz, SkInterpolator*
}
env->ReleaseFloatArrayElements(valueArray, values, 0);
}
-
+
return result;
}
@@ -87,7 +87,6 @@ static JNINativeMethod gInterpolatorMethods[] = {
{ "nativeTimeToValues", "(II[F)I", (void*)Interpolator_timeToValues }
};
-int register_android_graphics_Interpolator(JNIEnv* env);
int register_android_graphics_Interpolator(JNIEnv* env)
{
return android::AndroidRuntime::registerNativeMethods(env,
diff --git a/core/jni/android/graphics/LayerRasterizer.cpp b/core/jni/android/graphics/LayerRasterizer.cpp
index 7c4588999584..e5bc6f8aee0b 100644
--- a/core/jni/android/graphics/LayerRasterizer.cpp
+++ b/core/jni/android/graphics/LayerRasterizer.cpp
@@ -11,7 +11,7 @@ public:
SkASSERT(layer);
SkASSERT(paint);
layer->addLayer(*paint, SkFloatToScalar(dx), SkFloatToScalar(dy));
- }
+ }
};
/////////////////////////////////////////////////////////////////////////////////////////
@@ -23,7 +23,6 @@ static JNINativeMethod gLayerRasterizerMethods[] = {
{ "nativeAddLayer", "(IIFF)V", (void*)SkLayerRasterizerGlue::addLayer }
};
-int register_android_graphics_LayerRasterizer(JNIEnv* env);
int register_android_graphics_LayerRasterizer(JNIEnv* env)
{
return android::AndroidRuntime::registerNativeMethods(env,
@@ -31,4 +30,3 @@ int register_android_graphics_LayerRasterizer(JNIEnv* env)
gLayerRasterizerMethods,
SK_ARRAY_COUNT(gLayerRasterizerMethods));
}
-
diff --git a/core/jni/android/graphics/MaskFilter.cpp b/core/jni/android/graphics/MaskFilter.cpp
index d3f9b78fecc2..d954ddfea198 100644
--- a/core/jni/android/graphics/MaskFilter.cpp
+++ b/core/jni/android/graphics/MaskFilter.cpp
@@ -23,7 +23,7 @@ public:
ThrowIAE_IfNull(env, filter);
return filter;
}
-
+
static SkMaskFilter* createEmboss(JNIEnv* env, jobject, jfloatArray dirArray, float ambient, float specular, float radius) {
SkScalar direction[3];
@@ -79,16 +79,14 @@ static JNINativeMethod gTableMaskFilterMethods[] = {
result = android::AndroidRuntime::registerNativeMethods(env, name, array, SK_ARRAY_COUNT(array)); \
if (result < 0) return result
-int register_android_graphics_MaskFilter(JNIEnv* env);
int register_android_graphics_MaskFilter(JNIEnv* env)
{
int result;
-
+
REG(env, "android/graphics/MaskFilter", gMaskFilterMethods);
REG(env, "android/graphics/BlurMaskFilter", gBlurMaskFilterMethods);
REG(env, "android/graphics/EmbossMaskFilter", gEmbossMaskFilterMethods);
REG(env, "android/graphics/TableMaskFilter", gTableMaskFilterMethods);
-
+
return 0;
}
-
diff --git a/core/jni/android/graphics/Movie.cpp b/core/jni/android/graphics/Movie.cpp
index 714543399003..c11242383814 100644
--- a/core/jni/android/graphics/Movie.cpp
+++ b/core/jni/android/graphics/Movie.cpp
@@ -23,11 +23,8 @@ jobject create_jmovie(JNIEnv* env, SkMovie* moov) {
if (NULL == moov) {
return NULL;
}
- jobject obj = env->AllocObject(gMovie_class);
- if (obj) {
- env->CallVoidMethod(obj, gMovie_constructorMethodID, (jint)moov);
- }
- return obj;
+ return env->NewObject(gMovie_class, gMovie_constructorMethodID,
+ static_cast<jint>(reinterpret_cast<uintptr_t>(moov)));
}
static SkMovie* J2Movie(JNIEnv* env, jobject movie) {
diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp
index f9a35183a7b3..0c8a8a3466e6 100644
--- a/core/jni/android/graphics/NinePatch.cpp
+++ b/core/jni/android/graphics/NinePatch.cpp
@@ -182,7 +182,6 @@ static JNINativeMethod gNinePatchMethods[] = {
(void*)SkNinePatchGlue::getTransparentRegion }
};
-int register_android_graphics_NinePatch(JNIEnv* env);
int register_android_graphics_NinePatch(JNIEnv* env)
{
return android::AndroidRuntime::registerNativeMethods(env,
diff --git a/core/jni/android/graphics/PathEffect.cpp b/core/jni/android/graphics/PathEffect.cpp
index cfa9ce44549b..0503614c008c 100644
--- a/core/jni/android/graphics/PathEffect.cpp
+++ b/core/jni/android/graphics/PathEffect.cpp
@@ -19,12 +19,12 @@ public:
SkPathEffect* outer, SkPathEffect* inner) {
return new SkComposePathEffect(outer, inner);
}
-
+
static SkPathEffect* Sum_constructor(JNIEnv* env, jobject,
SkPathEffect* first, SkPathEffect* second) {
return new SkSumPathEffect(first, second);
}
-
+
static SkPathEffect* Dash_constructor(JNIEnv* env, jobject,
jfloatArray intervalArray, float phase) {
AutoJavaFloatArray autoInterval(env, intervalArray);
@@ -32,30 +32,30 @@ public:
float* values = autoInterval.ptr();
SkAutoSTMalloc<32, SkScalar> storage(count);
- SkScalar* intervals = storage.get();
+ SkScalar* intervals = storage.get();
for (int i = 0; i < count; i++) {
intervals[i] = SkFloatToScalar(values[i]);
}
return new SkDashPathEffect(intervals, count, SkFloatToScalar(phase));
}
-
+
static SkPathEffect* OneD_constructor(JNIEnv* env, jobject,
const SkPath* shape, float advance, float phase, int style) {
SkASSERT(shape != NULL);
return new SkPath1DPathEffect(*shape, SkFloatToScalar(advance),
SkFloatToScalar(phase), (SkPath1DPathEffect::Style)style);
}
-
+
static SkPathEffect* Corner_constructor(JNIEnv* env, jobject, float radius){
return new SkCornerPathEffect(SkFloatToScalar(radius));
}
-
+
static SkPathEffect* Discrete_constructor(JNIEnv* env, jobject,
float length, float deviation) {
return new SkDiscretePathEffect(SkFloatToScalar(length),
SkFloatToScalar(deviation));
}
-
+
};
////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -95,11 +95,10 @@ static JNINativeMethod gDiscretePathEffectMethods[] = {
SK_ARRAY_COUNT(array)); \
if (result < 0) return result
-int register_android_graphics_PathEffect(JNIEnv* env);
int register_android_graphics_PathEffect(JNIEnv* env)
{
int result;
-
+
REG(env, "android/graphics/PathEffect", gPathEffectMethods);
REG(env, "android/graphics/ComposePathEffect", gComposePathEffectMethods);
REG(env, "android/graphics/SumPathEffect", gSumPathEffectMethods);
@@ -107,7 +106,6 @@ int register_android_graphics_PathEffect(JNIEnv* env)
REG(env, "android/graphics/PathDashPathEffect", gPathDashPathEffectMethods);
REG(env, "android/graphics/CornerPathEffect", gCornerPathEffectMethods);
REG(env, "android/graphics/DiscretePathEffect", gDiscretePathEffectMethods);
-
+
return 0;
}
-
diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp
index 24452292ab62..5c6ebdf0b9c4 100644
--- a/core/jni/android/graphics/Region.cpp
+++ b/core/jni/android/graphics/Region.cpp
@@ -69,7 +69,7 @@ static jboolean Region_getBoundaryPath(JNIEnv* env, jobject, const SkRegion* reg
static jboolean Region_op0(JNIEnv* env, jobject, SkRegion* dst, int left, int top, int right, int bottom, int op) {
SkIRect ir;
-
+
ir.set(left, top, right, bottom);
return dst->op(ir, (SkRegion::Op)op);
}
@@ -84,16 +84,16 @@ static jboolean Region_op2(JNIEnv* env, jobject, SkRegion* dst, const SkRegion*
return dst->op(*region1, *region2, (SkRegion::Op)op);
}
-//////////////////////////////////// These are methods, not static
+//////////////////////////////////// These are methods, not static
static jboolean Region_isEmpty(JNIEnv* env, jobject region) {
return GetSkRegion(env, region)->isEmpty();
}
-
+
static jboolean Region_isRect(JNIEnv* env, jobject region) {
return GetSkRegion(env, region)->isRect();
}
-
+
static jboolean Region_isComplex(JNIEnv* env, jobject region) {
return GetSkRegion(env, region)->isComplex();
}
@@ -101,21 +101,21 @@ static jboolean Region_isComplex(JNIEnv* env, jobject region) {
static jboolean Region_contains(JNIEnv* env, jobject region, int x, int y) {
return GetSkRegion(env, region)->contains(x, y);
}
-
+
static jboolean Region_quickContains(JNIEnv* env, jobject region, int left, int top, int right, int bottom) {
return GetSkRegion(env, region)->quickContains(left, top, right, bottom);
}
-
+
static jboolean Region_quickRejectIIII(JNIEnv* env, jobject region, int left, int top, int right, int bottom) {
SkIRect ir;
ir.set(left, top, right, bottom);
return GetSkRegion(env, region)->quickReject(ir);
}
-
+
static jboolean Region_quickRejectRgn(JNIEnv* env, jobject region, jobject other) {
return GetSkRegion(env, region)->quickReject(*GetSkRegion(env, other));
}
-
+
static void Region_translate(JNIEnv* env, jobject region, int x, int y, jobject dst) {
SkRegion* rgn = GetSkRegion(env, region);
if (dst)
@@ -171,13 +171,13 @@ static SkRegion* Region_createFromParcel(JNIEnv* env, jobject clazz, jobject par
if (parcel == NULL) {
return NULL;
}
-
+
android::Parcel* p = android::parcelForJavaObject(env, parcel);
-
+
SkRegion* region = new SkRegion;
size_t size = p->readInt32();
region->unflatten(p->readInplace(size));
-
+
return region;
}
@@ -186,7 +186,7 @@ static jboolean Region_writeToParcel(JNIEnv* env, jobject clazz, const SkRegion*
if (parcel == NULL) {
return false;
}
-
+
android::Parcel* p = android::parcelForJavaObject(env, parcel);
size_t size = region->flatten(NULL);
@@ -208,7 +208,7 @@ static jboolean Region_equals(JNIEnv* env, jobject clazz, const SkRegion *r1, co
struct RgnIterPair {
SkRegion fRgn; // a copy of the caller's region
SkRegion::Iterator fIter; // an iterator acting upon the copy (fRgn)
-
+
RgnIterPair(const SkRegion& rgn) : fRgn(rgn) {
// have our iterator reference our copy (fRgn), so we know it will be
// unchanged for the lifetime of the iterator
@@ -218,7 +218,7 @@ struct RgnIterPair {
static RgnIterPair* RegionIter_constructor(JNIEnv* env, jobject, const SkRegion* region)
{
- SkASSERT(region);
+ SkASSERT(region);
return new RgnIterPair(*region);
}
@@ -279,12 +279,11 @@ static JNINativeMethod gRegionMethods[] = {
{ "nativeEquals", "(II)Z", (void*)Region_equals },
};
-int register_android_graphics_Region(JNIEnv* env);
int register_android_graphics_Region(JNIEnv* env)
{
jclass clazz = env->FindClass("android/graphics/Region");
SkASSERT(clazz);
-
+
gRegion_nativeInstanceFieldID = env->GetFieldID(clazz, "mNativeRegion", "I");
SkASSERT(gRegion_nativeInstanceFieldID);
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index 7fdad10c0744..f4cc9e44d7df 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -35,7 +35,7 @@ static void Color_RGBToHSV(JNIEnv* env, jobject, int red, int green, int blue, j
values[i] = SkScalarToFloat(hsv[i]);
}
}
-
+
static int Color_HSVToColor(JNIEnv* env, jobject, int alpha, jfloatArray hsvArray)
{
AutoJavaFloatArray autoHSV(env, hsvArray, 3);
@@ -45,7 +45,7 @@ static int Color_HSVToColor(JNIEnv* env, jobject, int alpha, jfloatArray hsvArra
for (int i = 0; i < 3; i++) {
hsv[i] = SkFloatToScalar(values[i]);
}
-
+
return SkHSVToColor(alpha, hsv);
}
@@ -104,7 +104,7 @@ static SkiaShader* BitmapShader_postConstructor(JNIEnv* env, jobject o, SkShader
return NULL;
#endif
}
-
+
///////////////////////////////////////////////////////////////////////////////////////////////
static SkShader* LinearGradient_create1(JNIEnv* env, jobject o,
@@ -129,7 +129,7 @@ static SkShader* LinearGradient_create1(JNIEnv* env, jobject o,
pos[i] = SkFloatToScalar(posValues[i]);
}
}
-
+
SkShader* shader = SkGradientShader::CreateLinear(pts,
reinterpret_cast<const SkColor*>(colorValues),
pos, count,
@@ -218,7 +218,7 @@ static SkShader* LinearGradient_create2(JNIEnv* env, jobject o,
SkColor colors[2];
colors[0] = color0;
colors[1] = color1;
-
+
SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL, 2, (SkShader::TileMode)tileMode);
ThrowIAE_IfNull(env, s);
@@ -237,7 +237,7 @@ static SkShader* RadialGradient_create1(JNIEnv* env, jobject, float x, float y,
SkAutoSTMalloc<8, SkScalar> storage(posArray ? count : 0);
SkScalar* pos = NULL;
-
+
if (posArray) {
AutoJavaFloatArray autoPos(env, posArray, count);
const float* posValues = autoPos.ptr();
@@ -338,10 +338,10 @@ static SkShader* SweepGradient_create1(JNIEnv* env, jobject, float x, float y,
jintArray jcolors, jfloatArray jpositions) {
size_t count = env->GetArrayLength(jcolors);
const jint* colors = env->GetIntArrayElements(jcolors, NULL);
-
+
SkAutoSTMalloc<8, SkScalar> storage(jpositions ? count : 0);
SkScalar* pos = NULL;
-
+
if (NULL != jpositions) {
AutoJavaFloatArray autoPos(env, jpositions, count);
const float* posValues = autoPos.ptr();
@@ -520,11 +520,10 @@ static JNINativeMethod gComposeShaderMethods[] = {
result = android::AndroidRuntime::registerNativeMethods(env, name, array, SK_ARRAY_COUNT(array)); \
if (result < 0) return result
-int register_android_graphics_Shader(JNIEnv* env);
int register_android_graphics_Shader(JNIEnv* env)
{
int result;
-
+
REG(env, "android/graphics/Color", gColorMethods);
REG(env, "android/graphics/Shader", gShaderMethods);
REG(env, "android/graphics/BitmapShader", gBitmapShaderMethods);
@@ -532,7 +531,6 @@ int register_android_graphics_Shader(JNIEnv* env)
REG(env, "android/graphics/RadialGradient", gRadialGradientMethods);
REG(env, "android/graphics/SweepGradient", gSweepGradientMethods);
REG(env, "android/graphics/ComposeShader", gComposeShaderMethods);
-
+
return result;
}
-
diff --git a/core/jni/android/graphics/TextLayout.h b/core/jni/android/graphics/TextLayout.h
index f203b751f998..9bb1b921675a 100644
--- a/core/jni/android/graphics/TextLayout.h
+++ b/core/jni/android/graphics/TextLayout.h
@@ -46,26 +46,26 @@ namespace android {
static TextLayoutCache gTextLayoutCache;
#endif
-class TextLayout {
-public:
-
- enum {
- kDirection_LTR = 0,
- kDirection_RTL = 1,
+enum {
+ kBidi_LTR = 0,
+ kBidi_RTL = 1,
+ kBidi_Default_LTR = 2,
+ kBidi_Default_RTL = 3,
+ kBidi_Force_LTR = 4,
+ kBidi_Force_RTL = 5,
+
+ kBidi_Mask = 0x7
+};
- kDirection_Mask = 0x1
- };
+enum {
+ kDirection_LTR = 0,
+ kDirection_RTL = 1,
- enum {
- kBidi_LTR = 0,
- kBidi_RTL = 1,
- kBidi_Default_LTR = 2,
- kBidi_Default_RTL = 3,
- kBidi_Force_LTR = 4,
- kBidi_Force_RTL = 5,
+ kDirection_Mask = 0x1
+};
- kBidi_Mask = 0x7
- };
+class TextLayout {
+public:
/*
* Draws a unidirectional run of text.
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index 8db768c0cd4c..77a731a3e948 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -15,6 +15,7 @@
*/
#include "TextLayoutCache.h"
+#include "TextLayout.h"
namespace android {
@@ -381,13 +382,128 @@ void TextLayoutCacheValue::shapeWithHarfbuzz(HB_ShaperItem* shaperItem, HB_FontR
}
}
+struct GlyphRun {
+ inline GlyphRun() {}
+ inline GlyphRun(jchar* glyphs, size_t glyphsCount, bool isRTL) :
+ glyphs(glyphs), glyphsCount(glyphsCount), isRTL(isRTL) { }
+ jchar* glyphs;
+ size_t glyphsCount;
+ int isRTL;
+};
+
void TextLayoutCacheValue::computeValuesWithHarfbuzz(SkPaint* paint, const UChar* chars,
size_t start, size_t count, size_t contextCount, int dirFlags,
jfloat* outAdvances, jfloat* outTotalAdvance,
jchar** outGlyphs, size_t* outGlyphsCount) {
+
+ UBiDiLevel bidiReq = 0;
+ bool forceLTR = false;
+ bool forceRTL = false;
+
+ switch (dirFlags) {
+ case kBidi_LTR: bidiReq = 0; break; // no ICU constant, canonical LTR level
+ case kBidi_RTL: bidiReq = 1; break; // no ICU constant, canonical RTL level
+ case kBidi_Default_LTR: bidiReq = UBIDI_DEFAULT_LTR; break;
+ case kBidi_Default_RTL: bidiReq = UBIDI_DEFAULT_RTL; break;
+ case kBidi_Force_LTR: forceLTR = true; break; // every char is LTR
+ case kBidi_Force_RTL: forceRTL = true; break; // every char is RTL
+ }
+
+ if (forceLTR || forceRTL) {
+#if DEBUG_GLYPHS
+ LOGD("computeValuesWithHarfbuzz -- forcing run with LTR=%d RTL=%d",
+ forceLTR, forceRTL);
+#endif
+ computeRunValuesWithHarfbuzz(paint, chars, start, count, contextCount, dirFlags,
+ outAdvances, outTotalAdvance, outGlyphs, outGlyphsCount);
+ } else {
+ UBiDi* bidi = ubidi_open();
+ if (bidi) {
+ UErrorCode status = U_ZERO_ERROR;
+#if DEBUG_GLYPHS
+ LOGD("computeValuesWithHarfbuzz -- bidiReq=%d", bidiReq);
+#endif
+ ubidi_setPara(bidi, chars, contextCount, bidiReq, NULL, &status);
+ if (U_SUCCESS(status)) {
+ int paraDir = ubidi_getParaLevel(bidi) & kDirection_Mask; // 0 if ltr, 1 if rtl
+ size_t rc = ubidi_countRuns(bidi, &status);
+#if DEBUG_GLYPHS
+ LOGD("computeValuesWithHarfbuzz -- dirFlags=%d run-count=%d paraDir=%d", dirFlags, rc, paraDir);
+#endif
+
+ if (rc == 1 || !U_SUCCESS(status)) {
+ computeRunValuesWithHarfbuzz(paint, chars, start, count, contextCount,
+ dirFlags, outAdvances, outTotalAdvance, outGlyphs, outGlyphsCount);
+ ubidi_close(bidi);
+ return;
+ }
+
+ size_t runIndex = 0;
+ Vector<GlyphRun> glyphRuns;
+ for (size_t i = 0; i < rc; ++i) {
+ int32_t startRun;
+ int32_t lengthRun;
+ UBiDiDirection runDir = ubidi_getVisualRun(bidi, i, &startRun, &lengthRun);
+
+ int newFlags = (runDir == UBIDI_RTL) ? kDirection_RTL : kDirection_LTR;
+ jfloat runTotalAdvance = 0;
+ jchar* runGlyphs;
+ size_t runGlyphsCount = 0;
+
+#if DEBUG_GLYPHS
+ LOGD("computeValuesWithHarfbuzz -- run-start=%d run-len=%d newFlags=%d",
+ startRun, lengthRun, newFlags);
+#endif
+ computeRunValuesWithHarfbuzz(paint, chars, startRun,
+ lengthRun, contextCount, newFlags,
+ outAdvances + runIndex, &runTotalAdvance,
+ &runGlyphs, &runGlyphsCount);
+
+ runIndex += lengthRun;
+
+ *outTotalAdvance += runTotalAdvance;
+ *outGlyphsCount += runGlyphsCount;
+
+#if DEBUG_GLYPHS
+ LOGD("computeValuesWithHarfbuzz -- run=%d run-glyphs-count=%d",
+ i, runGlyphsCount);
+ for (size_t j = 0; j < runGlyphsCount; j++) {
+ LOGD(" -- glyphs[%d]=%d", j, runGlyphs[j]);
+ }
+#endif
+ glyphRuns.push(GlyphRun(runGlyphs, runGlyphsCount, newFlags));
+ }
+
+#if DEBUG_GLYPHS
+ LOGD("computeValuesWithHarfbuzz -- total-glyphs-count=%d", *outGlyphsCount);
+#endif
+ *outGlyphs = new jchar[*outGlyphsCount];
+ jchar* glyphs = *outGlyphs;
+ for (size_t i = 0; i < glyphRuns.size(); i++) {
+ const GlyphRun& glyphRun = glyphRuns.itemAt(i);
+ if (glyphRun.isRTL) {
+ for (size_t n = 0; n < glyphRun.glyphsCount; n++) {
+ glyphs[glyphRun.glyphsCount - n - 1] = glyphRun.glyphs[n];
+ }
+ } else {
+ memcpy(glyphs, glyphRun.glyphs, glyphRun.glyphsCount * sizeof(jchar));
+ }
+ glyphs += glyphRun.glyphsCount;
+ delete[] glyphRun.glyphs;
+ }
+ }
+ ubidi_close(bidi);
+ }
+ }
+}
+
+void TextLayoutCacheValue::computeRunValuesWithHarfbuzz(SkPaint* paint, const UChar* chars,
+ size_t start, size_t count, size_t contextCount, int dirFlags,
+ jfloat* outAdvances, jfloat* outTotalAdvance,
+ jchar** outGlyphs, size_t* outGlyphsCount) {
+
bool isRTL = dirFlags & 0x1;
- // TODO: need to run BiDi algo here to breakdown the text in several runs
HB_ShaperItem shaperItem;
HB_FontRec font;
FontData fontData;
@@ -397,21 +513,30 @@ void TextLayoutCacheValue::computeValuesWithHarfbuzz(SkPaint* paint, const UChar
#if DEBUG_GLYPHS
LOGD("HARFBUZZ -- num_glypth=%d - kerning_applied=%d", shaperItem.num_glyphs,
shaperItem.kerning_applied);
- LOGD(" -- string= '%s'", String8(chars, contextCount).string());
+ LOGD(" -- string= '%s'", String8(chars + start, count).string());
LOGD(" -- isDevKernText=%d", paint->isDevKernText());
#endif
// Get Advances and their total
- jfloat totalAdvance = 0;
- for (size_t i = 0; i < count; i++) {
- totalAdvance += outAdvances[i] = HBFixedToFloat(shaperItem.advances[i]);
-#if DEBUG_ADVANCES
- LOGD("hb-adv = %d - rebased = %f - total = %f", shaperItem.advances[i], outAdvances[i],
- totalAdvance);
-#endif
+ jfloat totalAdvance = outAdvances[0] = HBFixedToFloat(shaperItem.advances[shaperItem.log_clusters[0]]);
+ for (size_t i = 1; i < count; i++) {
+ size_t clusterPrevious = shaperItem.log_clusters[i - 1];
+ size_t cluster = shaperItem.log_clusters[i];
+ if (cluster == clusterPrevious) {
+ outAdvances[i] = 0;
+ } else {
+ totalAdvance += outAdvances[i] = HBFixedToFloat(shaperItem.advances[shaperItem.log_clusters[i]]);
+ }
}
*outTotalAdvance = totalAdvance;
+#if DEBUG_ADVANCES
+ for (size_t i = 0; i < count; i++) {
+ LOGD("hb-adv[%d] = %f - log_clusters = %d - total = %f", i,
+ outAdvances[i], shaperItem.log_clusters[i], totalAdvance);
+ }
+#endif
+
// Get Glyphs
if (outGlyphs) {
*outGlyphsCount = shaperItem.num_glyphs;
diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h
index e6ce68d75cb1..62813df154aa 100644
--- a/core/jni/android/graphics/TextLayoutCache.h
+++ b/core/jni/android/graphics/TextLayoutCache.h
@@ -178,6 +178,10 @@ private:
static void createGlyphArrays(HB_ShaperItem* shaperItem, int size);
static void resetGlyphArrays(HB_ShaperItem* shaperItem);
+ static void computeRunValuesWithHarfbuzz(SkPaint* paint, const UChar* chars, size_t start,
+ size_t count, size_t contextCount, int dirFlags,
+ jfloat* outAdvances, jfloat* outTotalAdvance,
+ jchar** outGlyphs, size_t* outGlyphsCount);
}; // TextLayoutCacheValue
/**
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index 53a5c0ada828..b25598aecf2a 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -44,7 +44,7 @@ static SkTypeface* Typeface_create(JNIEnv* env, jobject, jstring name,
static SkTypeface* Typeface_createFromTypeface(JNIEnv* env, jobject, SkTypeface* family, int style) {
return SkTypeface::CreateFromTypeface(family, (SkTypeface::Style)style);
}
-
+
static void Typeface_unref(JNIEnv* env, jobject obj, SkTypeface* face) {
SkSafeUnref(face);
}
@@ -64,7 +64,7 @@ public:
{
delete fAsset;
}
-
+
virtual const void* getMemoryBase()
{
return fMemoryBase;
@@ -75,38 +75,38 @@ public:
off64_t pos = fAsset->seek(0, SEEK_SET);
return pos != (off64_t)-1;
}
-
+
virtual size_t read(void* buffer, size_t size)
{
ssize_t amount;
-
+
if (NULL == buffer)
{
if (0 == size) // caller is asking us for our total length
return fAsset->getLength();
-
+
// asset->seek returns new total offset
// we want to return amount that was skipped
-
+
off64_t oldOffset = fAsset->seek(0, SEEK_CUR);
if (-1 == oldOffset)
return 0;
off64_t newOffset = fAsset->seek(size, SEEK_CUR);
if (-1 == newOffset)
return 0;
-
+
amount = newOffset - oldOffset;
}
else
{
amount = fAsset->read(buffer, size);
}
-
+
if (amount < 0)
amount = 0;
return amount;
}
-
+
private:
Asset* fAsset;
const void* fMemoryBase;
@@ -115,21 +115,21 @@ private:
static SkTypeface* Typeface_createFromAsset(JNIEnv* env, jobject,
jobject jassetMgr,
jstring jpath) {
-
+
NPE_CHECK_RETURN_ZERO(env, jassetMgr);
NPE_CHECK_RETURN_ZERO(env, jpath);
-
+
AssetManager* mgr = assetManagerForJavaObject(env, jassetMgr);
if (NULL == mgr) {
return NULL;
}
-
+
AutoJavaStringToUTF8 str(env, jpath);
Asset* asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
if (NULL == asset) {
return NULL;
}
-
+
SkStream* stream = new AssetStream(asset, true);
SkTypeface* face = SkTypeface::CreateFromStream(stream);
// SkTypeFace::CreateFromStream calls ref() on the stream, so we
@@ -180,7 +180,6 @@ static JNINativeMethod gTypefaceMethods[] = {
{ "setGammaForText", "(FF)V", (void*)Typeface_setGammaForText },
};
-int register_android_graphics_Typeface(JNIEnv* env);
int register_android_graphics_Typeface(JNIEnv* env)
{
return android::AndroidRuntime::registerNativeMethods(env,
diff --git a/core/jni/android/graphics/YuvToJpegEncoder.cpp b/core/jni/android/graphics/YuvToJpegEncoder.cpp
index 0a0c5b3d3d41..8333e00057d6 100644
--- a/core/jni/android/graphics/YuvToJpegEncoder.cpp
+++ b/core/jni/android/graphics/YuvToJpegEncoder.cpp
@@ -242,7 +242,6 @@ static JNINativeMethod gYuvImageMethods[] = {
#define kClassPathName "android/graphics/YuvImage"
-int register_android_graphics_YuvImage(JNIEnv* env);
int register_android_graphics_YuvImage(JNIEnv* env)
{
return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
diff --git a/core/jni/android_backup_BackupDataInput.cpp b/core/jni/android_backup_BackupDataInput.cpp
index b03dd16351fc..c174a41443d1 100644
--- a/core/jni/android_backup_BackupDataInput.cpp
+++ b/core/jni/android_backup_BackupDataInput.cpp
@@ -25,9 +25,6 @@
namespace android
{
-// java.io.FileDescriptor
-static jfieldID s_descriptorField = 0;
-
// android.app.backup.BackupDataInput$EntityHeader
static jfieldID s_keyField = 0;
static jfieldID s_dataSizeField = 0;
@@ -35,9 +32,7 @@ static jfieldID s_dataSizeField = 0;
static int
ctor_native(JNIEnv* env, jobject clazz, jobject fileDescriptor)
{
- int err;
-
- int fd = env->GetIntField(fileDescriptor, s_descriptorField);
+ int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
if (fd == -1) {
return NULL;
}
@@ -140,15 +135,7 @@ int register_android_backup_BackupDataInput(JNIEnv* env)
{
//LOGD("register_android_backup_BackupDataInput");
- jclass clazz;
-
- clazz = env->FindClass("java/io/FileDescriptor");
- LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor");
- s_descriptorField = env->GetFieldID(clazz, "descriptor", "I");
- LOG_FATAL_IF(s_descriptorField == NULL,
- "Unable to find descriptor field in java.io.FileDescriptor");
-
- clazz = env->FindClass("android/app/backup/BackupDataInput$EntityHeader");
+ jclass clazz = env->FindClass("android/app/backup/BackupDataInput$EntityHeader");
LOG_FATAL_IF(clazz == NULL, "Unable to find class android.app.backup.BackupDataInput.EntityHeader");
s_keyField = env->GetFieldID(clazz, "key", "Ljava/lang/String;");
LOG_FATAL_IF(s_keyField == NULL,
diff --git a/core/jni/android_backup_BackupDataOutput.cpp b/core/jni/android_backup_BackupDataOutput.cpp
index b895d118203a..144a10ced67c 100644
--- a/core/jni/android_backup_BackupDataOutput.cpp
+++ b/core/jni/android_backup_BackupDataOutput.cpp
@@ -25,14 +25,10 @@
namespace android
{
-static jfieldID s_descriptorField = 0;
-
static int
ctor_native(JNIEnv* env, jobject clazz, jobject fileDescriptor)
{
- int err;
-
- int fd = env->GetIntField(fileDescriptor, s_descriptorField);
+ int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
if (fd == -1) {
return NULL;
}
@@ -112,15 +108,6 @@ static const JNINativeMethod g_methods[] = {
int register_android_backup_BackupDataOutput(JNIEnv* env)
{
//LOGD("register_android_backup_BackupDataOutput");
-
- jclass clazz;
-
- clazz = env->FindClass("java/io/FileDescriptor");
- LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor");
- s_descriptorField = env->GetFieldID(clazz, "descriptor", "I");
- LOG_FATAL_IF(s_descriptorField == NULL,
- "Unable to find descriptor field in java.io.FileDescriptor");
-
return AndroidRuntime::registerNativeMethods(env, "android/app/backup/BackupDataOutput",
g_methods, NELEM(g_methods));
}
diff --git a/core/jni/android_backup_BackupHelperDispatcher.cpp b/core/jni/android_backup_BackupHelperDispatcher.cpp
index 26e7d66da24d..49f1cd49fd8f 100644
--- a/core/jni/android_backup_BackupHelperDispatcher.cpp
+++ b/core/jni/android_backup_BackupHelperDispatcher.cpp
@@ -37,8 +37,6 @@ struct chunk_header_v1 {
int nameLength; // not including the NULL terminator, which is not written to the file
};
-// java.io.FileDescriptor
-static jfieldID s_descriptorField = 0;
static jfieldID s_chunkSizeField = 0;
static jfieldID s_keyPrefixField = 0;
@@ -46,12 +44,11 @@ static int
readHeader_native(JNIEnv* env, jobject clazz, jobject headerObj, jobject fdObj)
{
chunk_header_v1 flattenedHeader;
- int fd;
ssize_t amt;
String8 keyPrefix;
char* buf;
- fd = env->GetIntField(fdObj, s_descriptorField);
+ int fd = jniGetFDFromFileDescriptor(env, fdObj);
amt = read(fd, &flattenedHeader.headerSize, sizeof(flattenedHeader.headerSize));
if (amt != sizeof(flattenedHeader.headerSize)) {
@@ -128,9 +125,7 @@ readHeader_native(JNIEnv* env, jobject clazz, jobject headerObj, jobject fdObj)
static int
skipChunk_native(JNIEnv* env, jobject clazz, jobject fdObj, jint bytesToSkip)
{
- int fd;
-
- fd = env->GetIntField(fdObj, s_descriptorField);
+ int fd = jniGetFDFromFileDescriptor(env, fdObj);
lseek(fd, bytesToSkip, SEEK_CUR);
@@ -152,9 +147,8 @@ allocateHeader_native(JNIEnv* env, jobject clazz, jobject headerObj, jobject fdO
int nameLength;
int namePadding;
int headerSize;
- int fd;
- fd = env->GetIntField(fdObj, s_descriptorField);
+ int fd = jniGetFDFromFileDescriptor(env, fdObj);
nameObj = (jstring)env->GetObjectField(headerObj, s_keyPrefixField);
@@ -166,7 +160,7 @@ allocateHeader_native(JNIEnv* env, jobject clazz, jobject headerObj, jobject fdO
pos = lseek(fd, 0, SEEK_CUR);
lseek(fd, headerSize, SEEK_CUR);
-
+
return pos;
}
@@ -175,13 +169,12 @@ writeHeader_native(JNIEnv* env, jobject clazz, jobject headerObj, jobject fdObj,
{
int err;
chunk_header_v1 header;
- int fd;
int namePadding;
int prevPos;
jstring nameObj;
const char* buf;
- fd = env->GetIntField(fdObj, s_descriptorField);
+ int fd = jniGetFDFromFileDescriptor(env, fdObj);
prevPos = lseek(fd, 0, SEEK_CUR);
nameObj = (jstring)env->GetObjectField(headerObj, s_keyPrefixField);
@@ -234,15 +227,7 @@ static const JNINativeMethod g_methods[] = {
int register_android_backup_BackupHelperDispatcher(JNIEnv* env)
{
- jclass clazz;
-
- clazz = env->FindClass("java/io/FileDescriptor");
- LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor");
- s_descriptorField = env->GetFieldID(clazz, "descriptor", "I");
- LOG_FATAL_IF(s_descriptorField == NULL,
- "Unable to find descriptor field in java.io.FileDescriptor");
-
- clazz = env->FindClass("android/app/backup/BackupHelperDispatcher$Header");
+ jclass clazz = env->FindClass("android/app/backup/BackupHelperDispatcher$Header");
LOG_FATAL_IF(clazz == NULL,
"Unable to find class android.app.backup.BackupHelperDispatcher.Header");
s_chunkSizeField = env->GetFieldID(clazz, "chunkSize", "I");
@@ -251,7 +236,7 @@ int register_android_backup_BackupHelperDispatcher(JNIEnv* env)
s_keyPrefixField = env->GetFieldID(clazz, "keyPrefix", "Ljava/lang/String;");
LOG_FATAL_IF(s_keyPrefixField == NULL,
"Unable to find keyPrefix field in android.app.backup.BackupHelperDispatcher.Header");
-
+
return AndroidRuntime::registerNativeMethods(env, "android/app/backup/BackupHelperDispatcher",
g_methods, NELEM(g_methods));
}
diff --git a/core/jni/android_backup_FileBackupHelperBase.cpp b/core/jni/android_backup_FileBackupHelperBase.cpp
index 0137a064e686..0dfd8dbfb29d 100644
--- a/core/jni/android_backup_FileBackupHelperBase.cpp
+++ b/core/jni/android_backup_FileBackupHelperBase.cpp
@@ -25,9 +25,6 @@
namespace android
{
-// java.io.FileDescriptor
-static jfieldID s_descriptorField = 0;
-
static int
ctor(JNIEnv* env, jobject clazz)
{
@@ -47,8 +44,8 @@ performBackup_native(JNIEnv* env, jobject clazz, jobject oldState, int data,
int err;
// all parameters have already been checked against null
- int oldStateFD = oldState != NULL ? env->GetIntField(oldState, s_descriptorField) : -1;
- int newStateFD = env->GetIntField(newState, s_descriptorField);
+ int oldStateFD = oldState != NULL ? jniGetFDFromFileDescriptor(env, oldState) : -1;
+ int newStateFD = jniGetFDFromFileDescriptor(env, newState);
BackupDataWriter* dataStream = (BackupDataWriter*)data;
const int fileCount = env->GetArrayLength(files);
@@ -102,7 +99,7 @@ writeSnapshot_native(JNIEnv* env, jobject clazz, jint ptr, jobject fileDescripto
int err;
RestoreHelperBase* restore = (RestoreHelperBase*)ptr;
- int fd = env->GetIntField(fileDescriptor, s_descriptorField);
+ int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
err = restore->WriteSnapshot(fd);
@@ -121,14 +118,6 @@ static const JNINativeMethod g_methods[] = {
int register_android_backup_FileBackupHelperBase(JNIEnv* env)
{
- jclass clazz;
-
- clazz = env->FindClass("java/io/FileDescriptor");
- LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor");
- s_descriptorField = env->GetFieldID(clazz, "descriptor", "I");
- LOG_FATAL_IF(s_descriptorField == NULL,
- "Unable to find descriptor field in java.io.FileDescriptor");
-
return AndroidRuntime::registerNativeMethods(env, "android/app/backup/FileBackupHelperBase",
g_methods, NELEM(g_methods));
}
diff --git a/core/jni/android_content_res_ObbScanner.cpp b/core/jni/android_content_res_ObbScanner.cpp
index 404a87dbcb02..883753843233 100644
--- a/core/jni/android_content_res_ObbScanner.cpp
+++ b/core/jni/android_content_res_ObbScanner.cpp
@@ -39,7 +39,7 @@ static struct {
static void android_content_res_ObbScanner_getObbInfo(JNIEnv* env, jobject clazz, jstring file,
jobject obbInfo)
{
- const char* filePath = env->GetStringUTFChars(file, JNI_FALSE);
+ const char* filePath = env->GetStringUTFChars(file, NULL);
sp<ObbFile> obb = new ObbFile();
if (!obb->readFrom(filePath)) {
diff --git a/core/jni/android_database_SQLiteStatement.cpp b/core/jni/android_database_SQLiteStatement.cpp
index 97e0483021f6..05ffbb1d97af 100644
--- a/core/jni/android_database_SQLiteStatement.cpp
+++ b/core/jni/android_database_SQLiteStatement.cpp
@@ -143,7 +143,7 @@ static jstring native_1x1_string(JNIEnv* env, jobject object)
static jobject createParcelFileDescriptor(JNIEnv * env, int fd)
{
// Create FileDescriptor object
- jobject fileDesc = newFileDescriptor(env, fd);
+ jobject fileDesc = jniCreateFileDescriptor(env, fd);
if (fileDesc == NULL) {
// FileDescriptor constructor has thrown an exception
close(fd);
diff --git a/core/jni/android_emoji_EmojiFactory.cpp b/core/jni/android_emoji_EmojiFactory.cpp
index 1ebb36c8e873..81dae88c1e11 100644
--- a/core/jni/android_emoji_EmojiFactory.cpp
+++ b/core/jni/android_emoji_EmojiFactory.cpp
@@ -93,8 +93,6 @@ static EmojiFactoryCaller* gCaller;
static pthread_once_t g_once = PTHREAD_ONCE_INIT;
static bool lib_emoji_factory_is_ready;
-static jclass gString_class;
-
static jclass gBitmap_class;
static jmethodID gBitmap_constructorMethodID;
@@ -108,15 +106,11 @@ static void InitializeCaller() {
static jobject create_java_EmojiFactory(
JNIEnv* env, EmojiFactory* factory, jstring name) {
- jobject obj = env->AllocObject(gEmojiFactory_class);
- if (obj) {
- env->CallVoidMethod(obj, gEmojiFactory_constructorMethodID,
- (jint)factory, name);
- if (env->ExceptionCheck() != 0) {
- LOGE("*** Uncaught exception returned from Java call!\n");
- env->ExceptionDescribe();
- obj = NULL;
- }
+ jobject obj = env->NewObject(gEmojiFactory_class, gEmojiFactory_constructorMethodID,
+ static_cast<jint>(reinterpret_cast<uintptr_t>(factory)), name);
+ if (env->ExceptionCheck() != 0) {
+ LOGE("*** Uncaught exception returned from Java call!\n");
+ env->ExceptionDescribe();
}
return obj;
}
@@ -182,17 +176,12 @@ static jobject android_emoji_EmojiFactory_getBitmapFromAndroidPua(
return NULL;
}
- jobject obj = env->AllocObject(gBitmap_class);
- if (obj) {
- env->CallVoidMethod(obj, gBitmap_constructorMethodID,
- reinterpret_cast<jint>(bitmap), NULL, false, NULL, -1);
- if (env->ExceptionCheck() != 0) {
- LOGE("*** Uncaught exception returned from Java call!\n");
- env->ExceptionDescribe();
- return NULL;
- }
+ jobject obj = env->NewObject(gBitmap_class, gBitmap_constructorMethodID,
+ static_cast<jint>(reinterpret_cast<uintptr_t>(bitmap)), NULL, false, NULL, -1);
+ if (env->ExceptionCheck() != 0) {
+ LOGE("*** Uncaught exception returned from Java call!\n");
+ env->ExceptionDescribe();
}
-
return obj;
}
diff --git a/core/jni/android_hardware_UsbDevice.cpp b/core/jni/android_hardware_UsbDevice.cpp
index c2950ea5fd64..25f901b96b33 100644
--- a/core/jni/android_hardware_UsbDevice.cpp
+++ b/core/jni/android_hardware_UsbDevice.cpp
@@ -54,13 +54,6 @@ static JNINativeMethod method_table[] = {
int register_android_hardware_UsbDevice(JNIEnv *env)
{
- jclass clazz = env->FindClass("android/hardware/usb/UsbDevice");
- if (clazz == NULL) {
- LOGE("Can't find android/hardware/usb/UsbDevice");
- return -1;
- }
-
return AndroidRuntime::registerNativeMethods(env, "android/hardware/usb/UsbDevice",
method_table, NELEM(method_table));
}
-
diff --git a/core/jni/android_hardware_UsbDeviceConnection.cpp b/core/jni/android_hardware_UsbDeviceConnection.cpp
index e25951457e83..4d73bf3d066d 100644
--- a/core/jni/android_hardware_UsbDeviceConnection.cpp
+++ b/core/jni/android_hardware_UsbDeviceConnection.cpp
@@ -42,7 +42,7 @@ static jboolean
android_hardware_UsbDeviceConnection_open(JNIEnv *env, jobject thiz, jstring deviceName,
jobject fileDescriptor)
{
- int fd = getParcelFileDescriptorFD(env, fileDescriptor);
+ int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
// duplicate the file descriptor, since ParcelFileDescriptor will eventually close its copy
fd = dup(fd);
if (fd < 0)
diff --git a/core/jni/android_media_JetPlayer.cpp b/core/jni/android_media_JetPlayer.cpp
index a7ffff4d872b..e12406924eb4 100644
--- a/core/jni/android_media_JetPlayer.cpp
+++ b/core/jni/android_media_JetPlayer.cpp
@@ -175,7 +175,7 @@ android_media_JetPlayer_loadFromFileD(JNIEnv *env, jobject thiz,
lpJet->setEventCallback(jetPlayerEventCallback);
LOGV("android_media_JetPlayer_openFileDescr(): trying to load JET file through its fd" );
- EAS_RESULT result = lpJet->loadFromFD(getParcelFileDescriptorFD(env, fileDescriptor),
+ EAS_RESULT result = lpJet->loadFromFD(jniGetFDFromFileDescriptor(env, fileDescriptor),
(long long)offset, (long long)length); // cast params to types used by EAS_FILE
if(result==EAS_SUCCESS) {
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index db132ec019aa..4a0e68e01a9b 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -1,16 +1,16 @@
/*
* Copyright 2008, The Android Open Source Project
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * 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
+ * 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
+ * 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.
*/
@@ -225,9 +225,6 @@ static JNINativeMethod gNetworkUtilMethods[] = {
int register_android_net_NetworkUtils(JNIEnv* env)
{
- jclass netutils = env->FindClass(NETUTILS_PKG_NAME);
- LOG_FATAL_IF(netutils == NULL, "Unable to find class " NETUTILS_PKG_NAME);
-
jclass dhcpInfoInternalClass = env->FindClass("android/net/DhcpInfoInternal");
LOG_FATAL_IF(dhcpInfoInternalClass == NULL, "Unable to find class android/net/DhcpInfoInternal");
dhcpInfoInternalFieldIds.constructorId = env->GetMethodID(dhcpInfoInternalClass, "<init>", "()V");
diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp
index 0c84f1138e7c..203b5efc1608 100644
--- a/core/jni/android_net_TrafficStats.cpp
+++ b/core/jni/android_net_TrafficStats.cpp
@@ -25,6 +25,7 @@
#include <android_runtime/AndroidRuntime.h>
#include <cutils/logger.h>
#include <jni.h>
+#include <ScopedUtfChars.h>
#include <utils/misc.h>
#include <utils/Log.h>
@@ -130,13 +131,14 @@ static jlong getMobileRxBytes(JNIEnv* env, jobject clazz) {
"/sys/class/net/ppp0/statistics/rx_bytes");
}
-static jlong getData(JNIEnv* env, char *what, jstring interface) {
- char filename[80];
- jboolean isCopy;
-
- const char *interfaceStr = env->GetStringUTFChars(interface, &isCopy);
- snprintf(filename, sizeof(filename), "/sys/class/net/%s/statistics/%s", interfaceStr, what);
+static jlong getData(JNIEnv* env, const char* what, jstring javaInterface) {
+ ScopedUtfChars interface(env, javaInterface);
+ if (interface.c_str() == NULL) {
+ return -1;
+ }
+ char filename[80];
+ snprintf(filename, sizeof(filename), "/sys/class/net/%s/statistics/%s", interface.c_str(), what);
return readNumber(filename);
}
diff --git a/core/jni/android_net_wifi_Wifi.cpp b/core/jni/android_net_wifi_Wifi.cpp
index 494dc27f5616..9d17fe9a200e 100644
--- a/core/jni/android_net_wifi_Wifi.cpp
+++ b/core/jni/android_net_wifi_Wifi.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "wifi"
#include "jni.h"
+#include <ScopedUtfChars.h>
#include <utils/misc.h>
#include <android_runtime/AndroidRuntime.h>
#include <utils/Log.h>
@@ -47,82 +48,100 @@ static int doCommand(const char *cmd, char *replybuf, int replybuflen)
}
}
-static jint doIntCommand(const char *cmd)
+static jint doIntCommand(const char* fmt, ...)
{
+ char buf[BUF_SIZE];
+ va_list args;
+ va_start(args, fmt);
+ int byteCount = vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+ if (byteCount < 0 || byteCount >= BUF_SIZE) {
+ return -1;
+ }
char reply[BUF_SIZE];
-
- if (doCommand(cmd, reply, sizeof(reply)) != 0) {
- return (jint)-1;
- } else {
- return (jint)atoi(reply);
+ if (doCommand(buf, reply, sizeof(reply)) != 0) {
+ return -1;
}
+ return static_cast<jint>(atoi(reply));
}
-static jboolean doBooleanCommand(const char *cmd, const char *expect)
+static jboolean doBooleanCommand(const char* expect, const char* fmt, ...)
{
+ char buf[BUF_SIZE];
+ va_list args;
+ va_start(args, fmt);
+ int byteCount = vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+ if (byteCount < 0 || byteCount >= BUF_SIZE) {
+ return JNI_FALSE;
+ }
char reply[BUF_SIZE];
-
- if (doCommand(cmd, reply, sizeof(reply)) != 0) {
- return (jboolean)JNI_FALSE;
- } else {
- return (jboolean)(strcmp(reply, expect) == 0);
+ if (doCommand(buf, reply, sizeof(reply)) != 0) {
+ return JNI_FALSE;
}
+ return (strcmp(reply, expect) == 0);
}
// Send a command to the supplicant, and return the reply as a String
-static jstring doStringCommand(JNIEnv *env, const char *cmd)
-{
+static jstring doStringCommand(JNIEnv* env, const char* fmt, ...) {
+ char buf[BUF_SIZE];
+ va_list args;
+ va_start(args, fmt);
+ int byteCount = vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+ if (byteCount < 0 || byteCount >= BUF_SIZE) {
+ return NULL;
+ }
char reply[4096];
-
- if (doCommand(cmd, reply, sizeof(reply)) != 0) {
- return env->NewStringUTF(NULL);
- } else {
- String16 str((char *)reply);
- return env->NewString((const jchar *)str.string(), str.size());
+ if (doCommand(buf, reply, sizeof(reply)) != 0) {
+ return NULL;
}
+ // TODO: why not just NewStringUTF?
+ String16 str((char *)reply);
+ return env->NewString((const jchar *)str.string(), str.size());
}
-static jboolean android_net_wifi_isDriverLoaded(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_isDriverLoaded(JNIEnv* env, jobject)
{
return (jboolean)(::is_wifi_driver_loaded() == 1);
}
-static jboolean android_net_wifi_loadDriver(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_loadDriver(JNIEnv* env, jobject)
{
return (jboolean)(::wifi_load_driver() == 0);
}
-static jboolean android_net_wifi_unloadDriver(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_unloadDriver(JNIEnv* env, jobject)
{
return (jboolean)(::wifi_unload_driver() == 0);
}
-static jboolean android_net_wifi_startSupplicant(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_startSupplicant(JNIEnv* env, jobject)
{
return (jboolean)(::wifi_start_supplicant() == 0);
}
-static jboolean android_net_wifi_stopSupplicant(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_stopSupplicant(JNIEnv* env, jobject)
{
- return doBooleanCommand("TERMINATE", "OK");
+ return doBooleanCommand("OK", "TERMINATE");
}
-static jboolean android_net_wifi_killSupplicant(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_killSupplicant(JNIEnv* env, jobject)
{
return (jboolean)(::wifi_stop_supplicant() == 0);
}
-static jboolean android_net_wifi_connectToSupplicant(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_connectToSupplicant(JNIEnv* env, jobject)
{
return (jboolean)(::wifi_connect_to_supplicant() == 0);
}
-static void android_net_wifi_closeSupplicantConnection(JNIEnv* env, jobject clazz)
+static void android_net_wifi_closeSupplicantConnection(JNIEnv* env, jobject)
{
::wifi_close_supplicant_connection();
}
-static jstring android_net_wifi_waitForEvent(JNIEnv* env, jobject clazz)
+static jstring android_net_wifi_waitForEvent(JNIEnv* env, jobject)
{
char buf[BUF_SIZE];
@@ -130,197 +149,143 @@ static jstring android_net_wifi_waitForEvent(JNIEnv* env, jobject clazz)
if (nread > 0) {
return env->NewStringUTF(buf);
} else {
- return env->NewStringUTF(NULL);
+ return NULL;
}
}
-static jstring android_net_wifi_listNetworksCommand(JNIEnv* env, jobject clazz)
+static jstring android_net_wifi_listNetworksCommand(JNIEnv* env, jobject)
{
return doStringCommand(env, "LIST_NETWORKS");
}
-static jint android_net_wifi_addNetworkCommand(JNIEnv* env, jobject clazz)
+static jint android_net_wifi_addNetworkCommand(JNIEnv* env, jobject)
{
return doIntCommand("ADD_NETWORK");
}
-static jboolean android_net_wifi_wpsPbcCommand(JNIEnv* env, jobject clazz, jstring bssid)
+static jboolean android_net_wifi_wpsPbcCommand(JNIEnv* env, jobject, jstring javaBssid)
{
- char cmdstr[BUF_SIZE];
- jboolean isCopy;
-
- const char *bssidStr = env->GetStringUTFChars(bssid, &isCopy);
- int numWritten = snprintf(cmdstr, sizeof(cmdstr), "WPS_PBC %s", bssidStr);
- env->ReleaseStringUTFChars(bssid, bssidStr);
-
- if ((numWritten == -1) || (numWritten >= sizeof(cmdstr))) {
- return false;
+ ScopedUtfChars bssid(env, javaBssid);
+ if (bssid.c_str() == NULL) {
+ return JNI_FALSE;
}
- return doBooleanCommand(cmdstr, "OK");
+ return doBooleanCommand("OK", "WPS_PBC %s", bssid.c_str());
}
-static jboolean android_net_wifi_wpsPinFromAccessPointCommand(JNIEnv* env, jobject clazz,
- jstring bssid, jstring apPin)
+static jboolean android_net_wifi_wpsPinFromAccessPointCommand(JNIEnv* env, jobject,
+ jstring javaBssid, jstring javaApPin)
{
- char cmdstr[BUF_SIZE];
- jboolean isCopy;
-
- const char *bssidStr = env->GetStringUTFChars(bssid, &isCopy);
- const char *apPinStr = env->GetStringUTFChars(apPin, &isCopy);
- int numWritten = snprintf(cmdstr, sizeof(cmdstr), "WPS_REG %s %s", bssidStr, apPinStr);
- env->ReleaseStringUTFChars(bssid, bssidStr);
- env->ReleaseStringUTFChars(apPin, apPinStr);
-
- if ((numWritten == -1) || (numWritten >= (int)sizeof(cmdstr))) {
- return false;
+ ScopedUtfChars bssid(env, javaBssid);
+ if (bssid.c_str() == NULL) {
+ return JNI_FALSE;
+ }
+ ScopedUtfChars apPin(env, javaApPin);
+ if (apPin.c_str() == NULL) {
+ return JNI_FALSE;
}
- return doBooleanCommand(cmdstr, "OK");
+ return doBooleanCommand("OK", "WPS_REG %s %s", bssid.c_str(), apPin.c_str());
}
-static jstring android_net_wifi_wpsPinFromDeviceCommand(JNIEnv* env, jobject clazz, jstring bssid)
+static jstring android_net_wifi_wpsPinFromDeviceCommand(JNIEnv* env, jobject, jstring javaBssid)
{
- char cmdstr[BUF_SIZE];
- jboolean isCopy;
-
- const char *bssidStr = env->GetStringUTFChars(bssid, &isCopy);
- int numWritten = snprintf(cmdstr, sizeof(cmdstr), "WPS_PIN %s", bssidStr);
- env->ReleaseStringUTFChars(bssid, bssidStr);
-
- if ((numWritten == -1) || (numWritten >= (int)sizeof(cmdstr))) {
+ ScopedUtfChars bssid(env, javaBssid);
+ if (bssid.c_str() == NULL) {
return NULL;
}
- return doStringCommand(env, cmdstr);
+ return doStringCommand(env, "WPS_PIN %s", bssid.c_str());
}
-static jboolean android_net_wifi_setCountryCodeCommand(JNIEnv* env, jobject clazz, jstring country)
+static jboolean android_net_wifi_setCountryCodeCommand(JNIEnv* env, jobject, jstring javaCountry)
{
- char cmdstr[BUF_SIZE];
- jboolean isCopy;
-
- const char *countryStr = env->GetStringUTFChars(country, &isCopy);
- int numWritten = snprintf(cmdstr, sizeof(cmdstr), "DRIVER COUNTRY %s", countryStr);
- env->ReleaseStringUTFChars(country, countryStr);
-
- if ((numWritten == -1) || (numWritten >= (int)sizeof(cmdstr))) {
- return false;
+ ScopedUtfChars country(env, javaCountry);
+ if (country.c_str() == NULL) {
+ return JNI_FALSE;
}
- return doBooleanCommand(cmdstr, "OK");
+ return doBooleanCommand("OK", "DRIVER COUNTRY %s", country.c_str());
}
static jboolean android_net_wifi_setNetworkVariableCommand(JNIEnv* env,
- jobject clazz,
+ jobject,
jint netId,
- jstring name,
- jstring value)
+ jstring javaName,
+ jstring javaValue)
{
- char cmdstr[BUF_SIZE];
- jboolean isCopy;
-
- const char *nameStr = env->GetStringUTFChars(name, &isCopy);
- const char *valueStr = env->GetStringUTFChars(value, &isCopy);
-
- if (nameStr == NULL || valueStr == NULL)
+ ScopedUtfChars name(env, javaName);
+ if (name.c_str() == NULL) {
return JNI_FALSE;
-
- int cmdTooLong = snprintf(cmdstr, sizeof(cmdstr), "SET_NETWORK %d %s %s",
- netId, nameStr, valueStr) >= (int)sizeof(cmdstr);
-
- env->ReleaseStringUTFChars(name, nameStr);
- env->ReleaseStringUTFChars(value, valueStr);
-
- return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+ }
+ ScopedUtfChars value(env, javaValue);
+ if (value.c_str() == NULL) {
+ return JNI_FALSE;
+ }
+ return doBooleanCommand("OK", "SET_NETWORK %d %s %s", netId, name.c_str(), value.c_str());
}
static jstring android_net_wifi_getNetworkVariableCommand(JNIEnv* env,
- jobject clazz,
+ jobject,
jint netId,
- jstring name)
+ jstring javaName)
{
- char cmdstr[BUF_SIZE];
- jboolean isCopy;
-
- const char *nameStr = env->GetStringUTFChars(name, &isCopy);
-
- if (nameStr == NULL)
- return env->NewStringUTF(NULL);
-
- int cmdTooLong = snprintf(cmdstr, sizeof(cmdstr), "GET_NETWORK %d %s",
- netId, nameStr) >= (int)sizeof(cmdstr);
-
- env->ReleaseStringUTFChars(name, nameStr);
-
- return cmdTooLong ? env->NewStringUTF(NULL) : doStringCommand(env, cmdstr);
+ ScopedUtfChars name(env, javaName);
+ if (name.c_str() == NULL) {
+ return NULL;
+ }
+ return doStringCommand(env, "GET_NETWORK %d %s", netId, name.c_str());
}
-static jboolean android_net_wifi_removeNetworkCommand(JNIEnv* env, jobject clazz, jint netId)
+static jboolean android_net_wifi_removeNetworkCommand(JNIEnv* env, jobject, jint netId)
{
- char cmdstr[BUF_SIZE];
-
- int numWritten = snprintf(cmdstr, sizeof(cmdstr), "REMOVE_NETWORK %d", netId);
- int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
-
- return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+ return doBooleanCommand("OK", "REMOVE_NETWORK %d", netId);
}
static jboolean android_net_wifi_enableNetworkCommand(JNIEnv* env,
- jobject clazz,
+ jobject,
jint netId,
jboolean disableOthers)
{
- char cmdstr[BUF_SIZE];
- const char *cmd = disableOthers ? "SELECT_NETWORK" : "ENABLE_NETWORK";
-
- int numWritten = snprintf(cmdstr, sizeof(cmdstr), "%s %d", cmd, netId);
- int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
-
- return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+ return doBooleanCommand("OK", "%s_NETWORK %d", disableOthers ? "SELECT" : "ENABLE", netId);
}
-static jboolean android_net_wifi_disableNetworkCommand(JNIEnv* env, jobject clazz, jint netId)
+static jboolean android_net_wifi_disableNetworkCommand(JNIEnv* env, jobject, jint netId)
{
- char cmdstr[BUF_SIZE];
-
- int numWritten = snprintf(cmdstr, sizeof(cmdstr), "DISABLE_NETWORK %d", netId);
- int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
-
- return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+ return doBooleanCommand("OK", "DISABLE_NETWORK %d", netId);
}
-static jstring android_net_wifi_statusCommand(JNIEnv* env, jobject clazz)
+static jstring android_net_wifi_statusCommand(JNIEnv* env, jobject)
{
return doStringCommand(env, "STATUS");
}
-static jboolean android_net_wifi_pingCommand(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_pingCommand(JNIEnv* env, jobject)
{
- return doBooleanCommand("PING", "PONG");
+ return doBooleanCommand("PONG", "PING");
}
-static jstring android_net_wifi_scanResultsCommand(JNIEnv* env, jobject clazz)
+static jstring android_net_wifi_scanResultsCommand(JNIEnv* env, jobject)
{
return doStringCommand(env, "SCAN_RESULTS");
}
-static jboolean android_net_wifi_disconnectCommand(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_disconnectCommand(JNIEnv* env, jobject)
{
- return doBooleanCommand("DISCONNECT", "OK");
+ return doBooleanCommand("OK", "DISCONNECT");
}
-static jboolean android_net_wifi_reconnectCommand(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_reconnectCommand(JNIEnv* env, jobject)
{
- return doBooleanCommand("RECONNECT", "OK");
+ return doBooleanCommand("OK", "RECONNECT");
}
-static jboolean android_net_wifi_reassociateCommand(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_reassociateCommand(JNIEnv* env, jobject)
{
- return doBooleanCommand("REASSOCIATE", "OK");
+ return doBooleanCommand("OK", "REASSOCIATE");
}
static jboolean doSetScanMode(jboolean setActive)
{
- return doBooleanCommand((setActive ? "DRIVER SCAN-ACTIVE" : "DRIVER SCAN-PASSIVE"), "OK");
+ return doBooleanCommand("OK", (setActive ? "DRIVER SCAN-ACTIVE" : "DRIVER SCAN-PASSIVE"));
}
-static jboolean android_net_wifi_scanCommand(JNIEnv* env, jobject clazz, jboolean forceActive)
+static jboolean android_net_wifi_scanCommand(JNIEnv* env, jobject, jboolean forceActive)
{
jboolean result;
@@ -328,43 +293,43 @@ static jboolean android_net_wifi_scanCommand(JNIEnv* env, jobject clazz, jboolea
// The scan will still work.
if (forceActive && !sScanModeActive)
doSetScanMode(true);
- result = doBooleanCommand("SCAN", "OK");
+ result = doBooleanCommand("OK", "SCAN");
if (forceActive && !sScanModeActive)
doSetScanMode(sScanModeActive);
return result;
}
-static jboolean android_net_wifi_setScanModeCommand(JNIEnv* env, jobject clazz, jboolean setActive)
+static jboolean android_net_wifi_setScanModeCommand(JNIEnv* env, jobject, jboolean setActive)
{
sScanModeActive = setActive;
return doSetScanMode(setActive);
}
-static jboolean android_net_wifi_startDriverCommand(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_startDriverCommand(JNIEnv* env, jobject)
{
- return doBooleanCommand("DRIVER START", "OK");
+ return doBooleanCommand("OK", "DRIVER START");
}
-static jboolean android_net_wifi_stopDriverCommand(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_stopDriverCommand(JNIEnv* env, jobject)
{
- return doBooleanCommand("DRIVER STOP", "OK");
+ return doBooleanCommand("OK", "DRIVER STOP");
}
-static jboolean android_net_wifi_startPacketFiltering(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_startPacketFiltering(JNIEnv* env, jobject)
{
- return doBooleanCommand("DRIVER RXFILTER-ADD 0", "OK")
- && doBooleanCommand("DRIVER RXFILTER-ADD 1", "OK")
- && doBooleanCommand("DRIVER RXFILTER-ADD 3", "OK")
- && doBooleanCommand("DRIVER RXFILTER-START", "OK");
+ return doBooleanCommand("OK", "DRIVER RXFILTER-ADD 0")
+ && doBooleanCommand("OK", "DRIVER RXFILTER-ADD 1")
+ && doBooleanCommand("OK", "DRIVER RXFILTER-ADD 3")
+ && doBooleanCommand("OK", "DRIVER RXFILTER-START");
}
-static jboolean android_net_wifi_stopPacketFiltering(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_stopPacketFiltering(JNIEnv* env, jobject)
{
- jboolean result = doBooleanCommand("DRIVER RXFILTER-STOP", "OK");
+ jboolean result = doBooleanCommand("OK", "DRIVER RXFILTER-STOP");
if (result) {
- (void)doBooleanCommand("DRIVER RXFILTER-REMOVE 3", "OK");
- (void)doBooleanCommand("DRIVER RXFILTER-REMOVE 1", "OK");
- (void)doBooleanCommand("DRIVER RXFILTER-REMOVE 0", "OK");
+ (void)doBooleanCommand("OK", "DRIVER RXFILTER-REMOVE 3");
+ (void)doBooleanCommand("OK", "DRIVER RXFILTER-REMOVE 1");
+ (void)doBooleanCommand("OK", "DRIVER RXFILTER-REMOVE 0");
}
return result;
@@ -399,17 +364,17 @@ static jint android_net_wifi_getRssiHelper(const char *cmd)
return (jint)rssi;
}
-static jint android_net_wifi_getRssiCommand(JNIEnv* env, jobject clazz)
+static jint android_net_wifi_getRssiCommand(JNIEnv* env, jobject)
{
return android_net_wifi_getRssiHelper("DRIVER RSSI");
}
-static jint android_net_wifi_getRssiApproxCommand(JNIEnv* env, jobject clazz)
+static jint android_net_wifi_getRssiApproxCommand(JNIEnv* env, jobject)
{
return android_net_wifi_getRssiHelper("DRIVER RSSI-APPROX");
}
-static jint android_net_wifi_getLinkSpeedCommand(JNIEnv* env, jobject clazz)
+static jint android_net_wifi_getLinkSpeedCommand(JNIEnv* env, jobject)
{
char reply[BUF_SIZE];
int linkspeed;
@@ -423,33 +388,28 @@ static jint android_net_wifi_getLinkSpeedCommand(JNIEnv* env, jobject clazz)
return (jint)linkspeed;
}
-static jstring android_net_wifi_getMacAddressCommand(JNIEnv* env, jobject clazz)
+static jstring android_net_wifi_getMacAddressCommand(JNIEnv* env, jobject)
{
char reply[BUF_SIZE];
char buf[BUF_SIZE];
if (doCommand("DRIVER MACADDR", reply, sizeof(reply)) != 0) {
- return env->NewStringUTF(NULL);
+ return NULL;
}
// reply comes back in the form "Macaddr = XX.XX.XX.XX.XX.XX" where XX
// is the part of the string we're interested in.
- if (sscanf(reply, "%*s = %255s", buf) == 1)
+ if (sscanf(reply, "%*s = %255s", buf) == 1) {
return env->NewStringUTF(buf);
- else
- return env->NewStringUTF(NULL);
+ }
+ return NULL;
}
-static jboolean android_net_wifi_setPowerModeCommand(JNIEnv* env, jobject clazz, jint mode)
+static jboolean android_net_wifi_setPowerModeCommand(JNIEnv* env, jobject, jint mode)
{
- char cmdstr[BUF_SIZE];
-
- int numWritten = snprintf(cmdstr, sizeof(cmdstr), "DRIVER POWERMODE %d", mode);
- int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
-
- return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+ return doBooleanCommand("OK", "DRIVER POWERMODE %d", mode);
}
-static jint android_net_wifi_getPowerModeCommand(JNIEnv* env, jobject clazz)
+static jint android_net_wifi_getPowerModeCommand(JNIEnv* env, jobject)
{
char reply[BUF_SIZE];
int power;
@@ -463,17 +423,12 @@ static jint android_net_wifi_getPowerModeCommand(JNIEnv* env, jobject clazz)
return (jint)power;
}
-static jboolean android_net_wifi_setBandCommand(JNIEnv* env, jobject clazz, jint band)
+static jboolean android_net_wifi_setBandCommand(JNIEnv* env, jobject, jint band)
{
- char cmdstr[25];
-
- int numWritten = snprintf(cmdstr, sizeof(cmdstr), "DRIVER SETBAND %d", band);
- int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
-
- return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+ return doBooleanCommand("OK", "DRIVER SETBAND %d", band);
}
-static jint android_net_wifi_getBandCommand(JNIEnv* env, jobject clazz)
+static jint android_net_wifi_getBandCommand(JNIEnv* env, jobject)
{
char reply[25];
int band;
@@ -487,94 +442,66 @@ static jint android_net_wifi_getBandCommand(JNIEnv* env, jobject clazz)
return (jint)band;
}
-static jboolean android_net_wifi_setBluetoothCoexistenceModeCommand(JNIEnv* env, jobject clazz, jint mode)
+static jboolean android_net_wifi_setBluetoothCoexistenceModeCommand(JNIEnv* env, jobject, jint mode)
{
- char cmdstr[BUF_SIZE];
-
- int numWritten = snprintf(cmdstr, sizeof(cmdstr), "DRIVER BTCOEXMODE %d", mode);
- int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
-
- return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+ return doBooleanCommand("OK", "DRIVER BTCOEXMODE %d", mode);
}
-static jboolean android_net_wifi_setBluetoothCoexistenceScanModeCommand(JNIEnv* env, jobject clazz, jboolean setCoexScanMode)
+static jboolean android_net_wifi_setBluetoothCoexistenceScanModeCommand(JNIEnv* env, jobject, jboolean setCoexScanMode)
{
- char cmdstr[BUF_SIZE];
-
- int numWritten = snprintf(cmdstr, sizeof(cmdstr), "DRIVER BTCOEXSCAN-%s", setCoexScanMode ? "START" : "STOP");
- int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
-
- return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+ return doBooleanCommand("OK", "DRIVER BTCOEXSCAN-%s", setCoexScanMode ? "START" : "STOP");
}
-static jboolean android_net_wifi_saveConfigCommand(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_saveConfigCommand(JNIEnv* env, jobject)
{
// Make sure we never write out a value for AP_SCAN other than 1
- (void)doBooleanCommand("AP_SCAN 1", "OK");
- return doBooleanCommand("SAVE_CONFIG", "OK");
+ (void)doBooleanCommand("OK", "AP_SCAN 1");
+ return doBooleanCommand("OK", "SAVE_CONFIG");
}
-static jboolean android_net_wifi_reloadConfigCommand(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_reloadConfigCommand(JNIEnv* env, jobject)
{
- return doBooleanCommand("RECONFIGURE", "OK");
+ return doBooleanCommand("OK", "RECONFIGURE");
}
-static jboolean android_net_wifi_setScanResultHandlingCommand(JNIEnv* env, jobject clazz, jint mode)
+static jboolean android_net_wifi_setScanResultHandlingCommand(JNIEnv* env, jobject, jint mode)
{
- char cmdstr[BUF_SIZE];
-
- int numWritten = snprintf(cmdstr, sizeof(cmdstr), "AP_SCAN %d", mode);
- int cmdTooLong = numWritten >= (int)sizeof(cmdstr);
-
- return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+ return doBooleanCommand("OK", "AP_SCAN %d", mode);
}
-static jboolean android_net_wifi_addToBlacklistCommand(JNIEnv* env, jobject clazz, jstring bssid)
+static jboolean android_net_wifi_addToBlacklistCommand(JNIEnv* env, jobject, jstring javaBssid)
{
- char cmdstr[BUF_SIZE];
- jboolean isCopy;
-
- const char *bssidStr = env->GetStringUTFChars(bssid, &isCopy);
-
- int cmdTooLong = snprintf(cmdstr, sizeof(cmdstr), "BLACKLIST %s", bssidStr) >= (int)sizeof(cmdstr);
-
- env->ReleaseStringUTFChars(bssid, bssidStr);
-
- return (jboolean)!cmdTooLong && doBooleanCommand(cmdstr, "OK");
+ ScopedUtfChars bssid(env, javaBssid);
+ if (bssid.c_str() == NULL) {
+ return JNI_FALSE;
+ }
+ return doBooleanCommand("OK", "BLACKLIST %s", bssid.c_str());
}
-static jboolean android_net_wifi_clearBlacklistCommand(JNIEnv* env, jobject clazz)
+static jboolean android_net_wifi_clearBlacklistCommand(JNIEnv* env, jobject)
{
- return doBooleanCommand("BLACKLIST clear", "OK");
+ return doBooleanCommand("OK", "BLACKLIST clear");
}
-static jboolean android_net_wifi_setSuspendOptimizationsCommand(JNIEnv* env, jobject clazz, jboolean enabled)
+static jboolean android_net_wifi_setSuspendOptimizationsCommand(JNIEnv* env, jobject, jboolean enabled)
{
- char cmdstr[BUF_SIZE];
-
- snprintf(cmdstr, sizeof(cmdstr), "DRIVER SETSUSPENDOPT %d", enabled ? 0 : 1);
- return doBooleanCommand(cmdstr, "OK");
+ return doBooleanCommand("OK", "DRIVER SETSUSPENDOPT %d", enabled ? 0 : 1);
}
-static void android_net_wifi_enableBackgroundScanCommand(JNIEnv* env, jobject clazz, jboolean enable)
+static void android_net_wifi_enableBackgroundScanCommand(JNIEnv* env, jobject, jboolean enable)
{
//Note: BGSCAN-START and BGSCAN-STOP are documented in core/res/res/values/config.xml
//and will need an update if the names are changed
if (enable) {
- doBooleanCommand("DRIVER BGSCAN-START", "OK");
- }
- else {
- doBooleanCommand("DRIVER BGSCAN-STOP", "OK");
+ doBooleanCommand("OK", "DRIVER BGSCAN-START");
+ } else {
+ doBooleanCommand("OK", "DRIVER BGSCAN-STOP");
}
}
-static void android_net_wifi_setScanIntervalCommand(JNIEnv* env, jobject clazz, jint scanInterval)
+static void android_net_wifi_setScanIntervalCommand(JNIEnv* env, jobject, jint scanInterval)
{
- char cmdstr[BUF_SIZE];
-
- int numWritten = snprintf(cmdstr, sizeof(cmdstr), "SCAN_INTERVAL %d", scanInterval);
-
- if(numWritten < (int)sizeof(cmdstr)) doBooleanCommand(cmdstr, "OK");
+ doBooleanCommand("OK", "SCAN_INTERVAL %d", scanInterval);
}
@@ -651,9 +578,6 @@ static JNINativeMethod gWifiMethods[] = {
int register_android_net_wifi_WifiManager(JNIEnv* env)
{
- jclass wifi = env->FindClass(WIFI_PKG_NAME);
- LOG_FATAL_IF(wifi == NULL, "Unable to find class " WIFI_PKG_NAME);
-
return AndroidRuntime::registerNativeMethods(env,
WIFI_PKG_NAME, gWifiMethods, NELEM(gWifiMethods));
}
diff --git a/core/jni/android_nio_utils.cpp b/core/jni/android_nio_utils.cpp
index 584e7a43ccd9..7cbbe124527b 100644
--- a/core/jni/android_nio_utils.cpp
+++ b/core/jni/android_nio_utils.cpp
@@ -32,20 +32,20 @@ void* android::nio_getPointer(JNIEnv *_env, jobject buffer, jarray *array) {
jlong pointer;
jint offset;
void *data;
-
+
pointer = _env->CallStaticLongMethod(gNioJNI.nioAccessClass,
gNioJNI.getBasePointerID, buffer);
if (pointer != 0L) {
*array = NULL;
return (void *) (jint) pointer;
}
-
+
*array = (jarray) _env->CallStaticObjectMethod(gNioJNI.nioAccessClass,
gNioJNI.getBaseArrayID, buffer);
offset = _env->CallStaticIntMethod(gNioJNI.nioAccessClass,
gNioJNI.getBaseArrayOffsetID, buffer);
data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-
+
return (void *) ((char *) data + offset);
}
@@ -94,8 +94,7 @@ static jfieldID getFieldID(JNIEnv* env, jclass c, const char name[],
}
namespace android {
-
-int register_android_nio_utils(JNIEnv* env);
+
int register_android_nio_utils(JNIEnv* env) {
jclass localClass = findClass(env, "java/nio/NIOAccess");
gNioJNI.getBasePointerID = findStaticMethod(env, localClass,
diff --git a/core/jni/android_opengl_GLES10.cpp b/core/jni/android_opengl_GLES10.cpp
index 2685d7595e32..6c29d6c3df46 100644
--- a/core/jni/android_opengl_GLES10.cpp
+++ b/core/jni/android_opengl_GLES10.cpp
@@ -2,21 +2,23 @@
**
** Copyright 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
+** 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
+** 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
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
// This source file is automatically generated
+#include "jni.h"
+#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
@@ -41,10 +43,6 @@ static int initialized = 0;
static jclass nioAccessClass;
static jclass bufferClass;
-static jclass OOMEClass;
-static jclass UOEClass;
-static jclass IAEClass;
-static jclass AIOOBEClass;
static jmethodID getBasePointerID;
static jmethodID getBaseArrayID;
static jmethodID getBaseArrayOffsetID;
@@ -55,7 +53,7 @@ static jfieldID elementSizeShiftID;
/* Cache method IDs each time the class is loaded. */
static void
-nativeClassInitBuffer(JNIEnv *_env)
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
{
jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
@@ -76,26 +74,6 @@ nativeClassInitBuffer(JNIEnv *_env)
_env->GetFieldID(bufferClass, "_elementSizeShift", "I");
}
-static void
-nativeClassInit(JNIEnv *_env, jclass glImplClass)
-{
- nativeClassInitBuffer(_env);
-
- jclass IAEClassLocal =
- _env->FindClass("java/lang/IllegalArgumentException");
- jclass OOMEClassLocal =
- _env->FindClass("java/lang/OutOfMemoryError");
- jclass UOEClassLocal =
- _env->FindClass("java/lang/UnsupportedOperationException");
- jclass AIOOBEClassLocal =
- _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
-
- IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
- OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
- UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
- AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
-}
-
static void *
getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
{
@@ -116,13 +94,13 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
*array = NULL;
return (void *) (jint) pointer;
}
-
+
*array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
getBaseArrayID, buffer);
offset = _env->CallStaticIntMethod(nioAccessClass,
getBaseArrayOffsetID, buffer);
data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-
+
return (void *) ((char *) data + offset);
}
@@ -141,7 +119,8 @@ getDirectBufferPointer(JNIEnv *_env, jobject buffer) {
jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
buf += position << elementSizeShift;
} else {
- _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+ jniThrowException(_env, "java/lang/IllegalArgumentException",
+ "Must use a native order direct Buffer");
}
return (void*) buf;
}
@@ -154,7 +133,6 @@ getNumCompressedTextureFormats() {
}
// --------------------------------------------------------------------------
-
/* void glActiveTexture ( GLenum texture ) */
static void
android_glActiveTexture__I
@@ -431,16 +409,16 @@ android_glDeleteTextures__I_3II
GLuint *textures = (GLuint *) 0;
if (!textures_ref) {
- _env->ThrowNew(IAEClass, "textures == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "textures == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(textures_ref) - offset;
if (_remaining < n) {
- _env->ThrowNew(IAEClass, "length - offset < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
goto exit;
}
textures_base = (GLuint *)
@@ -469,7 +447,7 @@ android_glDeleteTextures__ILjava_nio_IntBuffer_2
textures = (GLuint *)getPointer(_env, textures_buf, &_array, &_remaining);
if (_remaining < n) {
- _env->ThrowNew(IAEClass, "remaining() < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
goto exit;
}
glDeleteTextures(
@@ -560,7 +538,7 @@ android_glDrawElements__IIILjava_nio_Buffer_2
indices = (GLvoid *)getPointer(_env, indices_buf, &_array, &_remaining);
if (_remaining < count) {
- _env->ThrowNew(AIOOBEClass, "remaining() < count");
+ jniThrowException(_env, "java/lang/ArrayIndexOutOfBoundsException", "remaining() < count");
goto exit;
}
glDrawElements(
@@ -627,11 +605,11 @@ android_glFogfv__I_3FI
GLfloat *params = (GLfloat *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -661,7 +639,7 @@ android_glFogfv__I_3FI
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLfloat *)
@@ -715,7 +693,7 @@ android_glFogfv__ILjava_nio_FloatBuffer_2
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glFogfv(
@@ -748,11 +726,11 @@ android_glFogxv__I_3II
GLfixed *params = (GLfixed *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -782,7 +760,7 @@ android_glFogxv__I_3II
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLfixed *)
@@ -836,7 +814,7 @@ android_glFogxv__ILjava_nio_IntBuffer_2
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glFogxv(
@@ -898,18 +876,18 @@ android_glGenTextures__I_3II
if (!textures_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "textures == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "textures == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(textures_ref) - offset;
if (_remaining < n) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
goto exit;
}
textures_base = (GLuint *)
@@ -940,7 +918,7 @@ android_glGenTextures__ILjava_nio_IntBuffer_2
textures = (GLuint *)getPointer(_env, textures_buf, &_array, &_remaining);
if (_remaining < n) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
goto exit;
}
glGenTextures(
@@ -974,12 +952,12 @@ android_glGetIntegerv__I_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1316,7 +1294,7 @@ android_glGetIntegerv__I_3II
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLint *)
@@ -1678,7 +1656,7 @@ android_glGetIntegerv__ILjava_nio_IntBuffer_2
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glGetIntegerv(
@@ -1692,16 +1670,10 @@ exit:
}
}
-#include <string.h>
-
/* const GLubyte * glGetString ( GLenum name ) */
-static
-jstring
-android_glGetString
- (JNIEnv *_env, jobject _this, jint name) {
- const char * chars = (const char *)glGetString((GLenum)name);
- jstring output = _env->NewStringUTF(chars);
- return output;
+static jstring android_glGetString(JNIEnv* _env, jobject, jint name) {
+ const char* chars = (const char*) glGetString((GLenum) name);
+ return _env->NewStringUTF(chars);
}
/* void glHint ( GLenum target, GLenum mode ) */
static void
@@ -1732,11 +1704,11 @@ android_glLightModelfv__I_3FI
GLfloat *params = (GLfloat *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1757,7 +1729,7 @@ android_glLightModelfv__I_3FI
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLfloat *)
@@ -1802,7 +1774,7 @@ android_glLightModelfv__ILjava_nio_FloatBuffer_2
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glLightModelfv(
@@ -1835,11 +1807,11 @@ android_glLightModelxv__I_3II
GLfixed *params = (GLfixed *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1860,7 +1832,7 @@ android_glLightModelxv__I_3II
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLfixed *)
@@ -1905,7 +1877,7 @@ android_glLightModelxv__ILjava_nio_IntBuffer_2
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glLightModelxv(
@@ -1939,11 +1911,11 @@ android_glLightfv__II_3FI
GLfloat *params = (GLfloat *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1990,7 +1962,7 @@ android_glLightfv__II_3FI
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLfloat *)
@@ -2062,7 +2034,7 @@ android_glLightfv__IILjava_nio_FloatBuffer_2
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glLightfv(
@@ -2097,11 +2069,11 @@ android_glLightxv__II_3II
GLfixed *params = (GLfixed *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2148,7 +2120,7 @@ android_glLightxv__II_3II
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLfixed *)
@@ -2220,7 +2192,7 @@ android_glLightxv__IILjava_nio_IntBuffer_2
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glLightxv(
@@ -2269,11 +2241,11 @@ android_glLoadMatrixf___3FI
GLfloat *m = (GLfloat *) 0;
if (!m_ref) {
- _env->ThrowNew(IAEClass, "m == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "m == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(m_ref) - offset;
@@ -2318,11 +2290,11 @@ android_glLoadMatrixx___3II
GLfixed *m = (GLfixed *) 0;
if (!m_ref) {
- _env->ThrowNew(IAEClass, "m == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "m == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(m_ref) - offset;
@@ -2387,11 +2359,11 @@ android_glMaterialfv__II_3FI
GLfloat *params = (GLfloat *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2424,7 +2396,7 @@ android_glMaterialfv__II_3FI
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLfloat *)
@@ -2482,7 +2454,7 @@ android_glMaterialfv__IILjava_nio_FloatBuffer_2
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glMaterialfv(
@@ -2517,11 +2489,11 @@ android_glMaterialxv__II_3II
GLfixed *params = (GLfixed *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2554,7 +2526,7 @@ android_glMaterialxv__II_3II
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLfixed *)
@@ -2612,7 +2584,7 @@ android_glMaterialxv__IILjava_nio_IntBuffer_2
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glMaterialxv(
@@ -2645,11 +2617,11 @@ android_glMultMatrixf___3FI
GLfloat *m = (GLfloat *) 0;
if (!m_ref) {
- _env->ThrowNew(IAEClass, "m == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "m == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(m_ref) - offset;
@@ -2694,11 +2666,11 @@ android_glMultMatrixx___3II
GLfixed *m = (GLfixed *) 0;
if (!m_ref) {
- _env->ThrowNew(IAEClass, "m == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "m == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(m_ref) - offset;
@@ -3079,11 +3051,11 @@ android_glTexEnvfv__II_3FI
GLfloat *params = (GLfloat *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -3110,7 +3082,7 @@ android_glTexEnvfv__II_3FI
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLfloat *)
@@ -3162,7 +3134,7 @@ android_glTexEnvfv__IILjava_nio_FloatBuffer_2
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glTexEnvfv(
@@ -3197,11 +3169,11 @@ android_glTexEnvxv__II_3II
GLfixed *params = (GLfixed *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -3228,7 +3200,7 @@ android_glTexEnvxv__II_3II
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLfixed *)
@@ -3280,7 +3252,7 @@ android_glTexEnvxv__IILjava_nio_IntBuffer_2
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glTexEnvxv(
diff --git a/core/jni/android_opengl_GLES10Ext.cpp b/core/jni/android_opengl_GLES10Ext.cpp
index f17ef21a521e..1154cef2171b 100644
--- a/core/jni/android_opengl_GLES10Ext.cpp
+++ b/core/jni/android_opengl_GLES10Ext.cpp
@@ -2,21 +2,23 @@
**
** Copyright 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
+** 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
+** 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
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
// This source file is automatically generated
+#include "jni.h"
+#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
@@ -28,10 +30,6 @@ static int initialized = 0;
static jclass nioAccessClass;
static jclass bufferClass;
-static jclass OOMEClass;
-static jclass UOEClass;
-static jclass IAEClass;
-static jclass AIOOBEClass;
static jmethodID getBasePointerID;
static jmethodID getBaseArrayID;
static jmethodID getBaseArrayOffsetID;
@@ -42,7 +40,7 @@ static jfieldID elementSizeShiftID;
/* Cache method IDs each time the class is loaded. */
static void
-nativeClassInitBuffer(JNIEnv *_env)
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
{
jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
@@ -64,26 +62,6 @@ nativeClassInitBuffer(JNIEnv *_env)
}
-static void
-nativeClassInit(JNIEnv *_env, jclass glImplClass)
-{
- nativeClassInitBuffer(_env);
-
- jclass IAEClassLocal =
- _env->FindClass("java/lang/IllegalArgumentException");
- jclass OOMEClassLocal =
- _env->FindClass("java/lang/OutOfMemoryError");
- jclass UOEClassLocal =
- _env->FindClass("java/lang/UnsupportedOperationException");
- jclass AIOOBEClassLocal =
- _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
-
- IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
- OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
- UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
- AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
-}
-
static void *
getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
{
@@ -104,13 +82,13 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
*array = NULL;
return (void *) (jint) pointer;
}
-
+
*array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
getBaseArrayID, buffer);
offset = _env->CallStaticIntMethod(nioAccessClass,
getBaseArrayOffsetID, buffer);
data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-
+
return (void *) ((char *) data + offset);
}
@@ -123,7 +101,6 @@ releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit)
}
// --------------------------------------------------------------------------
-
/* GLbitfield glQueryMatrixxOES ( GLfixed *mantissa, GLint *exponent ) */
static jint
android_glQueryMatrixxOES___3II_3II
@@ -139,18 +116,18 @@ android_glQueryMatrixxOES___3II_3II
if (!mantissa_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "mantissa == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "mantissa == null");
goto exit;
}
if (mantissaOffset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "mantissaOffset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "mantissaOffset < 0");
goto exit;
}
_mantissaRemaining = _env->GetArrayLength(mantissa_ref) - mantissaOffset;
if (_mantissaRemaining < 16) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - mantissaOffset < 16");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - mantissaOffset < 16");
goto exit;
}
mantissa_base = (GLfixed *)
@@ -159,18 +136,18 @@ android_glQueryMatrixxOES___3II_3II
if (!exponent_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "exponent == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "exponent == null");
goto exit;
}
if (exponentOffset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "exponentOffset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "exponentOffset < 0");
goto exit;
}
_exponentRemaining = _env->GetArrayLength(exponent_ref) - exponentOffset;
if (_exponentRemaining < 16) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - exponentOffset < 16");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - exponentOffset < 16");
goto exit;
}
exponent_base = (GLint *)
@@ -210,13 +187,13 @@ android_glQueryMatrixxOES__Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2
mantissa = (GLfixed *)getPointer(_env, mantissa_buf, &_mantissaArray, &_mantissaRemaining);
if (_mantissaRemaining < 16) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < 16");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 16");
goto exit;
}
exponent = (GLint *)getPointer(_env, exponent_buf, &_exponentArray, &_exponentRemaining);
if (_exponentRemaining < 16) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < 16");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 16");
goto exit;
}
_returnValue = glQueryMatrixxOES(
diff --git a/core/jni/android_opengl_GLES11.cpp b/core/jni/android_opengl_GLES11.cpp
index 1c326baea293..d038f2051499 100644
--- a/core/jni/android_opengl_GLES11.cpp
+++ b/core/jni/android_opengl_GLES11.cpp
@@ -2,21 +2,23 @@
**
** Copyright 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
+** 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
+** 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
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
// This source file is automatically generated
+#include "jni.h"
+#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
@@ -35,10 +37,6 @@ static int initialized = 0;
static jclass nioAccessClass;
static jclass bufferClass;
-static jclass OOMEClass;
-static jclass UOEClass;
-static jclass IAEClass;
-static jclass AIOOBEClass;
static jmethodID getBasePointerID;
static jmethodID getBaseArrayID;
static jmethodID getBaseArrayOffsetID;
@@ -49,7 +47,7 @@ static jfieldID elementSizeShiftID;
/* Cache method IDs each time the class is loaded. */
static void
-nativeClassInitBuffer(JNIEnv *_env)
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
{
jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
@@ -71,26 +69,6 @@ nativeClassInitBuffer(JNIEnv *_env)
}
-static void
-nativeClassInit(JNIEnv *_env, jclass glImplClass)
-{
- nativeClassInitBuffer(_env);
-
- jclass IAEClassLocal =
- _env->FindClass("java/lang/IllegalArgumentException");
- jclass OOMEClassLocal =
- _env->FindClass("java/lang/OutOfMemoryError");
- jclass UOEClassLocal =
- _env->FindClass("java/lang/UnsupportedOperationException");
- jclass AIOOBEClassLocal =
- _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
-
- IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
- OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
- UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
- AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
-}
-
static void *
getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
{
@@ -111,13 +89,13 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
*array = NULL;
return (void *) (jint) pointer;
}
-
+
*array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
getBaseArrayID, buffer);
offset = _env->CallStaticIntMethod(nioAccessClass,
getBaseArrayOffsetID, buffer);
data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-
+
return (void *) ((char *) data + offset);
}
@@ -137,13 +115,13 @@ getDirectBufferPointer(JNIEnv *_env, jobject buffer) {
jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
buf += position << elementSizeShift;
} else {
- _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+ jniThrowException(_env, "java/lang/IllegalArgumentException",
+ "Must use a native order direct Buffer");
}
return (void*) buf;
}
// --------------------------------------------------------------------------
-
/* void glBindBuffer ( GLenum target, GLuint buffer ) */
static void
android_glBindBuffer__II
@@ -165,7 +143,7 @@ android_glBufferData__IILjava_nio_Buffer_2I
if (data_buf) {
data = (GLvoid *)getPointer(_env, data_buf, &_array, &_remaining);
if (_remaining < size) {
- _env->ThrowNew(IAEClass, "remaining() < size");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < size");
goto exit;
}
}
@@ -192,7 +170,7 @@ android_glBufferSubData__IIILjava_nio_Buffer_2
data = (GLvoid *)getPointer(_env, data_buf, &_array, &_remaining);
if (_remaining < size) {
- _env->ThrowNew(IAEClass, "remaining() < size");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < size");
goto exit;
}
glBufferSubData(
@@ -217,11 +195,11 @@ android_glClipPlanef__I_3FI
GLfloat *equation = (GLfloat *) 0;
if (!equation_ref) {
- _env->ThrowNew(IAEClass, "equation == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "equation == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(equation_ref) - offset;
@@ -268,11 +246,11 @@ android_glClipPlanex__I_3II
GLfixed *equation = (GLfixed *) 0;
if (!equation_ref) {
- _env->ThrowNew(IAEClass, "equation == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "equation == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(equation_ref) - offset;
@@ -343,16 +321,16 @@ android_glDeleteBuffers__I_3II
GLuint *buffers = (GLuint *) 0;
if (!buffers_ref) {
- _env->ThrowNew(IAEClass, "buffers == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "buffers == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(buffers_ref) - offset;
if (_remaining < n) {
- _env->ThrowNew(IAEClass, "length - offset < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
goto exit;
}
buffers_base = (GLuint *)
@@ -381,7 +359,7 @@ android_glDeleteBuffers__ILjava_nio_IntBuffer_2
buffers = (GLuint *)getPointer(_env, buffers_buf, &_array, &_remaining);
if (_remaining < n) {
- _env->ThrowNew(IAEClass, "remaining() < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
goto exit;
}
glDeleteBuffers(
@@ -418,18 +396,18 @@ android_glGenBuffers__I_3II
if (!buffers_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "buffers == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "buffers == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(buffers_ref) - offset;
if (_remaining < n) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
goto exit;
}
buffers_base = (GLuint *)
@@ -460,7 +438,7 @@ android_glGenBuffers__ILjava_nio_IntBuffer_2
buffers = (GLuint *)getPointer(_env, buffers_buf, &_array, &_remaining);
if (_remaining < n) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
goto exit;
}
glGenBuffers(
@@ -485,12 +463,12 @@ android_glGetBooleanv__I_3ZI
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -540,18 +518,18 @@ android_glGetBufferParameteriv__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
if (_remaining < 1) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
goto exit;
}
params_base = (GLint *)
@@ -583,7 +561,7 @@ android_glGetBufferParameteriv__IILjava_nio_IntBuffer_2
params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining);
if (_remaining < 1) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
goto exit;
}
glGetBufferParameteriv(
@@ -609,12 +587,12 @@ android_glGetClipPlanef__I_3FI
if (!eqn_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "eqn == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "eqn == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(eqn_ref) - offset;
@@ -664,12 +642,12 @@ android_glGetClipPlanex__I_3II
if (!eqn_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "eqn == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "eqn == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(eqn_ref) - offset;
@@ -719,12 +697,12 @@ android_glGetFixedv__I_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -774,12 +752,12 @@ android_glGetFloatv__I_3FI
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -829,12 +807,12 @@ android_glGetLightfv__II_3FI
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -882,7 +860,7 @@ android_glGetLightfv__II_3FI
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLfloat *)
@@ -956,7 +934,7 @@ android_glGetLightfv__IILjava_nio_FloatBuffer_2
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glGetLightfv(
@@ -982,12 +960,12 @@ android_glGetLightxv__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1035,7 +1013,7 @@ android_glGetLightxv__II_3II
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLfixed *)
@@ -1109,7 +1087,7 @@ android_glGetLightxv__IILjava_nio_IntBuffer_2
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glGetLightxv(
@@ -1135,12 +1113,12 @@ android_glGetMaterialfv__II_3FI
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1174,7 +1152,7 @@ android_glGetMaterialfv__II_3FI
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLfloat *)
@@ -1234,7 +1212,7 @@ android_glGetMaterialfv__IILjava_nio_FloatBuffer_2
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glGetMaterialfv(
@@ -1260,12 +1238,12 @@ android_glGetMaterialxv__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1299,7 +1277,7 @@ android_glGetMaterialxv__II_3II
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLfixed *)
@@ -1359,7 +1337,7 @@ android_glGetMaterialxv__IILjava_nio_IntBuffer_2
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glGetMaterialxv(
@@ -1385,12 +1363,12 @@ android_glGetTexEnvfv__II_3FI
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1418,7 +1396,7 @@ android_glGetTexEnvfv__II_3FI
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLfloat *)
@@ -1472,7 +1450,7 @@ android_glGetTexEnvfv__IILjava_nio_FloatBuffer_2
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glGetTexEnvfv(
@@ -1498,12 +1476,12 @@ android_glGetTexEnviv__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1531,7 +1509,7 @@ android_glGetTexEnviv__II_3II
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLint *)
@@ -1585,7 +1563,7 @@ android_glGetTexEnviv__IILjava_nio_IntBuffer_2
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glGetTexEnviv(
@@ -1611,12 +1589,12 @@ android_glGetTexEnvxv__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1644,7 +1622,7 @@ android_glGetTexEnvxv__II_3II
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLfixed *)
@@ -1698,7 +1676,7 @@ android_glGetTexEnvxv__IILjava_nio_IntBuffer_2
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glGetTexEnvxv(
@@ -1724,18 +1702,18 @@ android_glGetTexParameterfv__II_3FI
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
if (_remaining < 1) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
goto exit;
}
params_base = (GLfloat *)
@@ -1767,7 +1745,7 @@ android_glGetTexParameterfv__IILjava_nio_FloatBuffer_2
params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining);
if (_remaining < 1) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
goto exit;
}
glGetTexParameterfv(
@@ -1793,18 +1771,18 @@ android_glGetTexParameteriv__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
if (_remaining < 1) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
goto exit;
}
params_base = (GLint *)
@@ -1836,7 +1814,7 @@ android_glGetTexParameteriv__IILjava_nio_IntBuffer_2
params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining);
if (_remaining < 1) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
goto exit;
}
glGetTexParameteriv(
@@ -1862,18 +1840,18 @@ android_glGetTexParameterxv__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
if (_remaining < 1) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
goto exit;
}
params_base = (GLfixed *)
@@ -1905,7 +1883,7 @@ android_glGetTexParameterxv__IILjava_nio_IntBuffer_2
params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining);
if (_remaining < 1) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
goto exit;
}
glGetTexParameterxv(
@@ -1983,16 +1961,16 @@ android_glPointParameterfv__I_3FI
GLfloat *params = (GLfloat *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
if (_remaining < 1) {
- _env->ThrowNew(IAEClass, "length - offset < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
goto exit;
}
params_base = (GLfloat *)
@@ -2021,7 +1999,7 @@ android_glPointParameterfv__ILjava_nio_FloatBuffer_2
params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining);
if (_remaining < 1) {
- _env->ThrowNew(IAEClass, "remaining() < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
goto exit;
}
glPointParameterfv(
@@ -2054,16 +2032,16 @@ android_glPointParameterxv__I_3II
GLfixed *params = (GLfixed *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
if (_remaining < 1) {
- _env->ThrowNew(IAEClass, "length - offset < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
goto exit;
}
params_base = (GLfixed *)
@@ -2092,7 +2070,7 @@ android_glPointParameterxv__ILjava_nio_IntBuffer_2
params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining);
if (_remaining < 1) {
- _env->ThrowNew(IAEClass, "remaining() < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
goto exit;
}
glPointParameterxv(
@@ -2160,11 +2138,11 @@ android_glTexEnviv__II_3II
GLint *params = (GLint *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2191,7 +2169,7 @@ android_glTexEnviv__II_3II
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLint *)
@@ -2243,7 +2221,7 @@ android_glTexEnviv__IILjava_nio_IntBuffer_2
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glTexEnviv(
@@ -2267,16 +2245,16 @@ android_glTexParameterfv__II_3FI
GLfloat *params = (GLfloat *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
if (_remaining < 1) {
- _env->ThrowNew(IAEClass, "length - offset < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
goto exit;
}
params_base = (GLfloat *)
@@ -2306,7 +2284,7 @@ android_glTexParameterfv__IILjava_nio_FloatBuffer_2
params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining);
if (_remaining < 1) {
- _env->ThrowNew(IAEClass, "remaining() < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
goto exit;
}
glTexParameterfv(
@@ -2341,16 +2319,16 @@ android_glTexParameteriv__II_3II
GLint *params = (GLint *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
if (_remaining < 1) {
- _env->ThrowNew(IAEClass, "length - offset < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
goto exit;
}
params_base = (GLint *)
@@ -2380,7 +2358,7 @@ android_glTexParameteriv__IILjava_nio_IntBuffer_2
params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining);
if (_remaining < 1) {
- _env->ThrowNew(IAEClass, "remaining() < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
goto exit;
}
glTexParameteriv(
@@ -2404,16 +2382,16 @@ android_glTexParameterxv__II_3II
GLfixed *params = (GLfixed *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
if (_remaining < 1) {
- _env->ThrowNew(IAEClass, "length - offset < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
goto exit;
}
params_base = (GLfixed *)
@@ -2443,7 +2421,7 @@ android_glTexParameterxv__IILjava_nio_IntBuffer_2
params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining);
if (_remaining < 1) {
- _env->ThrowNew(IAEClass, "remaining() < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
goto exit;
}
glTexParameterxv(
diff --git a/core/jni/android_opengl_GLES11Ext.cpp b/core/jni/android_opengl_GLES11Ext.cpp
index 139050649d51..d6dc0fed1bdb 100644
--- a/core/jni/android_opengl_GLES11Ext.cpp
+++ b/core/jni/android_opengl_GLES11Ext.cpp
@@ -2,21 +2,23 @@
**
** Copyright 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
+** 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
+** 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
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
// This source file is automatically generated
+#include "jni.h"
+#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
@@ -37,10 +39,6 @@ static int initialized = 0;
static jclass nioAccessClass;
static jclass bufferClass;
-static jclass OOMEClass;
-static jclass UOEClass;
-static jclass IAEClass;
-static jclass AIOOBEClass;
static jmethodID getBasePointerID;
static jmethodID getBaseArrayID;
static jmethodID getBaseArrayOffsetID;
@@ -51,7 +49,7 @@ static jfieldID elementSizeShiftID;
/* Cache method IDs each time the class is loaded. */
static void
-nativeClassInitBuffer(JNIEnv *_env)
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
{
jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
@@ -73,26 +71,6 @@ nativeClassInitBuffer(JNIEnv *_env)
}
-static void
-nativeClassInit(JNIEnv *_env, jclass glImplClass)
-{
- nativeClassInitBuffer(_env);
-
- jclass IAEClassLocal =
- _env->FindClass("java/lang/IllegalArgumentException");
- jclass OOMEClassLocal =
- _env->FindClass("java/lang/OutOfMemoryError");
- jclass UOEClassLocal =
- _env->FindClass("java/lang/UnsupportedOperationException");
- jclass AIOOBEClassLocal =
- _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
-
- IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
- OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
- UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
- AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
-}
-
static void *
getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
{
@@ -113,13 +91,13 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
*array = NULL;
return (void *) (jint) pointer;
}
-
+
*array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
getBaseArrayID, buffer);
offset = _env->CallStaticIntMethod(nioAccessClass,
getBaseArrayOffsetID, buffer);
data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-
+
return (void *) ((char *) data + offset);
}
@@ -139,12 +117,12 @@ getDirectBufferPointer(JNIEnv *_env, jobject buffer) {
jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
buf += position << elementSizeShift;
} else {
- _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+ jniThrowException(_env, "java/lang/IllegalArgumentException",
+ "Must use a native order direct Buffer");
}
return (void*) buf;
}
// --------------------------------------------------------------------------
-
/* void glBlendEquationSeparateOES ( GLenum modeRGB, GLenum modeAlpha ) */
static void
android_glBlendEquationSeparateOES__II
@@ -224,16 +202,16 @@ android_glDrawTexsvOES___3SI
GLshort *coords = (GLshort *) 0;
if (!coords_ref) {
- _env->ThrowNew(IAEClass, "coords == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "coords == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(coords_ref) - offset;
if (_remaining < 5) {
- _env->ThrowNew(IAEClass, "length - offset < 5");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 5");
goto exit;
}
coords_base = (GLshort *)
@@ -261,7 +239,7 @@ android_glDrawTexsvOES__Ljava_nio_ShortBuffer_2
coords = (GLshort *)getPointer(_env, coords_buf, &_array, &_remaining);
if (_remaining < 5) {
- _env->ThrowNew(IAEClass, "remaining() < 5");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 5");
goto exit;
}
glDrawTexsvOES(
@@ -283,16 +261,16 @@ android_glDrawTexivOES___3II
GLint *coords = (GLint *) 0;
if (!coords_ref) {
- _env->ThrowNew(IAEClass, "coords == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "coords == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(coords_ref) - offset;
if (_remaining < 5) {
- _env->ThrowNew(IAEClass, "length - offset < 5");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 5");
goto exit;
}
coords_base = (GLint *)
@@ -320,7 +298,7 @@ android_glDrawTexivOES__Ljava_nio_IntBuffer_2
coords = (GLint *)getPointer(_env, coords_buf, &_array, &_remaining);
if (_remaining < 5) {
- _env->ThrowNew(IAEClass, "remaining() < 5");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 5");
goto exit;
}
glDrawTexivOES(
@@ -342,16 +320,16 @@ android_glDrawTexxvOES___3II
GLfixed *coords = (GLfixed *) 0;
if (!coords_ref) {
- _env->ThrowNew(IAEClass, "coords == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "coords == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(coords_ref) - offset;
if (_remaining < 5) {
- _env->ThrowNew(IAEClass, "length - offset < 5");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 5");
goto exit;
}
coords_base = (GLfixed *)
@@ -379,7 +357,7 @@ android_glDrawTexxvOES__Ljava_nio_IntBuffer_2
coords = (GLfixed *)getPointer(_env, coords_buf, &_array, &_remaining);
if (_remaining < 5) {
- _env->ThrowNew(IAEClass, "remaining() < 5");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 5");
goto exit;
}
glDrawTexxvOES(
@@ -414,16 +392,16 @@ android_glDrawTexfvOES___3FI
GLfloat *coords = (GLfloat *) 0;
if (!coords_ref) {
- _env->ThrowNew(IAEClass, "coords == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "coords == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(coords_ref) - offset;
if (_remaining < 5) {
- _env->ThrowNew(IAEClass, "length - offset < 5");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 5");
goto exit;
}
coords_base = (GLfloat *)
@@ -451,7 +429,7 @@ android_glDrawTexfvOES__Ljava_nio_FloatBuffer_2
coords = (GLfloat *)getPointer(_env, coords_buf, &_array, &_remaining);
if (_remaining < 5) {
- _env->ThrowNew(IAEClass, "remaining() < 5");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 5");
goto exit;
}
glDrawTexfvOES(
@@ -542,11 +520,11 @@ android_glClipPlanexOES__I_3II
GLfixed *equation = (GLfixed *) 0;
if (!equation_ref) {
- _env->ThrowNew(IAEClass, "equation == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "equation == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(equation_ref) - offset;
@@ -625,11 +603,11 @@ android_glFogxvOES__I_3II
GLfixed *params = (GLfixed *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -692,18 +670,18 @@ android_glGetClipPlanexOES__I_3II
if (!eqn_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "eqn == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "eqn == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(eqn_ref) - offset;
if (_remaining < 4) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < 4");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 4");
goto exit;
}
eqn_base = (GLfixed *)
@@ -734,7 +712,7 @@ android_glGetClipPlanexOES__ILjava_nio_IntBuffer_2
eqn = (GLfixed *)getPointer(_env, eqn_buf, &_array, &_remaining);
if (_remaining < 4) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < 4");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 4");
goto exit;
}
glGetClipPlanexOES(
@@ -759,12 +737,12 @@ android_glGetFixedvOES__I_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -814,12 +792,12 @@ android_glGetLightxvOES__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -871,12 +849,12 @@ android_glGetMaterialxvOES__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -928,12 +906,12 @@ android_glGetTexEnvxvOES__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -985,12 +963,12 @@ android_glGetTexParameterxvOES__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1050,11 +1028,11 @@ android_glLightModelxvOES__I_3II
GLfixed *params = (GLfixed *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1112,11 +1090,11 @@ android_glLightxvOES__II_3II
GLfixed *params = (GLfixed *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1174,11 +1152,11 @@ android_glLoadMatrixxOES___3II
GLfixed *m = (GLfixed *) 0;
if (!m_ref) {
- _env->ThrowNew(IAEClass, "m == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "m == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(m_ref) - offset;
@@ -1234,11 +1212,11 @@ android_glMaterialxvOES__II_3II
GLfixed *params = (GLfixed *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1287,11 +1265,11 @@ android_glMultMatrixxOES___3II
GLfixed *m = (GLfixed *) 0;
if (!m_ref) {
- _env->ThrowNew(IAEClass, "m == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "m == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(m_ref) - offset;
@@ -1384,11 +1362,11 @@ android_glPointParameterxvOES__I_3II
GLfixed *params = (GLfixed *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1498,11 +1476,11 @@ android_glTexEnvxvOES__II_3II
GLfixed *params = (GLfixed *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1562,11 +1540,11 @@ android_glTexParameterxvOES__II_3II
GLfixed *params = (GLfixed *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1647,16 +1625,16 @@ android_glDeleteRenderbuffersOES__I_3II
GLuint *renderbuffers = (GLuint *) 0;
if (!renderbuffers_ref) {
- _env->ThrowNew(IAEClass, "renderbuffers == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "renderbuffers == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(renderbuffers_ref) - offset;
if (_remaining < n) {
- _env->ThrowNew(IAEClass, "length - offset < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
goto exit;
}
renderbuffers_base = (GLuint *)
@@ -1685,7 +1663,7 @@ android_glDeleteRenderbuffersOES__ILjava_nio_IntBuffer_2
renderbuffers = (GLuint *)getPointer(_env, renderbuffers_buf, &_array, &_remaining);
if (_remaining < n) {
- _env->ThrowNew(IAEClass, "remaining() < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
goto exit;
}
glDeleteRenderbuffersOES(
@@ -1710,18 +1688,18 @@ android_glGenRenderbuffersOES__I_3II
if (!renderbuffers_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "renderbuffers == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "renderbuffers == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(renderbuffers_ref) - offset;
if (_remaining < n) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
goto exit;
}
renderbuffers_base = (GLuint *)
@@ -1752,7 +1730,7 @@ android_glGenRenderbuffersOES__ILjava_nio_IntBuffer_2
renderbuffers = (GLuint *)getPointer(_env, renderbuffers_buf, &_array, &_remaining);
if (_remaining < n) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
goto exit;
}
glGenRenderbuffersOES(
@@ -1789,18 +1767,18 @@ android_glGetRenderbufferParameterivOES__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
if (_remaining < 1) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
goto exit;
}
params_base = (GLint *)
@@ -1832,7 +1810,7 @@ android_glGetRenderbufferParameterivOES__IILjava_nio_IntBuffer_2
params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining);
if (_remaining < 1) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
goto exit;
}
glGetRenderbufferParameterivOES(
@@ -1877,16 +1855,16 @@ android_glDeleteFramebuffersOES__I_3II
GLuint *framebuffers = (GLuint *) 0;
if (!framebuffers_ref) {
- _env->ThrowNew(IAEClass, "framebuffers == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "framebuffers == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(framebuffers_ref) - offset;
if (_remaining < n) {
- _env->ThrowNew(IAEClass, "length - offset < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
goto exit;
}
framebuffers_base = (GLuint *)
@@ -1915,7 +1893,7 @@ android_glDeleteFramebuffersOES__ILjava_nio_IntBuffer_2
framebuffers = (GLuint *)getPointer(_env, framebuffers_buf, &_array, &_remaining);
if (_remaining < n) {
- _env->ThrowNew(IAEClass, "remaining() < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
goto exit;
}
glDeleteFramebuffersOES(
@@ -1940,18 +1918,18 @@ android_glGenFramebuffersOES__I_3II
if (!framebuffers_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "framebuffers == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "framebuffers == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(framebuffers_ref) - offset;
if (_remaining < n) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
goto exit;
}
framebuffers_base = (GLuint *)
@@ -1982,7 +1960,7 @@ android_glGenFramebuffersOES__ILjava_nio_IntBuffer_2
framebuffers = (GLuint *)getPointer(_env, framebuffers_buf, &_array, &_remaining);
if (_remaining < n) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
goto exit;
}
glGenFramebuffersOES(
@@ -2043,18 +2021,18 @@ android_glGetFramebufferAttachmentParameterivOES__III_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
if (_remaining < 1) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
goto exit;
}
params_base = (GLint *)
@@ -2087,7 +2065,7 @@ android_glGetFramebufferAttachmentParameterivOES__IIILjava_nio_IntBuffer_2
params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining);
if (_remaining < 1) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
goto exit;
}
glGetFramebufferAttachmentParameterivOES(
@@ -2221,11 +2199,11 @@ android_glClipPlanefOES__I_3FI
GLfloat *equation = (GLfloat *) 0;
if (!equation_ref) {
- _env->ThrowNew(IAEClass, "equation == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "equation == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(equation_ref) - offset;
@@ -2274,18 +2252,18 @@ android_glGetClipPlanefOES__I_3FI
if (!eqn_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "eqn == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "eqn == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(eqn_ref) - offset;
if (_remaining < 4) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < 4");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 4");
goto exit;
}
eqn_base = (GLfloat *)
@@ -2316,7 +2294,7 @@ android_glGetClipPlanefOES__ILjava_nio_FloatBuffer_2
eqn = (GLfloat *)getPointer(_env, eqn_buf, &_array, &_remaining);
if (_remaining < 4) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < 4");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 4");
goto exit;
}
glGetClipPlanefOES(
@@ -2359,11 +2337,11 @@ android_glTexGenfvOES__II_3FI
GLfloat *params = (GLfloat *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2423,11 +2401,11 @@ android_glTexGenivOES__II_3II
GLint *params = (GLint *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2487,11 +2465,11 @@ android_glTexGenxvOES__II_3II
GLfixed *params = (GLfixed *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2542,12 +2520,12 @@ android_glGetTexGenfvOES__II_3FI
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2599,12 +2577,12 @@ android_glGetTexGenivOES__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2656,12 +2634,12 @@ android_glGetTexGenxvOES__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
diff --git a/core/jni/android_opengl_GLES20.cpp b/core/jni/android_opengl_GLES20.cpp
index 7ac0f6ed9e81..a53e4d7081ec 100644
--- a/core/jni/android_opengl_GLES20.cpp
+++ b/core/jni/android_opengl_GLES20.cpp
@@ -2,21 +2,23 @@
**
** Copyright 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
+** 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
+** 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
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
// This source file is automatically generated
+#include "jni.h"
+#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
@@ -28,10 +30,6 @@ static int initialized = 0;
static jclass nioAccessClass;
static jclass bufferClass;
-static jclass OOMEClass;
-static jclass UOEClass;
-static jclass IAEClass;
-static jclass AIOOBEClass;
static jmethodID getBasePointerID;
static jmethodID getBaseArrayID;
static jmethodID getBaseArrayOffsetID;
@@ -42,7 +40,7 @@ static jfieldID elementSizeShiftID;
/* Cache method IDs each time the class is loaded. */
static void
-nativeClassInitBuffer(JNIEnv *_env)
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
{
jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
@@ -64,26 +62,6 @@ nativeClassInitBuffer(JNIEnv *_env)
}
-static void
-nativeClassInit(JNIEnv *_env, jclass glImplClass)
-{
- nativeClassInitBuffer(_env);
-
- jclass IAEClassLocal =
- _env->FindClass("java/lang/IllegalArgumentException");
- jclass OOMEClassLocal =
- _env->FindClass("java/lang/OutOfMemoryError");
- jclass UOEClassLocal =
- _env->FindClass("java/lang/UnsupportedOperationException");
- jclass AIOOBEClassLocal =
- _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
-
- IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
- OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
- UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
- AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
-}
-
static void *
getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
{
@@ -104,13 +82,13 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
*array = NULL;
return (void *) (jint) pointer;
}
-
+
*array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
getBaseArrayID, buffer);
offset = _env->CallStaticIntMethod(nioAccessClass,
getBaseArrayOffsetID, buffer);
data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-
+
return (void *) ((char *) data + offset);
}
@@ -130,7 +108,8 @@ getDirectBufferPointer(JNIEnv *_env, jobject buffer) {
jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
buf += position << elementSizeShift;
} else {
- _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+ jniThrowException(_env, "java/lang/IllegalArgumentException",
+ "Must use a native order direct Buffer");
}
return (void*) buf;
}
@@ -148,7 +127,6 @@ static void glVertexAttribPointerBounds(GLuint indx, GLint size, GLenum type,
}
// --------------------------------------------------------------------------
-
/* void glActiveTexture ( GLenum texture ) */
static void
android_glActiveTexture__I
@@ -175,7 +153,7 @@ android_glBindAttribLocation__IILjava_lang_String_2
const char* _nativename = 0;
if (!name) {
- _env->ThrowNew(IAEClass, "name == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "name == null");
goto exit;
}
_nativename = _env->GetStringUTFChars(name, 0);
@@ -297,7 +275,7 @@ android_glBufferData__IILjava_nio_Buffer_2I
if (data_buf) {
data = (GLvoid *)getPointer(_env, data_buf, &_array, &_remaining);
if (_remaining < size) {
- _env->ThrowNew(IAEClass, "remaining() < size");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < size");
goto exit;
}
}
@@ -324,7 +302,7 @@ android_glBufferSubData__IIILjava_nio_Buffer_2
data = (GLvoid *)getPointer(_env, data_buf, &_array, &_remaining);
if (_remaining < size) {
- _env->ThrowNew(IAEClass, "remaining() < size");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < size");
goto exit;
}
glBufferSubData(
@@ -530,16 +508,16 @@ android_glDeleteBuffers__I_3II
GLuint *buffers = (GLuint *) 0;
if (!buffers_ref) {
- _env->ThrowNew(IAEClass, "buffers == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "buffers == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(buffers_ref) - offset;
if (_remaining < n) {
- _env->ThrowNew(IAEClass, "length - offset < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
goto exit;
}
buffers_base = (GLuint *)
@@ -568,7 +546,7 @@ android_glDeleteBuffers__ILjava_nio_IntBuffer_2
buffers = (GLuint *)getPointer(_env, buffers_buf, &_array, &_remaining);
if (_remaining < n) {
- _env->ThrowNew(IAEClass, "remaining() < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
goto exit;
}
glDeleteBuffers(
@@ -591,11 +569,11 @@ android_glDeleteFramebuffers__I_3II
GLuint *framebuffers = (GLuint *) 0;
if (!framebuffers_ref) {
- _env->ThrowNew(IAEClass, "framebuffers == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "framebuffers == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(framebuffers_ref) - offset;
@@ -651,11 +629,11 @@ android_glDeleteRenderbuffers__I_3II
GLuint *renderbuffers = (GLuint *) 0;
if (!renderbuffers_ref) {
- _env->ThrowNew(IAEClass, "renderbuffers == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "renderbuffers == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(renderbuffers_ref) - offset;
@@ -711,16 +689,16 @@ android_glDeleteTextures__I_3II
GLuint *textures = (GLuint *) 0;
if (!textures_ref) {
- _env->ThrowNew(IAEClass, "textures == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "textures == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(textures_ref) - offset;
if (_remaining < n) {
- _env->ThrowNew(IAEClass, "length - offset < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
goto exit;
}
textures_base = (GLuint *)
@@ -749,7 +727,7 @@ android_glDeleteTextures__ILjava_nio_IntBuffer_2
textures = (GLuint *)getPointer(_env, textures_buf, &_array, &_remaining);
if (_remaining < n) {
- _env->ThrowNew(IAEClass, "remaining() < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
goto exit;
}
glDeleteTextures(
@@ -852,7 +830,7 @@ android_glDrawElements__IIILjava_nio_Buffer_2
indices = (GLvoid *)getPointer(_env, indices_buf, &_array, &_remaining);
if (_remaining < count) {
- _env->ThrowNew(AIOOBEClass, "remaining() < count");
+ jniThrowException(_env, "java/lang/ArrayIndexOutOfBoundsException", "remaining() < count");
goto exit;
}
glDrawElements(
@@ -945,18 +923,18 @@ android_glGenBuffers__I_3II
if (!buffers_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "buffers == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "buffers == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(buffers_ref) - offset;
if (_remaining < n) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
goto exit;
}
buffers_base = (GLuint *)
@@ -987,7 +965,7 @@ android_glGenBuffers__ILjava_nio_IntBuffer_2
buffers = (GLuint *)getPointer(_env, buffers_buf, &_array, &_remaining);
if (_remaining < n) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
goto exit;
}
glGenBuffers(
@@ -1021,12 +999,12 @@ android_glGenFramebuffers__I_3II
if (!framebuffers_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "framebuffers == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "framebuffers == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(framebuffers_ref) - offset;
@@ -1076,12 +1054,12 @@ android_glGenRenderbuffers__I_3II
if (!renderbuffers_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "renderbuffers == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "renderbuffers == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(renderbuffers_ref) - offset;
@@ -1131,18 +1109,18 @@ android_glGenTextures__I_3II
if (!textures_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "textures == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "textures == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(textures_ref) - offset;
if (_remaining < n) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
goto exit;
}
textures_base = (GLuint *)
@@ -1173,7 +1151,7 @@ android_glGenTextures__ILjava_nio_IntBuffer_2
textures = (GLuint *)getPointer(_env, textures_buf, &_array, &_remaining);
if (_remaining < n) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
goto exit;
}
glGenTextures(
@@ -1207,12 +1185,12 @@ android_glGetActiveAttrib__III_3II_3II_3II_3BI
if (!length_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length == null");
goto exit;
}
if (lengthOffset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "lengthOffset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "lengthOffset < 0");
goto exit;
}
_lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset;
@@ -1222,12 +1200,12 @@ android_glGetActiveAttrib__III_3II_3II_3II_3BI
if (!size_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "size == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "size == null");
goto exit;
}
if (sizeOffset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "sizeOffset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "sizeOffset < 0");
goto exit;
}
_sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset;
@@ -1237,12 +1215,12 @@ android_glGetActiveAttrib__III_3II_3II_3II_3BI
if (!type_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "type == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "type == null");
goto exit;
}
if (typeOffset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "typeOffset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "typeOffset < 0");
goto exit;
}
_typeRemaining = _env->GetArrayLength(type_ref) - typeOffset;
@@ -1252,12 +1230,12 @@ android_glGetActiveAttrib__III_3II_3II_3II_3BI
if (!name_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "name == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "name == null");
goto exit;
}
if (nameOffset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "nameOffset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "nameOffset < 0");
goto exit;
}
_nameRemaining = _env->GetArrayLength(name_ref) - nameOffset;
@@ -1352,12 +1330,12 @@ android_glGetActiveUniform__III_3II_3II_3II_3BI
if (!length_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length == null");
goto exit;
}
if (lengthOffset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "lengthOffset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "lengthOffset < 0");
goto exit;
}
_lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset;
@@ -1367,12 +1345,12 @@ android_glGetActiveUniform__III_3II_3II_3II_3BI
if (!size_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "size == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "size == null");
goto exit;
}
if (sizeOffset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "sizeOffset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "sizeOffset < 0");
goto exit;
}
_sizeRemaining = _env->GetArrayLength(size_ref) - sizeOffset;
@@ -1382,12 +1360,12 @@ android_glGetActiveUniform__III_3II_3II_3II_3BI
if (!type_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "type == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "type == null");
goto exit;
}
if (typeOffset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "typeOffset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "typeOffset < 0");
goto exit;
}
_typeRemaining = _env->GetArrayLength(type_ref) - typeOffset;
@@ -1397,12 +1375,12 @@ android_glGetActiveUniform__III_3II_3II_3II_3BI
if (!name_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "name == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "name == null");
goto exit;
}
if (nameOffset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "nameOffset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "nameOffset < 0");
goto exit;
}
_nameRemaining = _env->GetArrayLength(name_ref) - nameOffset;
@@ -1491,12 +1469,12 @@ android_glGetAttachedShaders__II_3II_3II
if (!count_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "count == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "count == null");
goto exit;
}
if (countOffset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "countOffset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "countOffset < 0");
goto exit;
}
_countRemaining = _env->GetArrayLength(count_ref) - countOffset;
@@ -1506,12 +1484,12 @@ android_glGetAttachedShaders__II_3II_3II
if (!shaders_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "shaders == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "shaders == null");
goto exit;
}
if (shadersOffset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "shadersOffset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "shadersOffset < 0");
goto exit;
}
_shadersRemaining = _env->GetArrayLength(shaders_ref) - shadersOffset;
@@ -1573,7 +1551,7 @@ android_glGetAttribLocation__ILjava_lang_String_2
const char* _nativename = 0;
if (!name) {
- _env->ThrowNew(IAEClass, "name == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "name == null");
goto exit;
}
_nativename = _env->GetStringUTFChars(name, 0);
@@ -1602,12 +1580,12 @@ android_glGetBooleanv__I_3ZI
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1657,18 +1635,18 @@ android_glGetBufferParameteriv__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
if (_remaining < 1) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
goto exit;
}
params_base = (GLint *)
@@ -1700,7 +1678,7 @@ android_glGetBufferParameteriv__IILjava_nio_IntBuffer_2
params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining);
if (_remaining < 1) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
goto exit;
}
glGetBufferParameteriv(
@@ -1735,12 +1713,12 @@ android_glGetFloatv__I_3FI
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1790,12 +1768,12 @@ android_glGetFramebufferAttachmentParameteriv__III_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1849,12 +1827,12 @@ android_glGetIntegerv__I_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2191,7 +2169,7 @@ android_glGetIntegerv__I_3II
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLint *)
@@ -2553,7 +2531,7 @@ android_glGetIntegerv__ILjava_nio_IntBuffer_2
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glGetIntegerv(
@@ -2578,12 +2556,12 @@ android_glGetProgramiv__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2624,32 +2602,24 @@ android_glGetProgramiv__IILjava_nio_IntBuffer_2
}
}
-#include <string.h>
+#include <stdlib.h>
/* void glGetProgramInfoLog ( GLuint shader, GLsizei maxLength, GLsizei* length, GLchar* infoLog ) */
-static
-jstring
-android_glGetProgramInfoLog (JNIEnv *_env, jobject _this, jint shader) {
+static jstring android_glGetProgramInfoLog(JNIEnv *_env, jobject, jint shader) {
GLint infoLen = 0;
- jstring _result = 0;
- char* buf = 0;
glGetProgramiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
- if (infoLen) {
- char* buf = (char*) malloc(infoLen);
- if (buf == 0) {
- _env->ThrowNew(IAEClass, "out of memory");
- goto exit;
- }
- glGetProgramInfoLog(shader, infoLen, NULL, buf);
- _result = _env->NewStringUTF(buf);
- } else {
- _result = _env->NewStringUTF("");
+ if (!infoLen) {
+ return _env->NewStringUTF("");
}
-exit:
- if (buf) {
- free(buf);
+ char* buf = (char*) malloc(infoLen);
+ if (buf == NULL) {
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "out of memory");
+ return NULL;
}
- return _result;
+ glGetProgramInfoLog(shader, infoLen, NULL, buf);
+ jstring result = _env->NewStringUTF(buf);
+ free(buf);
+ return result;
}
/* void glGetRenderbufferParameteriv ( GLenum target, GLenum pname, GLint *params ) */
static void
@@ -2662,12 +2632,12 @@ android_glGetRenderbufferParameteriv__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2719,12 +2689,12 @@ android_glGetShaderiv__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2765,32 +2735,24 @@ android_glGetShaderiv__IILjava_nio_IntBuffer_2
}
}
-#include <string.h>
+#include <stdlib.h>
/* void glGetShaderInfoLog ( GLuint shader, GLsizei maxLength, GLsizei* length, GLchar* infoLog ) */
-static
-jstring
-android_glGetShaderInfoLog (JNIEnv *_env, jobject _this, jint shader) {
+static jstring android_glGetShaderInfoLog(JNIEnv *_env, jobject, jint shader) {
GLint infoLen = 0;
- jstring _result = 0;
- char* buf = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
- if (infoLen) {
- char* buf = (char*) malloc(infoLen);
- if (buf == 0) {
- _env->ThrowNew(IAEClass, "out of memory");
- goto exit;
- }
- glGetShaderInfoLog(shader, infoLen, NULL, buf);
- _result = _env->NewStringUTF(buf);
- } else {
- _result = _env->NewStringUTF("");
+ if (!infoLen) {
+ return _env->NewStringUTF("");
}
-exit:
- if (buf) {
- free(buf);
+ char* buf = (char*) malloc(infoLen);
+ if (buf == NULL) {
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "out of memory");
+ return NULL;
}
- return _result;
+ glGetShaderInfoLog(shader, infoLen, NULL, buf);
+ jstring result = _env->NewStringUTF(buf);
+ free(buf);
+ return result;
}
/* void glGetShaderPrecisionFormat ( GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision ) */
static void
@@ -2806,12 +2768,12 @@ android_glGetShaderPrecisionFormat__II_3II_3II
if (!range_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "range == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "range == null");
goto exit;
}
if (rangeOffset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "rangeOffset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "rangeOffset < 0");
goto exit;
}
_rangeRemaining = _env->GetArrayLength(range_ref) - rangeOffset;
@@ -2821,12 +2783,12 @@ android_glGetShaderPrecisionFormat__II_3II_3II
if (!precision_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "precision == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "precision == null");
goto exit;
}
if (precisionOffset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "precisionOffset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "precisionOffset < 0");
goto exit;
}
_precisionRemaining = _env->GetArrayLength(precision_ref) - precisionOffset;
@@ -2894,12 +2856,12 @@ android_glGetShaderSource__II_3II_3BI
if (!length_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length == null");
goto exit;
}
if (lengthOffset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "lengthOffset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "lengthOffset < 0");
goto exit;
}
_lengthRemaining = _env->GetArrayLength(length_ref) - lengthOffset;
@@ -2909,12 +2871,12 @@ android_glGetShaderSource__II_3II_3BI
if (!source_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "source == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "source == null");
goto exit;
}
if (sourceOffset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "sourceOffset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "sourceOffset < 0");
goto exit;
}
_sourceRemaining = _env->GetArrayLength(source_ref) - sourceOffset;
@@ -2961,16 +2923,10 @@ android_glGetShaderSource__IILjava_nio_IntBuffer_2B
}
}
-#include <string.h>
-
/* const GLubyte * glGetString ( GLenum name ) */
-static
-jstring
-android_glGetString
- (JNIEnv *_env, jobject _this, jint name) {
- const char * chars = (const char *)glGetString((GLenum)name);
- jstring output = _env->NewStringUTF(chars);
- return output;
+static jstring android_glGetString(JNIEnv* _env, jobject, jint name) {
+ const char* chars = (const char*) glGetString((GLenum) name);
+ return _env->NewStringUTF(chars);
}
/* void glGetTexParameterfv ( GLenum target, GLenum pname, GLfloat *params ) */
static void
@@ -2983,18 +2939,18 @@ android_glGetTexParameterfv__II_3FI
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
if (_remaining < 1) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
goto exit;
}
params_base = (GLfloat *)
@@ -3026,7 +2982,7 @@ android_glGetTexParameterfv__IILjava_nio_FloatBuffer_2
params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining);
if (_remaining < 1) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
goto exit;
}
glGetTexParameterfv(
@@ -3052,18 +3008,18 @@ android_glGetTexParameteriv__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
if (_remaining < 1) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
goto exit;
}
params_base = (GLint *)
@@ -3095,7 +3051,7 @@ android_glGetTexParameteriv__IILjava_nio_IntBuffer_2
params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining);
if (_remaining < 1) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
goto exit;
}
glGetTexParameteriv(
@@ -3121,12 +3077,12 @@ android_glGetUniformfv__II_3FI
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -3178,12 +3134,12 @@ android_glGetUniformiv__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -3232,7 +3188,7 @@ android_glGetUniformLocation__ILjava_lang_String_2
const char* _nativename = 0;
if (!name) {
- _env->ThrowNew(IAEClass, "name == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "name == null");
goto exit;
}
_nativename = _env->GetStringUTFChars(name, 0);
@@ -3261,12 +3217,12 @@ android_glGetVertexAttribfv__II_3FI
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -3318,12 +3274,12 @@ android_glGetVertexAttribiv__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -3566,11 +3522,11 @@ android_glShaderBinary__I_3IIILjava_nio_Buffer_2I
GLvoid *binary = (GLvoid *) 0;
if (!shaders_ref) {
- _env->ThrowNew(IAEClass, "shaders == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "shaders == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_shadersRemaining = _env->GetArrayLength(shaders_ref) - offset;
@@ -3633,7 +3589,7 @@ android_glShaderSource
(JNIEnv *_env, jobject _this, jint shader, jstring string) {
if (!string) {
- _env->ThrowNew(IAEClass, "string == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "string == null");
return;
}
@@ -3754,16 +3710,16 @@ android_glTexParameterfv__II_3FI
GLfloat *params = (GLfloat *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
if (_remaining < 1) {
- _env->ThrowNew(IAEClass, "length - offset < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
goto exit;
}
params_base = (GLfloat *)
@@ -3793,7 +3749,7 @@ android_glTexParameterfv__IILjava_nio_FloatBuffer_2
params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining);
if (_remaining < 1) {
- _env->ThrowNew(IAEClass, "remaining() < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
goto exit;
}
glTexParameterfv(
@@ -3828,16 +3784,16 @@ android_glTexParameteriv__II_3II
GLint *params = (GLint *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
if (_remaining < 1) {
- _env->ThrowNew(IAEClass, "length - offset < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
goto exit;
}
params_base = (GLint *)
@@ -3867,7 +3823,7 @@ android_glTexParameteriv__IILjava_nio_IntBuffer_2
params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining);
if (_remaining < 1) {
- _env->ThrowNew(IAEClass, "remaining() < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
goto exit;
}
glTexParameteriv(
@@ -3928,11 +3884,11 @@ android_glUniform1fv__II_3FI
GLfloat *v = (GLfloat *) 0;
if (!v_ref) {
- _env->ThrowNew(IAEClass, "v == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "v == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(v_ref) - offset;
@@ -3991,11 +3947,11 @@ android_glUniform1iv__II_3II
GLint *v = (GLint *) 0;
if (!v_ref) {
- _env->ThrowNew(IAEClass, "v == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "v == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(v_ref) - offset;
@@ -4055,11 +4011,11 @@ android_glUniform2fv__II_3FI
GLfloat *v = (GLfloat *) 0;
if (!v_ref) {
- _env->ThrowNew(IAEClass, "v == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "v == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(v_ref) - offset;
@@ -4119,11 +4075,11 @@ android_glUniform2iv__II_3II
GLint *v = (GLint *) 0;
if (!v_ref) {
- _env->ThrowNew(IAEClass, "v == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "v == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(v_ref) - offset;
@@ -4184,11 +4140,11 @@ android_glUniform3fv__II_3FI
GLfloat *v = (GLfloat *) 0;
if (!v_ref) {
- _env->ThrowNew(IAEClass, "v == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "v == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(v_ref) - offset;
@@ -4249,11 +4205,11 @@ android_glUniform3iv__II_3II
GLint *v = (GLint *) 0;
if (!v_ref) {
- _env->ThrowNew(IAEClass, "v == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "v == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(v_ref) - offset;
@@ -4315,11 +4271,11 @@ android_glUniform4fv__II_3FI
GLfloat *v = (GLfloat *) 0;
if (!v_ref) {
- _env->ThrowNew(IAEClass, "v == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "v == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(v_ref) - offset;
@@ -4381,11 +4337,11 @@ android_glUniform4iv__II_3II
GLint *v = (GLint *) 0;
if (!v_ref) {
- _env->ThrowNew(IAEClass, "v == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "v == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(v_ref) - offset;
@@ -4434,11 +4390,11 @@ android_glUniformMatrix2fv__IIZ_3FI
GLfloat *value = (GLfloat *) 0;
if (!value_ref) {
- _env->ThrowNew(IAEClass, "value == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "value == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(value_ref) - offset;
@@ -4489,11 +4445,11 @@ android_glUniformMatrix3fv__IIZ_3FI
GLfloat *value = (GLfloat *) 0;
if (!value_ref) {
- _env->ThrowNew(IAEClass, "value == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "value == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(value_ref) - offset;
@@ -4544,11 +4500,11 @@ android_glUniformMatrix4fv__IIZ_3FI
GLfloat *value = (GLfloat *) 0;
if (!value_ref) {
- _env->ThrowNew(IAEClass, "value == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "value == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(value_ref) - offset;
@@ -4627,11 +4583,11 @@ android_glVertexAttrib1fv__I_3FI
GLfloat *values = (GLfloat *) 0;
if (!values_ref) {
- _env->ThrowNew(IAEClass, "values == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "values == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(values_ref) - offset;
@@ -4689,11 +4645,11 @@ android_glVertexAttrib2fv__I_3FI
GLfloat *values = (GLfloat *) 0;
if (!values_ref) {
- _env->ThrowNew(IAEClass, "values == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "values == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(values_ref) - offset;
@@ -4752,11 +4708,11 @@ android_glVertexAttrib3fv__I_3FI
GLfloat *values = (GLfloat *) 0;
if (!values_ref) {
- _env->ThrowNew(IAEClass, "values == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "values == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(values_ref) - offset;
@@ -4816,11 +4772,11 @@ android_glVertexAttrib4fv__I_3FI
GLfloat *values = (GLfloat *) 0;
if (!values_ref) {
- _env->ThrowNew(IAEClass, "values == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "values == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(values_ref) - offset;
diff --git a/core/jni/android_os_FileUtils.cpp b/core/jni/android_os_FileUtils.cpp
index 2b4a955efdd5..89dce8987364 100644
--- a/core/jni/android_os_FileUtils.cpp
+++ b/core/jni/android_os_FileUtils.cpp
@@ -2,16 +2,16 @@
**
** Copyright 2006, 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
+** 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
+** 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
+** 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.
*/
@@ -145,7 +145,7 @@ jint android_os_FileUtils_getFatVolumeId(JNIEnv* env, jobject clazz, jstring pat
jboolean android_os_FileUtils_getFileStatus(JNIEnv* env, jobject clazz, jstring path, jobject fileStatus) {
const char* pathStr = env->GetStringUTFChars(path, NULL);
jboolean ret = false;
-
+
struct stat s;
int res = stat(pathStr, &s);
if (res == 0) {
@@ -165,9 +165,9 @@ jboolean android_os_FileUtils_getFileStatus(JNIEnv* env, jobject clazz, jstring
env->SetLongField(fileStatus, gFileStatusCtimeFieldID, s.st_ctime);
}
}
-
+
env->ReleaseStringUTFChars(path, pathStr);
-
+
return ret;
}
@@ -183,11 +183,6 @@ static const char* const kFileUtilsPathName = "android/os/FileUtils";
int register_android_os_FileUtils(JNIEnv* env)
{
- jclass clazz;
-
- clazz = env->FindClass(kFileUtilsPathName);
- LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.FileUtils");
-
jclass fileStatusClass = env->FindClass("android/os/FileUtils$FileStatus");
LOG_FATAL_IF(fileStatusClass == NULL, "Unable to find class android.os.FileUtils$FileStatus");
diff --git a/core/jni/android_os_MemoryFile.cpp b/core/jni/android_os_MemoryFile.cpp
index ee8d836c06d5..71341916ce68 100644
--- a/core/jni/android_os_MemoryFile.cpp
+++ b/core/jni/android_os_MemoryFile.cpp
@@ -148,17 +148,10 @@ static const JNINativeMethod methods[] = {
(void*)android_os_MemoryFile_get_size}
};
-static const char* const kClassPathName = "android/os/MemoryFile";
-
int register_android_os_MemoryFile(JNIEnv* env)
{
- jclass clazz;
-
- clazz = env->FindClass(kClassPathName);
- LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.FileUtils");
-
return AndroidRuntime::registerNativeMethods(
- env, kClassPathName,
+ env, "android/os/MemoryFile",
methods, NELEM(methods));
}
diff --git a/core/jni/android_os_ParcelFileDescriptor.cpp b/core/jni/android_os_ParcelFileDescriptor.cpp
index 1f737f940038..4ec131cd9f48 100644
--- a/core/jni/android_os_ParcelFileDescriptor.cpp
+++ b/core/jni/android_os_ParcelFileDescriptor.cpp
@@ -29,43 +29,11 @@
namespace android
{
-static struct file_descriptor_offsets_t
-{
- jclass mClass;
- jmethodID mConstructor;
- jfieldID mDescriptor;
-} gFileDescriptorOffsets;
-
-static struct socket_offsets_t
-{
- jfieldID mSocketImpl;
-} gSocketOffsets;
-
-static struct socket_impl_offsets_t
-{
- jfieldID mFileDescriptor;
-} gSocketImplOffsets;
-
static struct parcel_file_descriptor_offsets_t
{
- jclass mClass;
jfieldID mFileDescriptor;
} gParcelFileDescriptorOffsets;
-static jobject android_os_ParcelFileDescriptor_getFileDescriptorFromSocket(JNIEnv* env,
- jobject clazz, jobject object)
-{
- jobject socketImpl = env->GetObjectField(object, gSocketOffsets.mSocketImpl);
- jobject fileDescriptor = env->GetObjectField(socketImpl, gSocketImplOffsets.mFileDescriptor);
- jint fd = env->GetIntField(fileDescriptor, gFileDescriptorOffsets.mDescriptor);
- jobject fileDescriptorClone = env->NewObject(gFileDescriptorOffsets.mClass,
- gFileDescriptorOffsets.mConstructor);
- if (fileDescriptorClone != NULL) {
- env->SetIntField(fileDescriptorClone, gFileDescriptorOffsets.mDescriptor, dup(fd));
- }
- return fileDescriptorClone;
-}
-
static int android_os_ParcelFileDescriptor_createPipeNative(JNIEnv* env,
jobject clazz, jobjectArray outFds)
{
@@ -75,11 +43,7 @@ static int android_os_ParcelFileDescriptor_createPipeNative(JNIEnv* env,
}
for (int i=0; i<2; i++) {
- jobject fdObj = env->NewObject(gFileDescriptorOffsets.mClass,
- gFileDescriptorOffsets.mConstructor);
- if (fdObj != NULL) {
- env->SetIntField(fdObj, gFileDescriptorOffsets.mDescriptor, fds[i]);
- }
+ jobject fdObj = jniCreateFileDescriptor(env, fds[i]);
env->SetObjectArrayElement(outFds, i, fdObj);
}
@@ -90,7 +54,7 @@ static jint getFd(JNIEnv* env, jobject clazz)
{
jobject descriptor = env->GetObjectField(clazz, gParcelFileDescriptorOffsets.mFileDescriptor);
if (descriptor == NULL) return -1;
- return env->GetIntField(descriptor, gFileDescriptorOffsets.mDescriptor);
+ return jniGetFDFromFileDescriptor(env, descriptor);
}
static jlong android_os_ParcelFileDescriptor_getStatSize(JNIEnv* env,
@@ -101,16 +65,16 @@ static jlong android_os_ParcelFileDescriptor_getStatSize(JNIEnv* env,
jniThrowException(env, "java/lang/IllegalArgumentException", "bad file descriptor");
return -1;
}
-
+
struct stat st;
if (fstat(fd, &st) != 0) {
return -1;
}
-
+
if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
return st.st_size;
}
-
+
return -1;
}
@@ -122,7 +86,7 @@ static jlong android_os_ParcelFileDescriptor_seekTo(JNIEnv* env,
jniThrowException(env, "java/lang/IllegalArgumentException", "bad file descriptor");
return -1;
}
-
+
return lseek(fd, pos, SEEK_SET);
}
@@ -138,8 +102,6 @@ static jlong android_os_ParcelFileDescriptor_getFdNative(JNIEnv* env, jobject cl
}
static const JNINativeMethod gParcelFileDescriptorMethods[] = {
- {"getFileDescriptorFromSocket", "(Ljava/net/Socket;)Ljava/io/FileDescriptor;",
- (void*)android_os_ParcelFileDescriptor_getFileDescriptorFromSocket},
{"createPipeNative", "([Ljava/io/FileDescriptor;)I",
(void*)android_os_ParcelFileDescriptor_createPipeNative},
{"getStatSize", "()J",
@@ -154,31 +116,8 @@ const char* const kParcelFileDescriptorPathName = "android/os/ParcelFileDescript
int register_android_os_ParcelFileDescriptor(JNIEnv* env)
{
- jclass clazz;
-
- clazz = env->FindClass("java/net/Socket");
- LOG_FATAL_IF(clazz == NULL, "Unable to find class java.net.Socket");
- gSocketOffsets.mSocketImpl = env->GetFieldID(clazz, "impl", "Ljava/net/SocketImpl;");
- LOG_FATAL_IF(gSocketOffsets.mSocketImpl == NULL,
- "Unable to find impl field in java.net.Socket");
-
- clazz = env->FindClass("java/net/SocketImpl");
- LOG_FATAL_IF(clazz == NULL, "Unable to find class java.net.SocketImpl");
- gSocketImplOffsets.mFileDescriptor = env->GetFieldID(clazz, "fd", "Ljava/io/FileDescriptor;");
- LOG_FATAL_IF(gSocketImplOffsets.mFileDescriptor == NULL,
- "Unable to find fd field in java.net.SocketImpl");
-
- clazz = env->FindClass("java/io/FileDescriptor");
- LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor");
- gFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
- gFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "()V");
- gFileDescriptorOffsets.mDescriptor = env->GetFieldID(clazz, "descriptor", "I");
- LOG_FATAL_IF(gFileDescriptorOffsets.mDescriptor == NULL,
- "Unable to find descriptor field in java.io.FileDescriptor");
-
- clazz = env->FindClass(kParcelFileDescriptorPathName);
+ jclass clazz = env->FindClass(kParcelFileDescriptorPathName);
LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor");
- gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
gParcelFileDescriptorOffsets.mFileDescriptor = env->GetFieldID(clazz, "mFileDescriptor", "Ljava/io/FileDescriptor;");
LOG_FATAL_IF(gParcelFileDescriptorOffsets.mFileDescriptor == NULL,
"Unable to find mFileDescriptor field in android.os.ParcelFileDescriptor");
diff --git a/core/jni/android_pim_EventRecurrence.cpp b/core/jni/android_pim_EventRecurrence.cpp
index 9056c900eaff..44e898d4f232 100644
--- a/core/jni/android_pim_EventRecurrence.cpp
+++ b/core/jni/android_pim_EventRecurrence.cpp
@@ -28,7 +28,6 @@ struct cached_array_fields_t
jfieldID count;
};
-static jclass clazz;
static jfieldID freq_field;
static jfieldID until_field;
static jfieldID count_field;
@@ -87,8 +86,7 @@ EventRecurrence_parse(JNIEnv* env, jobject This, jstring jstr)
jniThrowNullPointerException(env, "EventRecurrence.parse str parameter null");
return ;
}
- jboolean isCopy;
- const jchar* jchars = env->GetStringChars(jstr, &isCopy);
+ const jchar* jchars = env->GetStringChars(jstr, NULL);
jsize len = env->GetStringLength(jstr);
String16 str(jchars, len);
env->ReleaseStringChars(jstr, jchars);
@@ -156,7 +154,7 @@ static const char*const CLASS_NAME = "android/pim/EventRecurrence";
int register_android_pim_EventRecurrence(JNIEnv* env)
{
- clazz = env->FindClass(CLASS_NAME);
+ jclass clazz = env->FindClass(CLASS_NAME);
if (clazz == NULL) {
LOGE("Field lookup unable to find class '%s'\n", CLASS_NAME);
return -1;
diff --git a/core/jni/android_text_AndroidBidi.cpp b/core/jni/android_text_AndroidBidi.cpp
index 53028c3546da..d50a69faeef6 100644
--- a/core/jni/android_text_AndroidBidi.cpp
+++ b/core/jni/android_text_AndroidBidi.cpp
@@ -2,16 +2,16 @@
**
** Copyright 2010, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** 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
+** 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
+** 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.
*/
@@ -24,8 +24,8 @@
#include "unicode/ubidi.h"
namespace android {
-
-static jint runBidi(JNIEnv* env, jobject obj, jint dir, jcharArray chsArray,
+
+static jint runBidi(JNIEnv* env, jobject obj, jint dir, jcharArray chsArray,
jbyteArray infoArray, int n, jboolean haveInfo)
{
// Parameters are checked on java side
@@ -63,9 +63,6 @@ static JNINativeMethod gMethods[] = {
int register_android_text_AndroidBidi(JNIEnv* env)
{
- jclass clazz = env->FindClass("android/text/AndroidBidi");
- LOG_ASSERT(clazz, "Cannot find android/text/AndroidBidi");
-
return AndroidRuntime::registerNativeMethods(env, "android/text/AndroidBidi",
gMethods, NELEM(gMethods));
}
diff --git a/core/jni/android_text_AndroidCharacter.cpp b/core/jni/android_text_AndroidCharacter.cpp
index 0d0f5fa879ae..dacbe41c3a96 100644
--- a/core/jni/android_text_AndroidCharacter.cpp
+++ b/core/jni/android_text_AndroidCharacter.cpp
@@ -191,9 +191,6 @@ static JNINativeMethod gMethods[] = {
int register_android_text_AndroidCharacter(JNIEnv* env)
{
- jclass clazz = env->FindClass("android/text/AndroidCharacter");
- LOG_ASSERT(clazz, "Cannot find android/text/AndroidCharacter");
-
return AndroidRuntime::registerNativeMethods(env, "android/text/AndroidCharacter",
gMethods, NELEM(gMethods));
}
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 8ea7e90f2366..b0e92e4a3c18 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -169,7 +169,7 @@ static jobject returnParcelFileDescriptor(JNIEnv* env, Asset* a, jlongArray outO
env->ReleasePrimitiveArrayCritical(outOffsets, offsets, 0);
- jobject fileDesc = newFileDescriptor(env, fd);
+ jobject fileDesc = jniCreateFileDescriptor(env, fd);
if (fileDesc == NULL) {
close(fd);
return NULL;
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 8618b795d4b8..06811953d999 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -131,13 +131,6 @@ static struct log_offsets_t
jmethodID mLogE;
} gLogOffsets;
-static struct file_descriptor_offsets_t
-{
- jclass mClass;
- jmethodID mConstructor;
- jfieldID mDescriptor;
-} gFileDescriptorOffsets;
-
static struct parcel_file_descriptor_offsets_t
{
jclass mClass;
@@ -591,17 +584,6 @@ Parcel* parcelForJavaObject(JNIEnv* env, jobject obj)
return NULL;
}
-jobject newFileDescriptor(JNIEnv* env, int fd)
-{
- jobject object = env->NewObject(
- gFileDescriptorOffsets.mClass, gFileDescriptorOffsets.mConstructor);
- if (object != NULL) {
- //LOGI("Created new FileDescriptor %p with fd %d\n", object, fd);
- env->SetIntField(object, gFileDescriptorOffsets.mDescriptor, fd);
- }
- return object;
-}
-
jobject newParcelFileDescriptor(JNIEnv* env, jobject fileDesc)
{
return env->NewObject(
@@ -1358,8 +1340,8 @@ static void android_os_Parcel_writeFileDescriptor(JNIEnv* env, jobject clazz, jo
{
Parcel* parcel = parcelForJavaObject(env, clazz);
if (parcel != NULL) {
- const status_t err = parcel->writeDupFileDescriptor(
- env->GetIntField(object, gFileDescriptorOffsets.mDescriptor));
+ const status_t err =
+ parcel->writeDupFileDescriptor(jniGetFDFromFileDescriptor(env, object));
if (err != NO_ERROR) {
jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
}
@@ -1459,13 +1441,7 @@ static jobject android_os_Parcel_readFileDescriptor(JNIEnv* env, jobject clazz)
if (fd < 0) return NULL;
fd = dup(fd);
if (fd < 0) return NULL;
- jobject object = env->NewObject(
- gFileDescriptorOffsets.mClass, gFileDescriptorOffsets.mConstructor);
- if (object != NULL) {
- //LOGI("Created new FileDescriptor %p with fd %d\n", object, fd);
- env->SetIntField(object, gFileDescriptorOffsets.mDescriptor, fd);
- }
- return object;
+ return jniCreateFileDescriptor(env, fd);
}
return NULL;
}
@@ -1512,7 +1488,7 @@ static jobject android_os_Parcel_openFileDescriptor(JNIEnv* env, jobject clazz,
jniThrowException(env, "java/io/FileNotFoundException", strerror(errno));
return NULL;
}
- jobject object = newFileDescriptor(env, fd);
+ jobject object = jniCreateFileDescriptor(env, fd);
if (object == NULL) {
close(fd);
}
@@ -1525,7 +1501,7 @@ static jobject android_os_Parcel_dupFileDescriptor(JNIEnv* env, jobject clazz, j
jniThrowNullPointerException(env, NULL);
return NULL;
}
- int origfd = env->GetIntField(orig, gFileDescriptorOffsets.mDescriptor);
+ int origfd = jniGetFDFromFileDescriptor(env, orig);
if (origfd < 0) {
jniThrowException(env, "java/lang/IllegalArgumentException", "bad FileDescriptor");
return NULL;
@@ -1536,7 +1512,7 @@ static jobject android_os_Parcel_dupFileDescriptor(JNIEnv* env, jobject clazz, j
jniThrowIOException(env, errno);
return NULL;
}
- jobject object = newFileDescriptor(env, fd);
+ jobject object = jniCreateFileDescriptor(env, fd);
if (object == NULL) {
close(fd);
}
@@ -1549,9 +1525,9 @@ static void android_os_Parcel_closeFileDescriptor(JNIEnv* env, jobject clazz, jo
jniThrowNullPointerException(env, NULL);
return;
}
- int fd = env->GetIntField(object, gFileDescriptorOffsets.mDescriptor);
+ int fd = jniGetFDFromFileDescriptor(env, object);
if (fd >= 0) {
- env->SetIntField(object, gFileDescriptorOffsets.mDescriptor, -1);
+ jniSetFileDescriptorOfFD(env, object, -1);
//LOGI("Closing ParcelFileDescriptor %d\n", fd);
close(fd);
}
@@ -1563,9 +1539,9 @@ static void android_os_Parcel_clearFileDescriptor(JNIEnv* env, jobject clazz, jo
jniThrowNullPointerException(env, NULL);
return;
}
- int fd = env->GetIntField(object, gFileDescriptorOffsets.mDescriptor);
+ int fd = jniGetFDFromFileDescriptor(env, object);
if (fd >= 0) {
- env->SetIntField(object, gFileDescriptorOffsets.mDescriptor, -1);
+ jniSetFileDescriptorOfFD(env, object, -1);
}
}
@@ -1794,15 +1770,6 @@ static int int_register_android_os_Parcel(JNIEnv* env)
clazz, "e", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/Throwable;)I");
assert(gLogOffsets.mLogE);
- clazz = env->FindClass("java/io/FileDescriptor");
- LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor");
- gFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
- gFileDescriptorOffsets.mConstructor
- = env->GetMethodID(clazz, "<init>", "()V");
- gFileDescriptorOffsets.mDescriptor = env->GetFieldID(clazz, "descriptor", "I");
- LOG_FATAL_IF(gFileDescriptorOffsets.mDescriptor == NULL,
- "Unable to find descriptor field in java.io.FileDescriptor");
-
clazz = env->FindClass("android/os/ParcelFileDescriptor");
LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor");
gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
@@ -1842,13 +1809,3 @@ int register_android_os_Binder(JNIEnv* env)
return -1;
return 0;
}
-
-namespace android {
-
-// Returns the Unix file descriptor for a ParcelFileDescriptor object
-int getParcelFileDescriptorFD(JNIEnv* env, jobject object)
-{
- return env->GetIntField(object, gFileDescriptorOffsets.mDescriptor);
-}
-
-}
diff --git a/core/jni/android_util_Binder.h b/core/jni/android_util_Binder.h
index 495e76a98285..0122691b25da 100644
--- a/core/jni/android_util_Binder.h
+++ b/core/jni/android_util_Binder.h
@@ -2,16 +2,16 @@
**
** Copyright 2006, 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
+** 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
+** 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
+** 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.
*/
@@ -29,7 +29,6 @@ extern sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj);
// Note: does not type checking; must guarantee jobject is a Java Parcel
extern Parcel* parcelForJavaObject(JNIEnv* env, jobject obj);
-extern jobject newFileDescriptor(JNIEnv* env, int fd);
extern jobject newParcelFileDescriptor(JNIEnv* env, jobject fileDesc);
}
diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index 91d37d30c941..5d51110c3d33 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -35,9 +35,6 @@ static jmethodID gEventInitID;
static jclass gIntegerClass;
static jfieldID gIntegerValueID;
-static jclass gListClass;
-static jfieldID gListItemsID;
-
static jclass gLongClass;
static jfieldID gLongValueID;
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 0068de73e72e..e5c28489ae99 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -103,17 +103,6 @@ static void signalExceptionForGroupError(JNIEnv* env, jobject obj, int err)
}
}
-
-static void fakeProcessEntry(void* arg)
-{
- String8* cls = (String8*)arg;
-
- AndroidRuntime* jr = AndroidRuntime::getRuntime();
- jr->callMain(cls->string(), 0, NULL);
-
- delete cls;
-}
-
jint android_os_Process_myPid(JNIEnv* env, jobject clazz)
{
return getpid();
@@ -915,11 +904,6 @@ const char* const kProcessPathName = "android/os/Process";
int register_android_os_Process(JNIEnv* env)
{
- jclass clazz;
-
- clazz = env->FindClass(kProcessPathName);
- LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.Process");
-
return AndroidRuntime::registerNativeMethods(
env, kProcessPathName,
methods, NELEM(methods));
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index f31bba91f841..314c2ee3b176 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -595,13 +595,11 @@ static jboolean android_view_GLES20Canvas_isAvailable(JNIEnv* env, jobject clazz
// Logging
// ----------------------------------------------------------------------------
-jfieldID gFileDescriptorField;
-
static void
android_app_ActivityThread_dumpGraphics(JNIEnv* env, jobject clazz, jobject javaFileDescriptor)
{
#ifdef USE_OPENGL_RENDERER
- int fd = env->GetIntField(javaFileDescriptor, gFileDescriptorField);
+ int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
android::uirenderer::DisplayList::outputLogBuffer(fd);
#endif // USE_OPENGL_RENDERER
}
@@ -736,12 +734,6 @@ const char* const kActivityThreadPathName = "android/app/ActivityThread";
int register_android_app_ActivityThread(JNIEnv* env)
{
- jclass fileDescriptorClass = env->FindClass("java/io/FileDescriptor");
- LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor");
- gFileDescriptorField = env->GetFieldID(fileDescriptorClass, "descriptor", "I");
- LOG_FATAL_IF(gFileDescriptorField == NULL,
- "Unable to find descriptor field in java.io.FileDescriptor");
-
return AndroidRuntime::registerNativeMethods(
env, kActivityThreadPathName,
gActivityThreadMethods, NELEM(gActivityThreadMethods));
diff --git a/core/jni/com_android_internal_graphics_NativeUtils.cpp b/core/jni/com_android_internal_graphics_NativeUtils.cpp
index 319946fc5eea..9cc43606fac5 100644
--- a/core/jni/com_android_internal_graphics_NativeUtils.cpp
+++ b/core/jni/com_android_internal_graphics_NativeUtils.cpp
@@ -29,11 +29,6 @@
namespace android
{
-static jclass class_fileDescriptor;
-static jfieldID field_fileDescriptor_descriptor;
-static jmethodID method_fileDescriptor_init;
-
-
static jboolean scrollRect(JNIEnv* env, jobject graphics2D, jobject canvas, jobject rect, int dx, int dy) {
if (canvas == NULL) {
jniThrowNullPointerException(env, NULL);
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index 61efcf26d73d..5f2065a05cdb 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -29,9 +29,6 @@
namespace android {
-static jclass gDisplay_class;
-static jclass gContext_class;
-static jclass gSurface_class;
static jclass gConfig_class;
static jmethodID gConfig_ctorID;
@@ -44,21 +41,6 @@ static jfieldID gConfig_EGLConfigFieldID;
static jfieldID gSurface_SurfaceFieldID;
static jfieldID gBitmap_NativeBitmapFieldID;
-static __attribute__((noinline))
-bool hasException(JNIEnv *env) {
- if (env->ExceptionCheck() != 0) {
- env->ExceptionDescribe();
- return true;
- }
- return false;
-}
-
-static __attribute__((noinline))
-jclass make_globalref(JNIEnv* env, const char classname[]) {
- jclass c = env->FindClass(classname);
- return (jclass)env->NewGlobalRef(c);
-}
-
static inline EGLDisplay getDisplay(JNIEnv* env, jobject o) {
if (!o) return EGL_NO_DISPLAY;
return (EGLDisplay)env->GetIntField(o, gDisplay_EGLDisplayFieldID);
@@ -77,18 +59,20 @@ static inline EGLConfig getConfig(JNIEnv* env, jobject o) {
}
static void nativeClassInit(JNIEnv *_env, jclass eglImplClass)
{
- gDisplay_class = make_globalref(_env, "com/google/android/gles_jni/EGLDisplayImpl");
- gContext_class = make_globalref(_env, "com/google/android/gles_jni/EGLContextImpl");
- gSurface_class = make_globalref(_env, "com/google/android/gles_jni/EGLSurfaceImpl");
- gConfig_class = make_globalref(_env, "com/google/android/gles_jni/EGLConfigImpl");
-
- gConfig_ctorID = _env->GetMethodID(gConfig_class, "<init>", "(I)V");
-
- gDisplay_EGLDisplayFieldID = _env->GetFieldID(gDisplay_class, "mEGLDisplay", "I");
- gContext_EGLContextFieldID = _env->GetFieldID(gContext_class, "mEGLContext", "I");
- gSurface_EGLSurfaceFieldID = _env->GetFieldID(gSurface_class, "mEGLSurface", "I");
- gSurface_NativePixelRefFieldID = _env->GetFieldID(gSurface_class, "mNativePixelRef", "I");
- gConfig_EGLConfigFieldID = _env->GetFieldID(gConfig_class, "mEGLConfig", "I");
+ jclass config_class = _env->FindClass("com/google/android/gles_jni/EGLConfigImpl");
+ gConfig_class = (jclass) _env->NewGlobalRef(config_class);
+ gConfig_ctorID = _env->GetMethodID(gConfig_class, "<init>", "(I)V");
+ gConfig_EGLConfigFieldID = _env->GetFieldID(gConfig_class, "mEGLConfig", "I");
+
+ jclass display_class = _env->FindClass("com/google/android/gles_jni/EGLDisplayImpl");
+ gDisplay_EGLDisplayFieldID = _env->GetFieldID(display_class, "mEGLDisplay", "I");
+
+ jclass context_class = _env->FindClass("com/google/android/gles_jni/EGLContextImpl");
+ gContext_EGLContextFieldID = _env->GetFieldID(context_class, "mEGLContext", "I");
+
+ jclass surface_class = _env->FindClass("com/google/android/gles_jni/EGLSurfaceImpl");
+ gSurface_EGLSurfaceFieldID = _env->GetFieldID(surface_class, "mEGLSurface", "I");
+ gSurface_NativePixelRefFieldID = _env->GetFieldID(surface_class, "mNativePixelRef", "I");
jclass bitmap_class = _env->FindClass("android/graphics/Bitmap");
gBitmap_NativeBitmapFieldID = _env->GetFieldID(bitmap_class, "mNativeBitmap", "I");
diff --git a/core/jni/com_google_android_gles_jni_GLImpl.cpp b/core/jni/com_google_android_gles_jni_GLImpl.cpp
index bf613e1550b6..8777131f2dba 100644
--- a/core/jni/com_google_android_gles_jni_GLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_GLImpl.cpp
@@ -2,21 +2,23 @@
**
** Copyright 2006, 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
+** 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
+** 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
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
// This source file is automatically generated
+#include "jni.h"
+#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
@@ -64,10 +66,6 @@ static int initialized = 0;
static jclass nioAccessClass;
static jclass bufferClass;
-static jclass OOMEClass;
-static jclass UOEClass;
-static jclass IAEClass;
-static jclass AIOOBEClass;
static jclass G11ImplClass;
static jmethodID getBasePointerID;
static jmethodID getBaseArrayID;
@@ -85,7 +83,7 @@ static jfieldID have_OES_texture_cube_mapID;
/* Cache method IDs each time the class is loaded. */
static void
-nativeClassInitBuffer(JNIEnv *_env)
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
{
jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
@@ -115,26 +113,6 @@ nativeClassInitBuffer(JNIEnv *_env)
_env->GetFieldID(bufferClass, "_elementSizeShift", "I");
}
-static void
-nativeClassInit(JNIEnv *_env, jclass glImplClass)
-{
- nativeClassInitBuffer(_env);
-
- jclass IAEClassLocal =
- _env->FindClass("java/lang/IllegalArgumentException");
- jclass OOMEClassLocal =
- _env->FindClass("java/lang/OutOfMemoryError");
- jclass UOEClassLocal =
- _env->FindClass("java/lang/UnsupportedOperationException");
- jclass AIOOBEClassLocal =
- _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
-
- IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
- OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
- UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
- AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
-}
-
static void *
getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
{
@@ -155,7 +133,7 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
*array = NULL;
return (void *) (jint) pointer;
}
-
+
*array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
getBaseArrayID, buffer);
if (*array == NULL) {
@@ -164,7 +142,7 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
offset = _env->CallStaticIntMethod(nioAccessClass,
getBaseArrayOffsetID, buffer);
data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-
+
return (void *) ((char *) data + offset);
}
@@ -208,7 +186,8 @@ getDirectBufferPointer(JNIEnv *_env, jobject buffer) {
releasePointer(_env, array, buf, 0);
}
} else {
- _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+ jniThrowException(_env, "java/lang/IllegalArgumentException",
+ "Must use a native order direct Buffer");
}
}
return buf;
@@ -251,7 +230,7 @@ nextExtension(const GLubyte* pExtensions) {
}
}
}
-
+
static bool
checkForExtension(const GLubyte* pExtensions, const GLubyte* pExtension) {
for (;*pExtensions != '\0'; pExtensions = nextExtension(pExtensions)) {
@@ -280,7 +259,6 @@ supportsExtension(JNIEnv *_env, jobject impl, jfieldID fieldId) {
}
// --------------------------------------------------------------------------
-
/* void glActiveTexture ( GLenum texture ) */
static void
android_glActiveTexture__I
@@ -557,16 +535,16 @@ android_glDeleteTextures__I_3II
GLuint *textures = (GLuint *) 0;
if (!textures_ref) {
- _env->ThrowNew(IAEClass, "textures == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "textures == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(textures_ref) - offset;
if (_remaining < n) {
- _env->ThrowNew(IAEClass, "length - offset < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
goto exit;
}
textures_base = (GLuint *)
@@ -595,7 +573,7 @@ android_glDeleteTextures__ILjava_nio_IntBuffer_2
textures = (GLuint *)getPointer(_env, textures_buf, &_array, &_remaining);
if (_remaining < n) {
- _env->ThrowNew(IAEClass, "remaining() < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
goto exit;
}
glDeleteTextures(
@@ -686,7 +664,7 @@ android_glDrawElements__IIILjava_nio_Buffer_2
indices = (GLvoid *)getPointer(_env, indices_buf, &_array, &_remaining);
if (_remaining < count) {
- _env->ThrowNew(AIOOBEClass, "remaining() < count");
+ jniThrowException(_env, "java/lang/ArrayIndexOutOfBoundsException", "remaining() < count");
goto exit;
}
glDrawElements(
@@ -753,11 +731,11 @@ android_glFogfv__I_3FI
GLfloat *params = (GLfloat *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -787,7 +765,7 @@ android_glFogfv__I_3FI
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLfloat *)
@@ -841,7 +819,7 @@ android_glFogfv__ILjava_nio_FloatBuffer_2
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glFogfv(
@@ -874,11 +852,11 @@ android_glFogxv__I_3II
GLfixed *params = (GLfixed *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -908,7 +886,7 @@ android_glFogxv__I_3II
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLfixed *)
@@ -962,7 +940,7 @@ android_glFogxv__ILjava_nio_IntBuffer_2
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glFogxv(
@@ -1024,18 +1002,18 @@ android_glGenTextures__I_3II
if (!textures_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "textures == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "textures == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(textures_ref) - offset;
if (_remaining < n) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
goto exit;
}
textures_base = (GLuint *)
@@ -1066,7 +1044,7 @@ android_glGenTextures__ILjava_nio_IntBuffer_2
textures = (GLuint *)getPointer(_env, textures_buf, &_array, &_remaining);
if (_remaining < n) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
goto exit;
}
glGenTextures(
@@ -1100,12 +1078,12 @@ android_glGetIntegerv__I_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1442,7 +1420,7 @@ android_glGetIntegerv__I_3II
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLint *)
@@ -1804,7 +1782,7 @@ android_glGetIntegerv__ILjava_nio_IntBuffer_2
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glGetIntegerv(
@@ -1818,16 +1796,10 @@ exit:
}
}
-#include <string.h>
-
/* const GLubyte * glGetString ( GLenum name ) */
-static
-jstring
-android_glGetString
- (JNIEnv *_env, jobject _this, jint name) {
- const char * chars = (const char *)glGetString((GLenum)name);
- jstring output = _env->NewStringUTF(chars);
- return output;
+static jstring android_glGetString(JNIEnv *_env, jobject, jint name) {
+ const char* chars = (const char*) glGetString((GLenum) name);
+ return _env->NewStringUTF(chars);
}
/* void glHint ( GLenum target, GLenum mode ) */
static void
@@ -1858,11 +1830,11 @@ android_glLightModelfv__I_3FI
GLfloat *params = (GLfloat *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1883,7 +1855,7 @@ android_glLightModelfv__I_3FI
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLfloat *)
@@ -1928,7 +1900,7 @@ android_glLightModelfv__ILjava_nio_FloatBuffer_2
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glLightModelfv(
@@ -1961,11 +1933,11 @@ android_glLightModelxv__I_3II
GLfixed *params = (GLfixed *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -1986,7 +1958,7 @@ android_glLightModelxv__I_3II
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLfixed *)
@@ -2031,7 +2003,7 @@ android_glLightModelxv__ILjava_nio_IntBuffer_2
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glLightModelxv(
@@ -2065,11 +2037,11 @@ android_glLightfv__II_3FI
GLfloat *params = (GLfloat *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2116,7 +2088,7 @@ android_glLightfv__II_3FI
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLfloat *)
@@ -2188,7 +2160,7 @@ android_glLightfv__IILjava_nio_FloatBuffer_2
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glLightfv(
@@ -2223,11 +2195,11 @@ android_glLightxv__II_3II
GLfixed *params = (GLfixed *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2274,7 +2246,7 @@ android_glLightxv__II_3II
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLfixed *)
@@ -2346,7 +2318,7 @@ android_glLightxv__IILjava_nio_IntBuffer_2
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glLightxv(
@@ -2395,11 +2367,11 @@ android_glLoadMatrixf___3FI
GLfloat *m = (GLfloat *) 0;
if (!m_ref) {
- _env->ThrowNew(IAEClass, "m == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "m == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(m_ref) - offset;
@@ -2444,11 +2416,11 @@ android_glLoadMatrixx___3II
GLfixed *m = (GLfixed *) 0;
if (!m_ref) {
- _env->ThrowNew(IAEClass, "m == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "m == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(m_ref) - offset;
@@ -2513,11 +2485,11 @@ android_glMaterialfv__II_3FI
GLfloat *params = (GLfloat *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2550,7 +2522,7 @@ android_glMaterialfv__II_3FI
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLfloat *)
@@ -2608,7 +2580,7 @@ android_glMaterialfv__IILjava_nio_FloatBuffer_2
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glMaterialfv(
@@ -2643,11 +2615,11 @@ android_glMaterialxv__II_3II
GLfixed *params = (GLfixed *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -2680,7 +2652,7 @@ android_glMaterialxv__II_3II
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLfixed *)
@@ -2738,7 +2710,7 @@ android_glMaterialxv__IILjava_nio_IntBuffer_2
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glMaterialxv(
@@ -2771,11 +2743,11 @@ android_glMultMatrixf___3FI
GLfloat *m = (GLfloat *) 0;
if (!m_ref) {
- _env->ThrowNew(IAEClass, "m == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "m == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(m_ref) - offset;
@@ -2820,11 +2792,11 @@ android_glMultMatrixx___3II
GLfixed *m = (GLfixed *) 0;
if (!m_ref) {
- _env->ThrowNew(IAEClass, "m == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "m == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(m_ref) - offset;
@@ -3205,11 +3177,11 @@ android_glTexEnvfv__II_3FI
GLfloat *params = (GLfloat *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -3236,7 +3208,7 @@ android_glTexEnvfv__II_3FI
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLfloat *)
@@ -3288,7 +3260,7 @@ android_glTexEnvfv__IILjava_nio_FloatBuffer_2
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glTexEnvfv(
@@ -3323,11 +3295,11 @@ android_glTexEnvxv__II_3II
GLfixed *params = (GLfixed *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -3354,7 +3326,7 @@ android_glTexEnvxv__II_3II
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLfixed *)
@@ -3406,7 +3378,7 @@ android_glTexEnvxv__IILjava_nio_IntBuffer_2
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glTexEnvxv(
@@ -3569,18 +3541,18 @@ android_glQueryMatrixxOES___3II_3II
if (!mantissa_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "mantissa == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "mantissa == null");
goto exit;
}
if (mantissaOffset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "mantissaOffset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "mantissaOffset < 0");
goto exit;
}
_mantissaRemaining = _env->GetArrayLength(mantissa_ref) - mantissaOffset;
if (_mantissaRemaining < 16) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - mantissaOffset < 16");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - mantissaOffset < 16");
goto exit;
}
mantissa_base = (GLfixed *)
@@ -3589,18 +3561,18 @@ android_glQueryMatrixxOES___3II_3II
if (!exponent_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "exponent == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "exponent == null");
goto exit;
}
if (exponentOffset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "exponentOffset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "exponentOffset < 0");
goto exit;
}
_exponentRemaining = _env->GetArrayLength(exponent_ref) - exponentOffset;
if (_exponentRemaining < 16) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - exponentOffset < 16");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - exponentOffset < 16");
goto exit;
}
exponent_base = (GLint *)
@@ -3640,13 +3612,13 @@ android_glQueryMatrixxOES__Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2
mantissa = (GLfixed *)getPointer(_env, mantissa_buf, &_mantissaArray, &_mantissaRemaining);
if (_mantissaRemaining < 16) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < 16");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 16");
goto exit;
}
exponent = (GLint *)getPointer(_env, exponent_buf, &_exponentArray, &_exponentRemaining);
if (_exponentRemaining < 16) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < 16");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 16");
goto exit;
}
_returnValue = glQueryMatrixxOES(
@@ -3685,7 +3657,7 @@ android_glBufferData__IILjava_nio_Buffer_2I
if (data_buf) {
data = (GLvoid *)getPointer(_env, data_buf, &_array, &_remaining);
if (_remaining < size) {
- _env->ThrowNew(IAEClass, "remaining() < size");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < size");
goto exit;
}
}
@@ -3712,7 +3684,7 @@ android_glBufferSubData__IIILjava_nio_Buffer_2
data = (GLvoid *)getPointer(_env, data_buf, &_array, &_remaining);
if (_remaining < size) {
- _env->ThrowNew(IAEClass, "remaining() < size");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < size");
goto exit;
}
glBufferSubData(
@@ -3737,16 +3709,16 @@ android_glClipPlanef__I_3FI
GLfloat *equation = (GLfloat *) 0;
if (!equation_ref) {
- _env->ThrowNew(IAEClass, "equation == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "equation == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(equation_ref) - offset;
if (_remaining < 4) {
- _env->ThrowNew(IAEClass, "length - offset < 4");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 4");
goto exit;
}
equation_base = (GLfloat *)
@@ -3775,7 +3747,7 @@ android_glClipPlanef__ILjava_nio_FloatBuffer_2
equation = (GLfloat *)getPointer(_env, equation_buf, &_array, &_remaining);
if (_remaining < 4) {
- _env->ThrowNew(IAEClass, "remaining() < 4");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 4");
goto exit;
}
glClipPlanef(
@@ -3798,16 +3770,16 @@ android_glClipPlanex__I_3II
GLfixed *equation = (GLfixed *) 0;
if (!equation_ref) {
- _env->ThrowNew(IAEClass, "equation == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "equation == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(equation_ref) - offset;
if (_remaining < 4) {
- _env->ThrowNew(IAEClass, "length - offset < 4");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 4");
goto exit;
}
equation_base = (GLfixed *)
@@ -3836,7 +3808,7 @@ android_glClipPlanex__ILjava_nio_IntBuffer_2
equation = (GLfixed *)getPointer(_env, equation_buf, &_array, &_remaining);
if (_remaining < 4) {
- _env->ThrowNew(IAEClass, "remaining() < 4");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 4");
goto exit;
}
glClipPlanex(
@@ -3883,16 +3855,16 @@ android_glDeleteBuffers__I_3II
GLuint *buffers = (GLuint *) 0;
if (!buffers_ref) {
- _env->ThrowNew(IAEClass, "buffers == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "buffers == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(buffers_ref) - offset;
if (_remaining < n) {
- _env->ThrowNew(IAEClass, "length - offset < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
goto exit;
}
buffers_base = (GLuint *)
@@ -3921,7 +3893,7 @@ android_glDeleteBuffers__ILjava_nio_IntBuffer_2
buffers = (GLuint *)getPointer(_env, buffers_buf, &_array, &_remaining);
if (_remaining < n) {
- _env->ThrowNew(IAEClass, "remaining() < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
goto exit;
}
glDeleteBuffers(
@@ -3958,18 +3930,18 @@ android_glGenBuffers__I_3II
if (!buffers_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "buffers == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "buffers == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(buffers_ref) - offset;
if (_remaining < n) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
goto exit;
}
buffers_base = (GLuint *)
@@ -4000,7 +3972,7 @@ android_glGenBuffers__ILjava_nio_IntBuffer_2
buffers = (GLuint *)getPointer(_env, buffers_buf, &_array, &_remaining);
if (_remaining < n) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
goto exit;
}
glGenBuffers(
@@ -4025,12 +3997,12 @@ android_glGetBooleanv__I_3ZI
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -4073,7 +4045,7 @@ android_glGetBooleanv__ILjava_nio_IntBuffer_2
static void
android_glGetBufferParameteriv__II_3II
(JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glGetBufferParameteriv");
}
@@ -4081,7 +4053,7 @@ android_glGetBufferParameteriv__II_3II
static void
android_glGetBufferParameteriv__IILjava_nio_IntBuffer_2
(JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glGetBufferParameteriv");
}
@@ -4096,12 +4068,12 @@ android_glGetClipPlanef__I_3FI
if (!eqn_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "eqn == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "eqn == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(eqn_ref) - offset;
@@ -4151,12 +4123,12 @@ android_glGetClipPlanex__I_3II
if (!eqn_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "eqn == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "eqn == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(eqn_ref) - offset;
@@ -4206,12 +4178,12 @@ android_glGetFixedv__I_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -4261,12 +4233,12 @@ android_glGetFloatv__I_3FI
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -4316,12 +4288,12 @@ android_glGetLightfv__II_3FI
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -4369,7 +4341,7 @@ android_glGetLightfv__II_3FI
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLfloat *)
@@ -4443,7 +4415,7 @@ android_glGetLightfv__IILjava_nio_FloatBuffer_2
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glGetLightfv(
@@ -4469,12 +4441,12 @@ android_glGetLightxv__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -4522,7 +4494,7 @@ android_glGetLightxv__II_3II
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLfixed *)
@@ -4596,7 +4568,7 @@ android_glGetLightxv__IILjava_nio_IntBuffer_2
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glGetLightxv(
@@ -4622,12 +4594,12 @@ android_glGetMaterialfv__II_3FI
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -4661,7 +4633,7 @@ android_glGetMaterialfv__II_3FI
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLfloat *)
@@ -4721,7 +4693,7 @@ android_glGetMaterialfv__IILjava_nio_FloatBuffer_2
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glGetMaterialfv(
@@ -4747,12 +4719,12 @@ android_glGetMaterialxv__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -4786,7 +4758,7 @@ android_glGetMaterialxv__II_3II
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLfixed *)
@@ -4846,7 +4818,7 @@ android_glGetMaterialxv__IILjava_nio_IntBuffer_2
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glGetMaterialxv(
@@ -4872,12 +4844,12 @@ android_glGetTexEnviv__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -4905,7 +4877,7 @@ android_glGetTexEnviv__II_3II
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLint *)
@@ -4959,7 +4931,7 @@ android_glGetTexEnviv__IILjava_nio_IntBuffer_2
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glGetTexEnviv(
@@ -4985,12 +4957,12 @@ android_glGetTexEnvxv__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -5018,7 +4990,7 @@ android_glGetTexEnvxv__II_3II
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLfixed *)
@@ -5072,7 +5044,7 @@ android_glGetTexEnvxv__IILjava_nio_IntBuffer_2
}
if (_remaining < _needed) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glGetTexEnvxv(
@@ -5098,18 +5070,18 @@ android_glGetTexParameterfv__II_3FI
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
if (_remaining < 1) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
goto exit;
}
params_base = (GLfloat *)
@@ -5141,7 +5113,7 @@ android_glGetTexParameterfv__IILjava_nio_FloatBuffer_2
params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining);
if (_remaining < 1) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
goto exit;
}
glGetTexParameterfv(
@@ -5167,18 +5139,18 @@ android_glGetTexParameteriv__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
if (_remaining < 1) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
goto exit;
}
params_base = (GLint *)
@@ -5210,7 +5182,7 @@ android_glGetTexParameteriv__IILjava_nio_IntBuffer_2
params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining);
if (_remaining < 1) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
goto exit;
}
glGetTexParameteriv(
@@ -5236,18 +5208,18 @@ android_glGetTexParameterxv__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
if (_remaining < 1) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
goto exit;
}
params_base = (GLfixed *)
@@ -5279,7 +5251,7 @@ android_glGetTexParameterxv__IILjava_nio_IntBuffer_2
params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining);
if (_remaining < 1) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
goto exit;
}
glGetTexParameterxv(
@@ -5357,16 +5329,16 @@ android_glPointParameterfv__I_3FI
GLfloat *params = (GLfloat *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
if (_remaining < 1) {
- _env->ThrowNew(IAEClass, "length - offset < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
goto exit;
}
params_base = (GLfloat *)
@@ -5395,7 +5367,7 @@ android_glPointParameterfv__ILjava_nio_FloatBuffer_2
params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining);
if (_remaining < 1) {
- _env->ThrowNew(IAEClass, "remaining() < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
goto exit;
}
glPointParameterfv(
@@ -5428,16 +5400,16 @@ android_glPointParameterxv__I_3II
GLfixed *params = (GLfixed *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
if (_remaining < 1) {
- _env->ThrowNew(IAEClass, "length - offset < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
goto exit;
}
params_base = (GLfixed *)
@@ -5466,7 +5438,7 @@ android_glPointParameterxv__ILjava_nio_IntBuffer_2
params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining);
if (_remaining < 1) {
- _env->ThrowNew(IAEClass, "remaining() < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
goto exit;
}
glPointParameterxv(
@@ -5534,11 +5506,11 @@ android_glTexEnviv__II_3II
GLint *params = (GLint *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -5565,7 +5537,7 @@ android_glTexEnviv__II_3II
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "length - offset < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < needed");
goto exit;
}
params_base = (GLint *)
@@ -5617,7 +5589,7 @@ android_glTexEnviv__IILjava_nio_IntBuffer_2
break;
}
if (_remaining < _needed) {
- _env->ThrowNew(IAEClass, "remaining() < needed");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < needed");
goto exit;
}
glTexEnviv(
@@ -5641,16 +5613,16 @@ android_glTexParameterfv__II_3FI
GLfloat *params = (GLfloat *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
if (_remaining < 1) {
- _env->ThrowNew(IAEClass, "length - offset < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
goto exit;
}
params_base = (GLfloat *)
@@ -5680,7 +5652,7 @@ android_glTexParameterfv__IILjava_nio_FloatBuffer_2
params = (GLfloat *)getPointer(_env, params_buf, &_array, &_remaining);
if (_remaining < 1) {
- _env->ThrowNew(IAEClass, "remaining() < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
goto exit;
}
glTexParameterfv(
@@ -5715,16 +5687,16 @@ android_glTexParameteriv__II_3II
GLint *params = (GLint *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
if (_remaining < 1) {
- _env->ThrowNew(IAEClass, "length - offset < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
goto exit;
}
params_base = (GLint *)
@@ -5754,7 +5726,7 @@ android_glTexParameteriv__IILjava_nio_IntBuffer_2
params = (GLint *)getPointer(_env, params_buf, &_array, &_remaining);
if (_remaining < 1) {
- _env->ThrowNew(IAEClass, "remaining() < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
goto exit;
}
glTexParameteriv(
@@ -5778,16 +5750,16 @@ android_glTexParameterxv__II_3II
GLfixed *params = (GLfixed *) 0;
if (!params_ref) {
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
if (_remaining < 1) {
- _env->ThrowNew(IAEClass, "length - offset < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 1");
goto exit;
}
params_base = (GLfixed *)
@@ -5817,7 +5789,7 @@ android_glTexParameterxv__IILjava_nio_IntBuffer_2
params = (GLfixed *)getPointer(_env, params_buf, &_array, &_remaining);
if (_remaining < 1) {
- _env->ThrowNew(IAEClass, "remaining() < 1");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 1");
goto exit;
}
glTexParameterxv(
@@ -5875,16 +5847,16 @@ android_glDrawTexfvOES___3FI
GLfloat *coords = (GLfloat *) 0;
if (!coords_ref) {
- _env->ThrowNew(IAEClass, "coords == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "coords == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(coords_ref) - offset;
if (_remaining < 5) {
- _env->ThrowNew(IAEClass, "length - offset < 5");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 5");
goto exit;
}
coords_base = (GLfloat *)
@@ -5912,7 +5884,7 @@ android_glDrawTexfvOES__Ljava_nio_FloatBuffer_2
coords = (GLfloat *)getPointer(_env, coords_buf, &_array, &_remaining);
if (_remaining < 5) {
- _env->ThrowNew(IAEClass, "remaining() < 5");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 5");
goto exit;
}
glDrawTexfvOES(
@@ -5947,16 +5919,16 @@ android_glDrawTexivOES___3II
GLint *coords = (GLint *) 0;
if (!coords_ref) {
- _env->ThrowNew(IAEClass, "coords == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "coords == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(coords_ref) - offset;
if (_remaining < 5) {
- _env->ThrowNew(IAEClass, "length - offset < 5");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 5");
goto exit;
}
coords_base = (GLint *)
@@ -5984,7 +5956,7 @@ android_glDrawTexivOES__Ljava_nio_IntBuffer_2
coords = (GLint *)getPointer(_env, coords_buf, &_array, &_remaining);
if (_remaining < 5) {
- _env->ThrowNew(IAEClass, "remaining() < 5");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 5");
goto exit;
}
glDrawTexivOES(
@@ -6019,16 +5991,16 @@ android_glDrawTexsvOES___3SI
GLshort *coords = (GLshort *) 0;
if (!coords_ref) {
- _env->ThrowNew(IAEClass, "coords == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "coords == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(coords_ref) - offset;
if (_remaining < 5) {
- _env->ThrowNew(IAEClass, "length - offset < 5");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 5");
goto exit;
}
coords_base = (GLshort *)
@@ -6056,7 +6028,7 @@ android_glDrawTexsvOES__Ljava_nio_ShortBuffer_2
coords = (GLshort *)getPointer(_env, coords_buf, &_array, &_remaining);
if (_remaining < 5) {
- _env->ThrowNew(IAEClass, "remaining() < 5");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 5");
goto exit;
}
glDrawTexsvOES(
@@ -6091,16 +6063,16 @@ android_glDrawTexxvOES___3II
GLfixed *coords = (GLfixed *) 0;
if (!coords_ref) {
- _env->ThrowNew(IAEClass, "coords == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "coords == null");
goto exit;
}
if (offset < 0) {
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(coords_ref) - offset;
if (_remaining < 5) {
- _env->ThrowNew(IAEClass, "length - offset < 5");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < 5");
goto exit;
}
coords_base = (GLfixed *)
@@ -6128,7 +6100,7 @@ android_glDrawTexxvOES__Ljava_nio_IntBuffer_2
coords = (GLfixed *)getPointer(_env, coords_buf, &_array, &_remaining);
if (_remaining < 5) {
- _env->ThrowNew(IAEClass, "remaining() < 5");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < 5");
goto exit;
}
glDrawTexxvOES(
@@ -6223,7 +6195,7 @@ static void
android_glBindFramebufferOES__II
(JNIEnv *_env, jobject _this, jint target, jint framebuffer) {
if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glBindFramebufferOES");
return;
}
@@ -6238,7 +6210,7 @@ static void
android_glBindRenderbufferOES__II
(JNIEnv *_env, jobject _this, jint target, jint renderbuffer) {
if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glBindRenderbufferOES");
return;
}
@@ -6253,7 +6225,7 @@ static void
android_glBlendEquation__I
(JNIEnv *_env, jobject _this, jint mode) {
if (! supportsExtension(_env, _this, have_OES_blend_subtractID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glBlendEquation");
return;
}
@@ -6267,7 +6239,7 @@ static void
android_glBlendEquationSeparate__II
(JNIEnv *_env, jobject _this, jint modeRGB, jint modeAlpha) {
if (! supportsExtension(_env, _this, have_OES_blend_equation_separateID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glBlendEquationSeparate");
return;
}
@@ -6282,7 +6254,7 @@ static void
android_glBlendFuncSeparate__IIII
(JNIEnv *_env, jobject _this, jint srcRGB, jint dstRGB, jint srcAlpha, jint dstAlpha) {
if (! supportsExtension(_env, _this, have_OES_blend_equation_separateID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glBlendFuncSeparate");
return;
}
@@ -6299,7 +6271,7 @@ static jint
android_glCheckFramebufferStatusOES__I
(JNIEnv *_env, jobject _this, jint target) {
if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glCheckFramebufferStatusOES");
return 0;
}
@@ -6315,7 +6287,7 @@ static void
android_glDeleteFramebuffersOES__I_3II
(JNIEnv *_env, jobject _this, jint n, jintArray framebuffers_ref, jint offset) {
if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glDeleteFramebuffersOES");
return;
}
@@ -6326,18 +6298,18 @@ android_glDeleteFramebuffersOES__I_3II
if (!framebuffers_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "framebuffers == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "framebuffers == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(framebuffers_ref) - offset;
if (_remaining < n) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
goto exit;
}
framebuffers_base = (GLuint *)
@@ -6361,7 +6333,7 @@ static void
android_glDeleteFramebuffersOES__ILjava_nio_IntBuffer_2
(JNIEnv *_env, jobject _this, jint n, jobject framebuffers_buf) {
if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glDeleteFramebuffersOES");
return;
}
@@ -6373,7 +6345,7 @@ android_glDeleteFramebuffersOES__ILjava_nio_IntBuffer_2
framebuffers = (GLuint *)getPointer(_env, framebuffers_buf, &_array, &_remaining);
if (_remaining < n) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
goto exit;
}
glDeleteFramebuffersOES(
@@ -6392,7 +6364,7 @@ static void
android_glDeleteRenderbuffersOES__I_3II
(JNIEnv *_env, jobject _this, jint n, jintArray renderbuffers_ref, jint offset) {
if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glDeleteRenderbuffersOES");
return;
}
@@ -6403,18 +6375,18 @@ android_glDeleteRenderbuffersOES__I_3II
if (!renderbuffers_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "renderbuffers == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "renderbuffers == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(renderbuffers_ref) - offset;
if (_remaining < n) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
goto exit;
}
renderbuffers_base = (GLuint *)
@@ -6438,7 +6410,7 @@ static void
android_glDeleteRenderbuffersOES__ILjava_nio_IntBuffer_2
(JNIEnv *_env, jobject _this, jint n, jobject renderbuffers_buf) {
if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glDeleteRenderbuffersOES");
return;
}
@@ -6450,7 +6422,7 @@ android_glDeleteRenderbuffersOES__ILjava_nio_IntBuffer_2
renderbuffers = (GLuint *)getPointer(_env, renderbuffers_buf, &_array, &_remaining);
if (_remaining < n) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
goto exit;
}
glDeleteRenderbuffersOES(
@@ -6469,7 +6441,7 @@ static void
android_glFramebufferRenderbufferOES__IIII
(JNIEnv *_env, jobject _this, jint target, jint attachment, jint renderbuffertarget, jint renderbuffer) {
if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glFramebufferRenderbufferOES");
return;
}
@@ -6486,7 +6458,7 @@ static void
android_glFramebufferTexture2DOES__IIIII
(JNIEnv *_env, jobject _this, jint target, jint attachment, jint textarget, jint texture, jint level) {
if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glFramebufferTexture2DOES");
return;
}
@@ -6504,7 +6476,7 @@ static void
android_glGenerateMipmapOES__I
(JNIEnv *_env, jobject _this, jint target) {
if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glGenerateMipmapOES");
return;
}
@@ -6518,7 +6490,7 @@ static void
android_glGenFramebuffersOES__I_3II
(JNIEnv *_env, jobject _this, jint n, jintArray framebuffers_ref, jint offset) {
if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glGenFramebuffersOES");
return;
}
@@ -6529,18 +6501,18 @@ android_glGenFramebuffersOES__I_3II
if (!framebuffers_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "framebuffers == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "framebuffers == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(framebuffers_ref) - offset;
if (_remaining < n) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
goto exit;
}
framebuffers_base = (GLuint *)
@@ -6564,7 +6536,7 @@ static void
android_glGenFramebuffersOES__ILjava_nio_IntBuffer_2
(JNIEnv *_env, jobject _this, jint n, jobject framebuffers_buf) {
if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glGenFramebuffersOES");
return;
}
@@ -6576,7 +6548,7 @@ android_glGenFramebuffersOES__ILjava_nio_IntBuffer_2
framebuffers = (GLuint *)getPointer(_env, framebuffers_buf, &_array, &_remaining);
if (_remaining < n) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
goto exit;
}
glGenFramebuffersOES(
@@ -6595,7 +6567,7 @@ static void
android_glGenRenderbuffersOES__I_3II
(JNIEnv *_env, jobject _this, jint n, jintArray renderbuffers_ref, jint offset) {
if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glGenRenderbuffersOES");
return;
}
@@ -6606,18 +6578,18 @@ android_glGenRenderbuffersOES__I_3II
if (!renderbuffers_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "renderbuffers == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "renderbuffers == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(renderbuffers_ref) - offset;
if (_remaining < n) {
_exception = 1;
- _env->ThrowNew(IAEClass, "length - offset < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "length - offset < n");
goto exit;
}
renderbuffers_base = (GLuint *)
@@ -6641,7 +6613,7 @@ static void
android_glGenRenderbuffersOES__ILjava_nio_IntBuffer_2
(JNIEnv *_env, jobject _this, jint n, jobject renderbuffers_buf) {
if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glGenRenderbuffersOES");
return;
}
@@ -6653,7 +6625,7 @@ android_glGenRenderbuffersOES__ILjava_nio_IntBuffer_2
renderbuffers = (GLuint *)getPointer(_env, renderbuffers_buf, &_array, &_remaining);
if (_remaining < n) {
_exception = 1;
- _env->ThrowNew(IAEClass, "remaining() < n");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "remaining() < n");
goto exit;
}
glGenRenderbuffersOES(
@@ -6672,7 +6644,7 @@ static void
android_glGetFramebufferAttachmentParameterivOES__III_3II
(JNIEnv *_env, jobject _this, jint target, jint attachment, jint pname, jintArray params_ref, jint offset) {
if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glGetFramebufferAttachmentParameterivOES");
return;
}
@@ -6683,12 +6655,12 @@ android_glGetFramebufferAttachmentParameterivOES__III_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -6715,7 +6687,7 @@ static void
android_glGetFramebufferAttachmentParameterivOES__IIILjava_nio_IntBuffer_2
(JNIEnv *_env, jobject _this, jint target, jint attachment, jint pname, jobject params_buf) {
if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glGetFramebufferAttachmentParameterivOES");
return;
}
@@ -6741,7 +6713,7 @@ static void
android_glGetRenderbufferParameterivOES__II_3II
(JNIEnv *_env, jobject _this, jint target, jint pname, jintArray params_ref, jint offset) {
if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glGetRenderbufferParameterivOES");
return;
}
@@ -6752,12 +6724,12 @@ android_glGetRenderbufferParameterivOES__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -6783,7 +6755,7 @@ static void
android_glGetRenderbufferParameterivOES__IILjava_nio_IntBuffer_2
(JNIEnv *_env, jobject _this, jint target, jint pname, jobject params_buf) {
if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glGetRenderbufferParameterivOES");
return;
}
@@ -6808,7 +6780,7 @@ static void
android_glGetTexGenfv__II_3FI
(JNIEnv *_env, jobject _this, jint coord, jint pname, jfloatArray params_ref, jint offset) {
if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glGetTexGenfv");
return;
}
@@ -6819,12 +6791,12 @@ android_glGetTexGenfv__II_3FI
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -6850,7 +6822,7 @@ static void
android_glGetTexGenfv__IILjava_nio_FloatBuffer_2
(JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) {
if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glGetTexGenfv");
return;
}
@@ -6875,7 +6847,7 @@ static void
android_glGetTexGeniv__II_3II
(JNIEnv *_env, jobject _this, jint coord, jint pname, jintArray params_ref, jint offset) {
if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glGetTexGeniv");
return;
}
@@ -6886,12 +6858,12 @@ android_glGetTexGeniv__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -6917,7 +6889,7 @@ static void
android_glGetTexGeniv__IILjava_nio_IntBuffer_2
(JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) {
if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glGetTexGeniv");
return;
}
@@ -6942,7 +6914,7 @@ static void
android_glGetTexGenxv__II_3II
(JNIEnv *_env, jobject _this, jint coord, jint pname, jintArray params_ref, jint offset) {
if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glGetTexGenxv");
return;
}
@@ -6953,12 +6925,12 @@ android_glGetTexGenxv__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -6984,7 +6956,7 @@ static void
android_glGetTexGenxv__IILjava_nio_IntBuffer_2
(JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) {
if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glGetTexGenxv");
return;
}
@@ -7009,7 +6981,7 @@ static jboolean
android_glIsFramebufferOES__I
(JNIEnv *_env, jobject _this, jint framebuffer) {
if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glIsFramebufferOES");
return JNI_FALSE;
}
@@ -7025,7 +6997,7 @@ static jboolean
android_glIsRenderbufferOES__I
(JNIEnv *_env, jobject _this, jint renderbuffer) {
if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glIsRenderbufferOES");
return JNI_FALSE;
}
@@ -7041,7 +7013,7 @@ static void
android_glRenderbufferStorageOES__IIII
(JNIEnv *_env, jobject _this, jint target, jint internalformat, jint width, jint height) {
if (! supportsExtension(_env, _this, have_OES_framebuffer_objectID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glRenderbufferStorageOES");
return;
}
@@ -7058,7 +7030,7 @@ static void
android_glTexGenf__IIF
(JNIEnv *_env, jobject _this, jint coord, jint pname, jfloat param) {
if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glTexGenf");
return;
}
@@ -7074,7 +7046,7 @@ static void
android_glTexGenfv__II_3FI
(JNIEnv *_env, jobject _this, jint coord, jint pname, jfloatArray params_ref, jint offset) {
if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glTexGenfv");
return;
}
@@ -7085,12 +7057,12 @@ android_glTexGenfv__II_3FI
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -7116,7 +7088,7 @@ static void
android_glTexGenfv__IILjava_nio_FloatBuffer_2
(JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) {
if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glTexGenfv");
return;
}
@@ -7141,7 +7113,7 @@ static void
android_glTexGeni__III
(JNIEnv *_env, jobject _this, jint coord, jint pname, jint param) {
if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glTexGeni");
return;
}
@@ -7157,7 +7129,7 @@ static void
android_glTexGeniv__II_3II
(JNIEnv *_env, jobject _this, jint coord, jint pname, jintArray params_ref, jint offset) {
if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glTexGeniv");
return;
}
@@ -7168,12 +7140,12 @@ android_glTexGeniv__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -7199,7 +7171,7 @@ static void
android_glTexGeniv__IILjava_nio_IntBuffer_2
(JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) {
if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glTexGeniv");
return;
}
@@ -7224,7 +7196,7 @@ static void
android_glTexGenx__III
(JNIEnv *_env, jobject _this, jint coord, jint pname, jint param) {
if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glTexGenx");
return;
}
@@ -7240,7 +7212,7 @@ static void
android_glTexGenxv__II_3II
(JNIEnv *_env, jobject _this, jint coord, jint pname, jintArray params_ref, jint offset) {
if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glTexGenxv");
return;
}
@@ -7251,12 +7223,12 @@ android_glTexGenxv__II_3II
if (!params_ref) {
_exception = 1;
- _env->ThrowNew(IAEClass, "params == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "params == null");
goto exit;
}
if (offset < 0) {
_exception = 1;
- _env->ThrowNew(IAEClass, "offset < 0");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "offset < 0");
goto exit;
}
_remaining = _env->GetArrayLength(params_ref) - offset;
@@ -7282,7 +7254,7 @@ static void
android_glTexGenxv__IILjava_nio_IntBuffer_2
(JNIEnv *_env, jobject _this, jint coord, jint pname, jobject params_buf) {
if (! supportsExtension(_env, _this, have_OES_texture_cube_mapID)) {
- _env->ThrowNew(UOEClass,
+ jniThrowException(_env, "java/lang/UnsupportedOperationException",
"glTexGenxv");
return;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 2a4d1b23332b..7f1812164511 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -607,6 +607,13 @@
android:label="@string/permlab_reorderTasks"
android:description="@string/permdesc_reorderTasks" />
+ <!-- Allows an application to change to remove/kill tasks -->
+ <permission android:name="android.permission.REMOVE_TASKS"
+ android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+ android:protectionLevel="signature"
+ android:label="@string/permlab_removeTasks"
+ android:description="@string/permdesc_removeTasks" />
+
<!-- Allows an application to modify the current configuration, such
as locale. -->
<permission android:name="android.permission.CHANGE_CONFIGURATION"
diff --git a/core/res/res/raw/execute_script_android.js b/core/res/res/raw/execute_script_android.js
new file mode 100644
index 000000000000..d145754a4b1a
--- /dev/null
+++ b/core/res/res/raw/execute_script_android.js
@@ -0,0 +1,8 @@
+function(){return function(){function h(a){var b=typeof a;if(b=="object")if(a){if(a instanceof Array)return"array";else if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if(c=="[object Window]")return"object";if(c=="[object Array]"||typeof a.length=="number"&&typeof a.splice!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("splice"))return"array";if(c=="[object Function]"||typeof a.call!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("call"))return"function"}else return"null";
+else if(b=="function"&&typeof a.call=="undefined")return"object";return b}function i(a){var b=h(a);return b=="array"||b=="object"&&typeof a.length=="number"}function j(a){a=h(a);return a=="object"||a=="array"||a=="function"}var k=Date.now||function(){return+new Date};function l(a,b){function c(){}c.prototype=b.prototype;a.c=b.prototype;a.prototype=new c};function m(a){this.stack=Error().stack||"";if(a)this.message=String(a)}l(m,Error);m.prototype.name="CustomError";function n(a,b,c){var d={};for(var e in a)if(b.call(c,a[e],e,a))d[e]=a[e];return d}function o(a,b,c){var d={};for(var e in a)d[e]=b.call(c,a[e],e,a);return d}function p(a,b,c){for(var d in a)if(b.call(c,a[d],d,a))return d};function q(a,b){m.call(this,b);this.code=a;this.name=r[a]||r[13]}l(q,m);var r,s={NoSuchElementError:7,NoSuchFrameError:8,UnknownCommandError:9,StaleElementReferenceError:10,ElementNotVisibleError:11,InvalidElementStateError:12,UnknownError:13,ElementNotSelectableError:15,XPathLookupError:19,NoSuchWindowError:23,InvalidCookieDomainError:24,UnableToSetCookieError:25,ModalDialogOpenedError:26,ModalDialogOpenError:27,ScriptTimeoutError:28},t={};for(var u in s)t[s[u]]=u;r=t;
+q.prototype.toString=function(){return"["+this.name+"] "+this.message};function v(a){for(var b=1;b<arguments.length;b++){var c=String(arguments[b]).replace(/\$/g,"$$$$");a=a.replace(/\%s/,c)}return a};function w(a,b){b.unshift(a);m.call(this,v.apply(null,b));b.shift();this.b=a}l(w,m);w.prototype.name="AssertionError";function x(a,b){if(!a){var c=Array.prototype.slice.call(arguments,2),d="Assertion failed";if(b){d+=": "+b;var e=c}throw new w(""+d,e||[]);}return a};var y=Array.prototype,z=y.map?function(a,b,c){x(a.length!=null);return y.map.call(a,b,c)}:function(a,b,c){var d=a.length,e=Array(d),f=typeof a=="string"?a.split(""):a;for(var g=0;g<d;g++)if(g in f)e[g]=b.call(c,f[g],g,a);return e};var A="",B;if(B=/WebKit\/(\S+)/){var C=B.exec(this.navigator?this.navigator.userAgent:null);A=C?C[1]:""};function D(){}
+function E(a,b,c){switch(typeof b){case "string":F(a,b,c);break;case "number":c.push(isFinite(b)&&!isNaN(b)?b:"null");break;case "boolean":c.push(b);break;case "undefined":c.push("null");break;case "object":if(b==null){c.push("null");break}if(h(b)=="array"){var d=b.length;c.push("[");var e="";for(var f=0;f<d;f++){c.push(e);E(a,b[f],c);e=","}c.push("]");break}c.push("{");d="";for(e in b)if(Object.prototype.hasOwnProperty.call(b,e)){f=b[e];if(typeof f!="function"){c.push(d);F(a,e,c);c.push(":");E(a,
+f,c);d=","}}c.push("}");break;case "function":break;default:throw Error("Unknown type: "+typeof b);}}var G={'"':'\\"',"\\":"\\\\","/":"\\/","\u0008":"\\b","\u000c":"\\f","\n":"\\n","\r":"\\r","\t":"\\t","\u000b":"\\u000b"},H=/\uffff/.test("\uffff")?/[\\\"\x00-\x1f\x7f-\uffff]/g:/[\\\"\x00-\x1f\x7f-\xff]/g;
+function F(a,b,c){c.push('"',b.replace(H,function(d){if(d in G)return G[d];var e=d.charCodeAt(0),f="\\u";if(e<16)f+="000";else if(e<256)f+="00";else if(e<4096)f+="0";return G[d]=f+e.toString(16)}),'"')};function I(a){switch(h(a)){case "string":case "number":case "boolean":return a;case "function":return a.toString();case "array":return z(a,I);case "object":a=a;if("tagName"in a&&"nodeType"in a&&a.nodeType==1){var b={};b.ELEMENT=J(a);return b}if(i(a))return z(a,I);a=n(a,function(c,d){return typeof d=="number"||typeof d=="string"});return o(a,I);default:return null}}
+function K(a,b){if(h(a)=="array")return z(a,function(c){return K(c,b)});else if(j(a))return"ELEMENT"in a?L(a.ELEMENT,b):o(a,function(c){return K(c,b)});return a}function M(a){a=a||document;var b=a.$wdc_;if(!b){b=a.$wdc_={};b.a=k()}return b}function J(a){var b=M(a.ownerDocument),c=p(b,function(d){return d==a});if(!c){c=":wdc:"+b.a++;b[c]=a}return c}
+function L(a,b){a=decodeURIComponent(a);var c=b||document,d=M(c);if(!(a in d))throw new q(10,"Element does not exist in cache");var e=d[a];for(var f=e;f;){if(f==c.documentElement)return e;f=f.parentNode}delete d[a];throw new q(10,"Element is no longer attached to the DOM");};function N(a,b,c){var d;try{if(typeof a=="string")a=new Function(a);var e=K(b),f=a.apply(null,e);d={status:0,value:I(f)}}catch(g){d={status:"code"in g?g.code:13,value:{message:g.message}}}if(c){a=[];E(new D,d,a);d=a.join("")}else d=d;return d}var O="_".split("."),P=this;!(O[0]in P)&&P.execScript&&P.execScript("var "+O[0]);for(var Q;O.length&&(Q=O.shift());)if(!O.length&&N!==undefined)P[Q]=N;else P=P[Q]?P[Q]:P[Q]={};; return this._.apply(null,arguments);}.apply({navigator:typeof window!='undefined'?window.navigator:null}, arguments);}
diff --git a/core/res/res/raw/find_element_android.js b/core/res/res/raw/find_element_android.js
new file mode 100644
index 000000000000..f49322383dd4
--- /dev/null
+++ b/core/res/res/raw/find_element_android.js
@@ -0,0 +1,26 @@
+function(){return function(){var i=this;
+function j(a){var b=typeof a;if(b=="object")if(a){if(a instanceof Array)return"array";else if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if(c=="[object Window]")return"object";if(c=="[object Array]"||typeof a.length=="number"&&typeof a.splice!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("splice"))return"array";if(c=="[object Function]"||typeof a.call!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("call"))return"function"}else return"null";else if(b==
+"function"&&typeof a.call=="undefined")return"object";return b}function aa(a){var b=j(a);return b=="array"||b=="object"&&typeof a.length=="number"}function k(a){return typeof a=="string"}function l(a){return j(a)=="function"}function ba(a){a=j(a);return a=="object"||a=="array"||a=="function"}var ca=Date.now||function(){return+new Date};function m(a,b){function c(){}c.prototype=b.prototype;a.m=b.prototype;a.prototype=new c};function n(a){this.stack=Error().stack||"";if(a)this.message=String(a)}m(n,Error);n.prototype.name="CustomError";function da(a,b,c){var d={};for(var e in a)if(b.call(c,a[e],e,a))d[e]=a[e];return d}function ea(a,b,c){var d={};for(var e in a)d[e]=b.call(c,a[e],e,a);return d}function fa(a,b,c){for(var d in a)if(b.call(c,a[d],d,a))return d};function o(a,b){n.call(this,b);this.code=a;this.name=p[a]||p[13]}m(o,n);var p,ga={NoSuchElementError:7,NoSuchFrameError:8,UnknownCommandError:9,StaleElementReferenceError:10,ElementNotVisibleError:11,InvalidElementStateError:12,UnknownError:13,ElementNotSelectableError:15,XPathLookupError:19,NoSuchWindowError:23,InvalidCookieDomainError:24,UnableToSetCookieError:25,ModalDialogOpenedError:26,ModalDialogOpenError:27,ScriptTimeoutError:28},ha={};for(var ia in ga)ha[ga[ia]]=ia;p=ha;
+o.prototype.toString=function(){return"["+this.name+"] "+this.message};function ja(a){for(var b=1;b<arguments.length;b++){var c=String(arguments[b]).replace(/\$/g,"$$$$");a=a.replace(/\%s/,c)}return a}function q(a){return a.replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")}function r(a,b){if(a<b)return-1;else if(a>b)return 1;return 0}var ka={};function la(a){return ka[a]||(ka[a]=String(a).replace(/\-([a-z])/g,function(b,c){return c.toUpperCase()}))};function s(a,b){b.unshift(a);n.call(this,ja.apply(null,b));b.shift();this.n=a}m(s,n);s.prototype.name="AssertionError";function t(a,b){if(!a){var c=Array.prototype.slice.call(arguments,2),d="Assertion failed";if(b){d+=": "+b;var e=c}throw new s(""+d,e||[]);}return a};var u=Array.prototype,ma=u.indexOf?function(a,b,c){t(a.length!=null);return u.indexOf.call(a,b,c)}:function(a,b,c){c=c==null?0:c<0?Math.max(0,a.length+c):c;if(k(a)){if(!k(b)||b.length!=1)return-1;return a.indexOf(b,c)}for(c=c;c<a.length;c++)if(c in a&&a[c]===b)return c;return-1},na=u.forEach?function(a,b,c){t(a.length!=null);u.forEach.call(a,b,c)}:function(a,b,c){var d=a.length,e=k(a)?a.split(""):a;for(var f=0;f<d;f++)f in e&&b.call(c,e[f],f,a)},v=u.filter?function(a,b,c){t(a.length!=null);return u.filter.call(a,
+b,c)}:function(a,b,c){var d=a.length,e=[],f=0,g=k(a)?a.split(""):a;for(var h=0;h<d;h++)if(h in g){var G=g[h];if(b.call(c,G,h,a))e[f++]=G}return e},w=u.map?function(a,b,c){t(a.length!=null);return u.map.call(a,b,c)}:function(a,b,c){var d=a.length,e=Array(d),f=k(a)?a.split(""):a;for(var g=0;g<d;g++)if(g in f)e[g]=b.call(c,f[g],g,a);return e},oa=u.some?function(a,b,c){t(a.length!=null);return u.some.call(a,b,c)}:function(a,b,c){var d=a.length,e=k(a)?a.split(""):a;for(var f=0;f<d;f++)if(f in e&&b.call(c,
+e[f],f,a))return true;return false};function x(a,b,c){a:{var d=a.length,e=k(a)?a.split(""):a;for(var f=0;f<d;f++)if(f in e&&b.call(c,e[f],f,a)){b=f;break a}b=-1}return b<0?null:k(a)?a.charAt(b):a[b]};var A=true,pa,qa="",B;if(A)B=/WebKit\/(\S+)/;if(B){var ra=B.exec(i.navigator?i.navigator.userAgent:null);qa=ra?ra[1]:""}pa=qa;var sa={};var ta;function C(a,b){this.width=a;this.height=b}C.prototype.toString=function(){return"("+this.width+" x "+this.height+")"};function D(a){return a?new E(F(a)):ta||(ta=new E)}function H(a,b){if(a.contains&&b.nodeType==1)return a==b||a.contains(b);if(typeof a.compareDocumentPosition!="undefined")return a==b||Boolean(a.compareDocumentPosition(b)&16);for(;b&&a!=b;)b=b.parentNode;return b==a}function F(a){return a.nodeType==9?a:a.ownerDocument||a.document}function ua(a,b){var c=[];return va(a,b,c,true)?c[0]:undefined}
+function va(a,b,c,d){if(a!=null){var e=0;for(var f;f=a.childNodes[e];e++){if(b(f)){c.push(f);if(d)return true}if(va(f,b,c,d))return true}}return false}function wa(a,b,c,d){if(!c)a=a.parentNode;c=d==null;for(var e=0;a&&(c||e<=d);){if(b(a))return a;a=a.parentNode;e++}return null}function E(a){this.g=a||i.document||document}
+function I(a,b,c,d){a=d||a.g;b=b&&b!="*"?b.toUpperCase():"";if(d=a.querySelectorAll){if(d=a.querySelector){if(!(d=!A)){if(!(d=document.compatMode=="CSS1Compat")){if(!(d=sa["528"])){d=0;var e=q(String(pa)).split("."),f=q(String("528")).split("."),g=Math.max(e.length,f.length);for(var h=0;d==0&&h<g;h++){var G=e[h]||"",Oa=f[h]||"",Pa=RegExp("(\\d*)(\\D*)","g"),Qa=RegExp("(\\d*)(\\D*)","g");do{var y=Pa.exec(G)||["","",""],z=Qa.exec(Oa)||["","",""];if(y[0].length==0&&z[0].length==0)break;d=r(y[1].length==
+0?0:parseInt(y[1],10),z[1].length==0?0:parseInt(z[1],10))||r(y[2].length==0,z[2].length==0)||r(y[2],z[2])}while(d==0)}d=sa["528"]=d>=0}d=d}d=d}d=d}d=d}if(d&&(b||c))c=a.querySelectorAll(b+(c?"."+c:""));else if(c&&a.getElementsByClassName){a=a.getElementsByClassName(c);if(b){d={};f=e=0;for(;g=a[f];f++)if(b==g.nodeName)d[e++]=g;d.length=e;c=d}else c=a}else{a=a.getElementsByTagName(b||"*");if(c){d={};e=0;for(f=0;g=a[f];f++){b=g.className;if(typeof b.split=="function"&&ma(b.split(/\s+/),c)>=0)d[e++]=g}d.length=
+e;c=d}else c=a}return c}E.prototype.contains=H;function xa(){}
+function J(a,b,c){switch(typeof b){case "string":ya(a,b,c);break;case "number":c.push(isFinite(b)&&!isNaN(b)?b:"null");break;case "boolean":c.push(b);break;case "undefined":c.push("null");break;case "object":if(b==null){c.push("null");break}if(j(b)=="array"){var d=b.length;c.push("[");var e="";for(var f=0;f<d;f++){c.push(e);J(a,b[f],c);e=","}c.push("]");break}c.push("{");d="";for(e in b)if(Object.prototype.hasOwnProperty.call(b,e)){f=b[e];if(typeof f!="function"){c.push(d);ya(a,e,c);c.push(":");J(a,
+f,c);d=","}}c.push("}");break;case "function":break;default:throw Error("Unknown type: "+typeof b);}}var K={'"':'\\"',"\\":"\\\\","/":"\\/","\u0008":"\\b","\u000c":"\\f","\n":"\\n","\r":"\\r","\t":"\\t","\u000b":"\\u000b"},za=/\uffff/.test("\uffff")?/[\\\"\x00-\x1f\x7f-\uffff]/g:/[\\\"\x00-\x1f\x7f-\xff]/g;
+function ya(a,b,c){c.push('"',b.replace(za,function(d){if(d in K)return K[d];var e=d.charCodeAt(0),f="\\u";if(e<16)f+="000";else if(e<256)f+="00";else if(e<4096)f+="0";return K[d]=f+e.toString(16)}),'"')};function L(a){switch(j(a)){case "string":case "number":case "boolean":return a;case "function":return a.toString();case "array":return w(a,L);case "object":a=a;if("tagName"in a&&"nodeType"in a&&a.nodeType==1){var b={};b.ELEMENT=Aa(a);return b}if(aa(a))return w(a,L);a=da(a,function(c,d){return typeof d=="number"||k(d)});return ea(a,L);default:return null}}
+function M(a,b){if(j(a)=="array")return w(a,function(c){return M(c,b)});else if(ba(a))return"ELEMENT"in a?Ba(a.ELEMENT,b):ea(a,function(c){return M(c,b)});return a}function Ca(a){a=a||document;var b=a.$wdc_;if(!b){b=a.$wdc_={};b.l=ca()}return b}function Aa(a){var b=Ca(a.ownerDocument),c=fa(b,function(d){return d==a});if(!c){c=":wdc:"+b.l++;b[c]=a}return c}
+function Ba(a,b){a=decodeURIComponent(a);var c=b||document,d=Ca(c);if(!(a in d))throw new o(10,"Element does not exist in cache");var e=d[a];for(var f=e;f;){if(f==c.documentElement)return e;f=f.parentNode}delete d[a];throw new o(10,"Element is no longer attached to the DOM");};var Da=window;var N={};N.b=function(a,b){if(!a)throw Error("No class name specified");a=q(a);if(a.split(/\s+/).length>1)throw Error("Compound class names not permitted");var c=I(D(b),"*",a,b);return c.length?c[0]:null};N.e=function(a,b){if(!a)throw Error("No class name specified");a=q(a);if(a.split(/\s+/).length>1)throw Error("Compound class names not permitted");return I(D(b),"*",a,b)};var O={};O.b=function(a,b){if(!l(b.querySelector)&&0)throw Error("CSS selection is not supported");if(!a)throw Error("No selector specified");if(a.split(/,/).length>1)throw Error("Compound selectors not permitted");a=q(a);var c=b.querySelector(a);return c&&c.nodeType==1?c:null};O.e=function(a,b){if(!l(b.querySelectorAll)&&0)throw Error("CSS selection is not supported");if(!a)throw Error("No selector specified");if(a.split(/,/).length>1)throw Error("Compound selectors not permitted");a=q(a);return b.querySelectorAll(a)};function Ea(a,b){if(typeof a.selectNodes!="undefined"){var c=F(a);typeof c.setProperty!="undefined"&&c.setProperty("SelectionLanguage","XPath");return a.selectNodes(b)}else if(document.implementation.hasFeature("XPath","3.0")){c=F(a);var d=c.createNSResolver(c.documentElement);c=c.evaluate(b,a,d,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null);d=[];var e=c.snapshotLength;for(var f=0;f<e;f++)d.push(c.snapshotItem(f));return d}else return[]};var P={};P.b=function(a,b){try{var c;if(typeof b.selectSingleNode!="undefined"){var d=F(b);typeof d.setProperty!="undefined"&&d.setProperty("SelectionLanguage","XPath");c=b.selectSingleNode(a)}else if(document.implementation.hasFeature("XPath","3.0")){d=F(b);var e=d.createNSResolver(d.documentElement);c=d.evaluate(a,b,e,XPathResult.FIRST_ORDERED_NODE_TYPE,null).singleNodeValue}else c=null}catch(f){return null}if(!c)return null;if(c.nodeType!=1)throw Error("Returned node is not an element: "+a);return c};
+P.e=function(a,b){var c=Ea(b,a);na(c,function(d){if(d.nodeType!=1)throw Error("Returned nodes must be elements: "+a);});return c};var Fa="StopIteration"in i?i.StopIteration:Error("StopIteration");function Ga(){}Ga.prototype.next=function(){throw Fa;};function Q(a,b,c,d,e){this.a=!!b;a&&R(this,a,d);this.f=e!=undefined?e:this.d||0;if(this.a)this.f*=-1;this.k=!c}m(Q,Ga);Q.prototype.c=null;Q.prototype.d=0;Q.prototype.j=false;function R(a,b,c,d){if(a.c=b)a.d=typeof c=="number"?c:a.c.nodeType!=1?0:a.a?-1:1;if(typeof d=="number")a.f=d}
+Q.prototype.next=function(){var a;if(this.j){if(!this.c||this.k&&this.f==0)throw Fa;a=this.c;var b=this.a?-1:1;if(this.d==b){var c=this.a?a.lastChild:a.firstChild;c?R(this,c):R(this,a,b*-1)}else(c=this.a?a.previousSibling:a.nextSibling)?R(this,c):R(this,a.parentNode,b*-1);this.f+=this.d*(this.a?-1:1)}else this.j=true;a=this.c;if(!this.c)throw Fa;return a};
+Q.prototype.splice=function(){var a=this.c,b=this.a?1:-1;if(this.d==b){this.d=b*-1;this.f+=this.d*(this.a?-1:1)}this.a=!this.a;Q.prototype.next.call(this);this.a=!this.a;b=aa(arguments[0])?arguments[0]:arguments;for(var c=b.length-1;c>=0;c--)a.parentNode&&a.parentNode.insertBefore(b[c],a.nextSibling);a&&a.parentNode&&a.parentNode.removeChild(a)};function Ha(a,b,c,d){Q.call(this,a,b,c,null,d)}m(Ha,Q);Ha.prototype.next=function(){do Ha.m.next.call(this);while(this.d==-1);return this.c};function Ia(a,b){var c=F(a);if(c.defaultView&&c.defaultView.getComputedStyle)if(c=c.defaultView.getComputedStyle(a,null))return c[b]||c.getPropertyValue(b);return""};function S(a,b){return!!a&&a.nodeType==1&&(!b||a.tagName.toUpperCase()==b)}
+var Ja=["async","autofocus","autoplay","checked","compact","complete","controls","declare","defaultchecked","defaultselected","defer","disabled","draggable","ended","formnovalidate","hidden","indeterminate","iscontenteditable","ismap","itemscope","loop","multiple","muted","nohref","noresize","noshade","novalidate","nowrap","open","paused","pubdate","readonly","required","reversed","scoped","seamless","seeking","selected","spellcheck","truespeed","willvalidate"];
+function T(a,b){if(8==a.nodeType)return null;b=b.toLowerCase();if(b=="style"){var c=q(a.style.cssText).toLowerCase();return c.charAt(c.length-1)==";"?c:c+";"}c=a.getAttributeNode(b);if(!c)return null;if(ma(Ja,b)>=0)return"true";return c.specified?c.value:null}function U(a){for(a=a.parentNode;a&&a.nodeType!=1&&a.nodeType!=9&&a.nodeType!=11;)a=a.parentNode;return S(a)?a:null}function V(a,b){b=la(String(b));return Ia(a,b)||Ka(a,b)}
+function Ka(a,b){var c=(a.currentStyle||a.style)[b];if(c!="inherit")return c!==undefined?c:null;return(c=U(a))?Ka(c,b):null}
+function La(a){if(l(a.getBBox))return a.getBBox();var b;if((Ia(a,"display")||(a.currentStyle?a.currentStyle.display:null)||a.style.display)!="none")b=new C(a.offsetWidth,a.offsetHeight);else{b=a.style;var c=b.display,d=b.visibility,e=b.position;b.visibility="hidden";b.position="absolute";b.display="inline";var f;f=a.offsetWidth;a=a.offsetHeight;b.display=c;b.position=e;b.visibility=d;b=new C(f,a)}return b}
+function W(a,b){function c(f){if(V(f,"display")=="none")return false;f=U(f);return!f||c(f)}function d(f){var g=La(f);if(g.height>0&&g.width>0)return true;if(f.innerText||f.textContent)if(Ma.test(f.innerText||f.textContent))return true;return A&&oa(f.childNodes,function(h){return S(h)&&d(h)})}if(!S(a))throw Error("Argument to isShown must be of type Element");if(S(a,"TITLE"))return(F(a)?F(a).parentWindow||F(a).defaultView:window)==Da;if(S(a,"OPTION")||S(a,"OPTGROUP")){var e=wa(a,function(f){return S(f,
+"SELECT")});return!!e&&W(e)}if(S(a,"MAP")){if(!a.name)return false;e=F(a);e=e.evaluate?P.b('/descendant::*[@usemap = "#'+a.name+'"]',e):ua(e,function(f){return S(f)&&T(f,"usemap")=="#"+a.name});return!!e&&W(e)}if(S(a,"AREA")){e=wa(a,function(f){return S(f,"MAP")});return!!e&&W(e)}if(S(a,"INPUT")&&a.type.toLowerCase()=="hidden")return false;if(V(a,"visibility")=="hidden")return false;if(!c(a))return false;if(!b&&Na(a)==0)return false;if(!d(a))return false;return true}
+function Ra(a){var b=[""];Sa(a,b);b=w(b,q);return q(b.join("\n"))}function Sa(a,b){if(S(a,"BR"))b.push("");else{var c=Ta(a);c&&b[b.length-1]&&b.push("");na(a.childNodes,function(d){if(d.nodeType==3){var e=U(d);if(e){W(e);if(e&&W(e)){d=d.nodeValue.replace(Ua," ");e=b.pop();var f=e.length-1;if(f>=0&&e.indexOf(" ",f)==f&&d.lastIndexOf(" ",0)==0)d=d.substr(1);b.push(e+d)}}}else S(d)&&Sa(d,b)});c&&b[b.length-1]&&b.push("")}}function Ta(a){a=V(a,"display");return a=="block"||a=="inline-block"}
+var Va="[\\s\\xa0"+String.fromCharCode(160)+"]+",Ua=RegExp(Va,"g"),Ma=RegExp("^"+Va+"$");function Na(a){var b=1,c=V(a,"opacity");if(c)b=Number(c);if(a=U(a))b*=Na(a);return b};var Wa={};Wa.b=function(a,b){var c=D(b),d=k(a)?c.g.getElementById(a):a;if(!d)return null;if(T(d,"id")==a&&H(b,d))return d;c=I(c,"*");return x(c,function(e){return T(e,"id")==a&&H(b,e)})};Wa.e=function(a,b){var c=I(D(b),"*",null,b);return v(c,function(d){return T(d,"id")==a})};var X={},Xa={};X.i=function(a,b,c){b=I(D(b),"A",null,b);return x(b,function(d){d=Ra(d);return c&&d.indexOf(a)!=-1||d==a})};X.h=function(a,b,c){b=I(D(b),"A",null,b);return v(b,function(d){d=Ra(d);return c&&d.indexOf(a)!=-1||d==a})};X.b=function(a,b){return X.i(a,b,false)};X.e=function(a,b){return X.h(a,b,false)};Xa.b=function(a,b){return X.i(a,b,true)};Xa.e=function(a,b){return X.h(a,b,true)};var Ya={};Ya.b=function(a,b){var c=I(D(b),"*",null,b);return x(c,function(d){return T(d,"name")==a})};Ya.e=function(a,b){var c=I(D(b),"*",null,b);return v(c,function(d){return T(d,"name")==a})};var Za={};Za.b=function(a,b){return I(D(b),a,null,b)[0]||null};Za.e=function(a,b){return I(D(b),a,null,b)};var $a={className:N,css:O,id:Wa,linkText:X,name:Ya,partialLinkText:Xa,tagName:Za,xpath:P};function ab(a,b){var c;a:{for(c in a){c=c;break a}c=void 0}if(c){var d=$a[c];if(d&&l(d.b))return d.b(a[c],b||F(Da))}throw Error("Unsupported locator strategy: "+c);};function bb(a,b,c){var d={};d[a]=b;a=ab;c=[d,c];var e;try{if(k(a))a=new Function(a);var f=M(c),g=a.apply(null,f);e={status:0,value:L(g)}}catch(h){e={status:"code"in h?h.code:13,value:{message:h.message}}}f=[];J(new xa,e,f);return f.join("")}var Y="_".split("."),Z=i;!(Y[0]in Z)&&Z.execScript&&Z.execScript("var "+Y[0]);for(var $;Y.length&&($=Y.shift());)if(!Y.length&&bb!==undefined)Z[$]=bb;else Z=Z[$]?Z[$]:Z[$]={};; return this._.apply(null,arguments);}.apply({navigator:typeof window!='undefined'?window.navigator:null}, arguments);}
diff --git a/core/res/res/raw/find_elements_android.js b/core/res/res/raw/find_elements_android.js
new file mode 100644
index 000000000000..796da586b646
--- /dev/null
+++ b/core/res/res/raw/find_elements_android.js
@@ -0,0 +1,26 @@
+function(){return function(){var i=this;
+function j(a){var b=typeof a;if(b=="object")if(a){if(a instanceof Array)return"array";else if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if(c=="[object Window]")return"object";if(c=="[object Array]"||typeof a.length=="number"&&typeof a.splice!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("splice"))return"array";if(c=="[object Function]"||typeof a.call!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("call"))return"function"}else return"null";else if(b==
+"function"&&typeof a.call=="undefined")return"object";return b}function aa(a){var b=j(a);return b=="array"||b=="object"&&typeof a.length=="number"}function k(a){return typeof a=="string"}function l(a){return j(a)=="function"}function ba(a){a=j(a);return a=="object"||a=="array"||a=="function"}var ca=Date.now||function(){return+new Date};function m(a,b){function c(){}c.prototype=b.prototype;a.m=b.prototype;a.prototype=new c};function n(a){this.stack=Error().stack||"";if(a)this.message=String(a)}m(n,Error);n.prototype.name="CustomError";function da(a,b,c){var d={};for(var e in a)if(b.call(c,a[e],e,a))d[e]=a[e];return d}function ea(a,b,c){var d={};for(var e in a)d[e]=b.call(c,a[e],e,a);return d}function fa(a,b,c){for(var d in a)if(b.call(c,a[d],d,a))return d};function o(a,b){n.call(this,b);this.code=a;this.name=p[a]||p[13]}m(o,n);var p,ga={NoSuchElementError:7,NoSuchFrameError:8,UnknownCommandError:9,StaleElementReferenceError:10,ElementNotVisibleError:11,InvalidElementStateError:12,UnknownError:13,ElementNotSelectableError:15,XPathLookupError:19,NoSuchWindowError:23,InvalidCookieDomainError:24,UnableToSetCookieError:25,ModalDialogOpenedError:26,ModalDialogOpenError:27,ScriptTimeoutError:28},ha={};for(var ia in ga)ha[ga[ia]]=ia;p=ha;
+o.prototype.toString=function(){return"["+this.name+"] "+this.message};function ja(a){for(var b=1;b<arguments.length;b++){var c=String(arguments[b]).replace(/\$/g,"$$$$");a=a.replace(/\%s/,c)}return a}function q(a){return a.replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")}function r(a,b){if(a<b)return-1;else if(a>b)return 1;return 0}var ka={};function la(a){return ka[a]||(ka[a]=String(a).replace(/\-([a-z])/g,function(b,c){return c.toUpperCase()}))};function s(a,b){b.unshift(a);n.call(this,ja.apply(null,b));b.shift();this.n=a}m(s,n);s.prototype.name="AssertionError";function t(a,b){if(!a){var c=Array.prototype.slice.call(arguments,2),d="Assertion failed";if(b){d+=": "+b;var e=c}throw new s(""+d,e||[]);}return a};var u=Array.prototype,ma=u.indexOf?function(a,b,c){t(a.length!=null);return u.indexOf.call(a,b,c)}:function(a,b,c){c=c==null?0:c<0?Math.max(0,a.length+c):c;if(k(a)){if(!k(b)||b.length!=1)return-1;return a.indexOf(b,c)}for(c=c;c<a.length;c++)if(c in a&&a[c]===b)return c;return-1},na=u.forEach?function(a,b,c){t(a.length!=null);u.forEach.call(a,b,c)}:function(a,b,c){var d=a.length,e=k(a)?a.split(""):a;for(var f=0;f<d;f++)f in e&&b.call(c,e[f],f,a)},v=u.filter?function(a,b,c){t(a.length!=null);return u.filter.call(a,
+b,c)}:function(a,b,c){var d=a.length,e=[],f=0,g=k(a)?a.split(""):a;for(var h=0;h<d;h++)if(h in g){var G=g[h];if(b.call(c,G,h,a))e[f++]=G}return e},w=u.map?function(a,b,c){t(a.length!=null);return u.map.call(a,b,c)}:function(a,b,c){var d=a.length,e=Array(d),f=k(a)?a.split(""):a;for(var g=0;g<d;g++)if(g in f)e[g]=b.call(c,f[g],g,a);return e},oa=u.some?function(a,b,c){t(a.length!=null);return u.some.call(a,b,c)}:function(a,b,c){var d=a.length,e=k(a)?a.split(""):a;for(var f=0;f<d;f++)if(f in e&&b.call(c,
+e[f],f,a))return true;return false};function x(a,b,c){a:{var d=a.length,e=k(a)?a.split(""):a;for(var f=0;f<d;f++)if(f in e&&b.call(c,e[f],f,a)){b=f;break a}b=-1}return b<0?null:k(a)?a.charAt(b):a[b]};var A=true,pa,qa="",B;if(A)B=/WebKit\/(\S+)/;if(B){var ra=B.exec(i.navigator?i.navigator.userAgent:null);qa=ra?ra[1]:""}pa=qa;var sa={};var ta;function C(a,b){this.width=a;this.height=b}C.prototype.toString=function(){return"("+this.width+" x "+this.height+")"};function D(a){return a?new E(F(a)):ta||(ta=new E)}function H(a,b){if(a.contains&&b.nodeType==1)return a==b||a.contains(b);if(typeof a.compareDocumentPosition!="undefined")return a==b||Boolean(a.compareDocumentPosition(b)&16);for(;b&&a!=b;)b=b.parentNode;return b==a}function F(a){return a.nodeType==9?a:a.ownerDocument||a.document}function ua(a,b){var c=[];return va(a,b,c,true)?c[0]:undefined}
+function va(a,b,c,d){if(a!=null){var e=0;for(var f;f=a.childNodes[e];e++){if(b(f)){c.push(f);if(d)return true}if(va(f,b,c,d))return true}}return false}function wa(a,b,c,d){if(!c)a=a.parentNode;c=d==null;for(var e=0;a&&(c||e<=d);){if(b(a))return a;a=a.parentNode;e++}return null}function E(a){this.g=a||i.document||document}
+function I(a,b,c,d){a=d||a.g;b=b&&b!="*"?b.toUpperCase():"";if(d=a.querySelectorAll){if(d=a.querySelector){if(!(d=!A)){if(!(d=document.compatMode=="CSS1Compat")){if(!(d=sa["528"])){d=0;var e=q(String(pa)).split("."),f=q(String("528")).split("."),g=Math.max(e.length,f.length);for(var h=0;d==0&&h<g;h++){var G=e[h]||"",Oa=f[h]||"",Pa=RegExp("(\\d*)(\\D*)","g"),Qa=RegExp("(\\d*)(\\D*)","g");do{var y=Pa.exec(G)||["","",""],z=Qa.exec(Oa)||["","",""];if(y[0].length==0&&z[0].length==0)break;d=r(y[1].length==
+0?0:parseInt(y[1],10),z[1].length==0?0:parseInt(z[1],10))||r(y[2].length==0,z[2].length==0)||r(y[2],z[2])}while(d==0)}d=sa["528"]=d>=0}d=d}d=d}d=d}d=d}if(d&&(b||c))c=a.querySelectorAll(b+(c?"."+c:""));else if(c&&a.getElementsByClassName){a=a.getElementsByClassName(c);if(b){d={};f=e=0;for(;g=a[f];f++)if(b==g.nodeName)d[e++]=g;d.length=e;c=d}else c=a}else{a=a.getElementsByTagName(b||"*");if(c){d={};e=0;for(f=0;g=a[f];f++){b=g.className;if(typeof b.split=="function"&&ma(b.split(/\s+/),c)>=0)d[e++]=g}d.length=
+e;c=d}else c=a}return c}E.prototype.contains=H;function xa(){}
+function J(a,b,c){switch(typeof b){case "string":ya(a,b,c);break;case "number":c.push(isFinite(b)&&!isNaN(b)?b:"null");break;case "boolean":c.push(b);break;case "undefined":c.push("null");break;case "object":if(b==null){c.push("null");break}if(j(b)=="array"){var d=b.length;c.push("[");var e="";for(var f=0;f<d;f++){c.push(e);J(a,b[f],c);e=","}c.push("]");break}c.push("{");d="";for(e in b)if(Object.prototype.hasOwnProperty.call(b,e)){f=b[e];if(typeof f!="function"){c.push(d);ya(a,e,c);c.push(":");J(a,
+f,c);d=","}}c.push("}");break;case "function":break;default:throw Error("Unknown type: "+typeof b);}}var K={'"':'\\"',"\\":"\\\\","/":"\\/","\u0008":"\\b","\u000c":"\\f","\n":"\\n","\r":"\\r","\t":"\\t","\u000b":"\\u000b"},za=/\uffff/.test("\uffff")?/[\\\"\x00-\x1f\x7f-\uffff]/g:/[\\\"\x00-\x1f\x7f-\xff]/g;
+function ya(a,b,c){c.push('"',b.replace(za,function(d){if(d in K)return K[d];var e=d.charCodeAt(0),f="\\u";if(e<16)f+="000";else if(e<256)f+="00";else if(e<4096)f+="0";return K[d]=f+e.toString(16)}),'"')};function L(a){switch(j(a)){case "string":case "number":case "boolean":return a;case "function":return a.toString();case "array":return w(a,L);case "object":a=a;if("tagName"in a&&"nodeType"in a&&a.nodeType==1){var b={};b.ELEMENT=Aa(a);return b}if(aa(a))return w(a,L);a=da(a,function(c,d){return typeof d=="number"||k(d)});return ea(a,L);default:return null}}
+function M(a,b){if(j(a)=="array")return w(a,function(c){return M(c,b)});else if(ba(a))return"ELEMENT"in a?Ba(a.ELEMENT,b):ea(a,function(c){return M(c,b)});return a}function Ca(a){a=a||document;var b=a.$wdc_;if(!b){b=a.$wdc_={};b.l=ca()}return b}function Aa(a){var b=Ca(a.ownerDocument),c=fa(b,function(d){return d==a});if(!c){c=":wdc:"+b.l++;b[c]=a}return c}
+function Ba(a,b){a=decodeURIComponent(a);var c=b||document,d=Ca(c);if(!(a in d))throw new o(10,"Element does not exist in cache");var e=d[a];for(var f=e;f;){if(f==c.documentElement)return e;f=f.parentNode}delete d[a];throw new o(10,"Element is no longer attached to the DOM");};var Da=window;var N={};N.d=function(a,b){if(!a)throw Error("No class name specified");a=q(a);if(a.split(/\s+/).length>1)throw Error("Compound class names not permitted");var c=I(D(b),"*",a,b);return c.length?c[0]:null};N.b=function(a,b){if(!a)throw Error("No class name specified");a=q(a);if(a.split(/\s+/).length>1)throw Error("Compound class names not permitted");return I(D(b),"*",a,b)};var O={};O.d=function(a,b){if(!l(b.querySelector)&&0)throw Error("CSS selection is not supported");if(!a)throw Error("No selector specified");if(a.split(/,/).length>1)throw Error("Compound selectors not permitted");a=q(a);var c=b.querySelector(a);return c&&c.nodeType==1?c:null};O.b=function(a,b){if(!l(b.querySelectorAll)&&0)throw Error("CSS selection is not supported");if(!a)throw Error("No selector specified");if(a.split(/,/).length>1)throw Error("Compound selectors not permitted");a=q(a);return b.querySelectorAll(a)};function Ea(a,b){if(typeof a.selectNodes!="undefined"){var c=F(a);typeof c.setProperty!="undefined"&&c.setProperty("SelectionLanguage","XPath");return a.selectNodes(b)}else if(document.implementation.hasFeature("XPath","3.0")){c=F(a);var d=c.createNSResolver(c.documentElement);c=c.evaluate(b,a,d,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,null);d=[];var e=c.snapshotLength;for(var f=0;f<e;f++)d.push(c.snapshotItem(f));return d}else return[]};var P={};P.d=function(a,b){try{var c;if(typeof b.selectSingleNode!="undefined"){var d=F(b);typeof d.setProperty!="undefined"&&d.setProperty("SelectionLanguage","XPath");c=b.selectSingleNode(a)}else if(document.implementation.hasFeature("XPath","3.0")){d=F(b);var e=d.createNSResolver(d.documentElement);c=d.evaluate(a,b,e,XPathResult.FIRST_ORDERED_NODE_TYPE,null).singleNodeValue}else c=null}catch(f){return null}if(!c)return null;if(c.nodeType!=1)throw Error("Returned node is not an element: "+a);return c};
+P.b=function(a,b){var c=Ea(b,a);na(c,function(d){if(d.nodeType!=1)throw Error("Returned nodes must be elements: "+a);});return c};var Fa="StopIteration"in i?i.StopIteration:Error("StopIteration");function Ga(){}Ga.prototype.next=function(){throw Fa;};function Q(a,b,c,d,e){this.a=!!b;a&&R(this,a,d);this.f=e!=undefined?e:this.e||0;if(this.a)this.f*=-1;this.k=!c}m(Q,Ga);Q.prototype.c=null;Q.prototype.e=0;Q.prototype.j=false;function R(a,b,c,d){if(a.c=b)a.e=typeof c=="number"?c:a.c.nodeType!=1?0:a.a?-1:1;if(typeof d=="number")a.f=d}
+Q.prototype.next=function(){var a;if(this.j){if(!this.c||this.k&&this.f==0)throw Fa;a=this.c;var b=this.a?-1:1;if(this.e==b){var c=this.a?a.lastChild:a.firstChild;c?R(this,c):R(this,a,b*-1)}else(c=this.a?a.previousSibling:a.nextSibling)?R(this,c):R(this,a.parentNode,b*-1);this.f+=this.e*(this.a?-1:1)}else this.j=true;a=this.c;if(!this.c)throw Fa;return a};
+Q.prototype.splice=function(){var a=this.c,b=this.a?1:-1;if(this.e==b){this.e=b*-1;this.f+=this.e*(this.a?-1:1)}this.a=!this.a;Q.prototype.next.call(this);this.a=!this.a;b=aa(arguments[0])?arguments[0]:arguments;for(var c=b.length-1;c>=0;c--)a.parentNode&&a.parentNode.insertBefore(b[c],a.nextSibling);a&&a.parentNode&&a.parentNode.removeChild(a)};function Ha(a,b,c,d){Q.call(this,a,b,c,null,d)}m(Ha,Q);Ha.prototype.next=function(){do Ha.m.next.call(this);while(this.e==-1);return this.c};function Ia(a,b){var c=F(a);if(c.defaultView&&c.defaultView.getComputedStyle)if(c=c.defaultView.getComputedStyle(a,null))return c[b]||c.getPropertyValue(b);return""};function S(a,b){return!!a&&a.nodeType==1&&(!b||a.tagName.toUpperCase()==b)}
+var Ja=["async","autofocus","autoplay","checked","compact","complete","controls","declare","defaultchecked","defaultselected","defer","disabled","draggable","ended","formnovalidate","hidden","indeterminate","iscontenteditable","ismap","itemscope","loop","multiple","muted","nohref","noresize","noshade","novalidate","nowrap","open","paused","pubdate","readonly","required","reversed","scoped","seamless","seeking","selected","spellcheck","truespeed","willvalidate"];
+function T(a,b){if(8==a.nodeType)return null;b=b.toLowerCase();if(b=="style"){var c=q(a.style.cssText).toLowerCase();return c.charAt(c.length-1)==";"?c:c+";"}c=a.getAttributeNode(b);if(!c)return null;if(ma(Ja,b)>=0)return"true";return c.specified?c.value:null}function U(a){for(a=a.parentNode;a&&a.nodeType!=1&&a.nodeType!=9&&a.nodeType!=11;)a=a.parentNode;return S(a)?a:null}function V(a,b){b=la(String(b));return Ia(a,b)||Ka(a,b)}
+function Ka(a,b){var c=(a.currentStyle||a.style)[b];if(c!="inherit")return c!==undefined?c:null;return(c=U(a))?Ka(c,b):null}
+function La(a){if(l(a.getBBox))return a.getBBox();var b;if((Ia(a,"display")||(a.currentStyle?a.currentStyle.display:null)||a.style.display)!="none")b=new C(a.offsetWidth,a.offsetHeight);else{b=a.style;var c=b.display,d=b.visibility,e=b.position;b.visibility="hidden";b.position="absolute";b.display="inline";var f;f=a.offsetWidth;a=a.offsetHeight;b.display=c;b.position=e;b.visibility=d;b=new C(f,a)}return b}
+function W(a,b){function c(f){if(V(f,"display")=="none")return false;f=U(f);return!f||c(f)}function d(f){var g=La(f);if(g.height>0&&g.width>0)return true;if(f.innerText||f.textContent)if(Ma.test(f.innerText||f.textContent))return true;return A&&oa(f.childNodes,function(h){return S(h)&&d(h)})}if(!S(a))throw Error("Argument to isShown must be of type Element");if(S(a,"TITLE"))return(F(a)?F(a).parentWindow||F(a).defaultView:window)==Da;if(S(a,"OPTION")||S(a,"OPTGROUP")){var e=wa(a,function(f){return S(f,
+"SELECT")});return!!e&&W(e)}if(S(a,"MAP")){if(!a.name)return false;e=F(a);e=e.evaluate?P.d('/descendant::*[@usemap = "#'+a.name+'"]',e):ua(e,function(f){return S(f)&&T(f,"usemap")=="#"+a.name});return!!e&&W(e)}if(S(a,"AREA")){e=wa(a,function(f){return S(f,"MAP")});return!!e&&W(e)}if(S(a,"INPUT")&&a.type.toLowerCase()=="hidden")return false;if(V(a,"visibility")=="hidden")return false;if(!c(a))return false;if(!b&&Na(a)==0)return false;if(!d(a))return false;return true}
+function Ra(a){var b=[""];Sa(a,b);b=w(b,q);return q(b.join("\n"))}function Sa(a,b){if(S(a,"BR"))b.push("");else{var c=Ta(a);c&&b[b.length-1]&&b.push("");na(a.childNodes,function(d){if(d.nodeType==3){var e=U(d);if(e){W(e);if(e&&W(e)){d=d.nodeValue.replace(Ua," ");e=b.pop();var f=e.length-1;if(f>=0&&e.indexOf(" ",f)==f&&d.lastIndexOf(" ",0)==0)d=d.substr(1);b.push(e+d)}}}else S(d)&&Sa(d,b)});c&&b[b.length-1]&&b.push("")}}function Ta(a){a=V(a,"display");return a=="block"||a=="inline-block"}
+var Va="[\\s\\xa0"+String.fromCharCode(160)+"]+",Ua=RegExp(Va,"g"),Ma=RegExp("^"+Va+"$");function Na(a){var b=1,c=V(a,"opacity");if(c)b=Number(c);if(a=U(a))b*=Na(a);return b};var Wa={};Wa.d=function(a,b){var c=D(b),d=k(a)?c.g.getElementById(a):a;if(!d)return null;if(T(d,"id")==a&&H(b,d))return d;c=I(c,"*");return x(c,function(e){return T(e,"id")==a&&H(b,e)})};Wa.b=function(a,b){var c=I(D(b),"*",null,b);return v(c,function(d){return T(d,"id")==a})};var X={},Xa={};X.i=function(a,b,c){b=I(D(b),"A",null,b);return x(b,function(d){d=Ra(d);return c&&d.indexOf(a)!=-1||d==a})};X.h=function(a,b,c){b=I(D(b),"A",null,b);return v(b,function(d){d=Ra(d);return c&&d.indexOf(a)!=-1||d==a})};X.d=function(a,b){return X.i(a,b,false)};X.b=function(a,b){return X.h(a,b,false)};Xa.d=function(a,b){return X.i(a,b,true)};Xa.b=function(a,b){return X.h(a,b,true)};var Ya={};Ya.d=function(a,b){var c=I(D(b),"*",null,b);return x(c,function(d){return T(d,"name")==a})};Ya.b=function(a,b){var c=I(D(b),"*",null,b);return v(c,function(d){return T(d,"name")==a})};var Za={};Za.d=function(a,b){return I(D(b),a,null,b)[0]||null};Za.b=function(a,b){return I(D(b),a,null,b)};var $a={className:N,css:O,id:Wa,linkText:X,name:Ya,partialLinkText:Xa,tagName:Za,xpath:P};function ab(a,b){var c;a:{for(c in a){c=c;break a}c=void 0}if(c){var d=$a[c];if(d&&l(d.b))return d.b(a[c],b||F(Da))}throw Error("Unsupported locator strategy: "+c);};function bb(a,b,c){var d={};d[a]=b;a=ab;c=[d,c];var e;try{if(k(a))a=new Function(a);var f=M(c),g=a.apply(null,f);e={status:0,value:L(g)}}catch(h){e={status:"code"in h?h.code:13,value:{message:h.message}}}f=[];J(new xa,e,f);return f.join("")}var Y="_".split("."),Z=i;!(Y[0]in Z)&&Z.execScript&&Z.execScript("var "+Y[0]);for(var $;Y.length&&($=Y.shift());)if(!Y.length&&bb!==undefined)Z[$]=bb;else Z=Z[$]?Z[$]:Z[$]={};; return this._.apply(null,arguments);}.apply({navigator:typeof window!='undefined'?window.navigator:null}, arguments);}
diff --git a/core/res/res/raw/get_attribute_value_android.js b/core/res/res/raw/get_attribute_value_android.js
new file mode 100644
index 000000000000..e96a8685861e
--- /dev/null
+++ b/core/res/res/raw/get_attribute_value_android.js
@@ -0,0 +1,11 @@
+function(){return function(){function g(a){var c=typeof a;if(c=="object")if(a){if(a instanceof Array)return"array";else if(a instanceof Object)return c;var b=Object.prototype.toString.call(a);if(b=="[object Window]")return"object";if(b=="[object Array]"||typeof a.length=="number"&&typeof a.splice!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("splice"))return"array";if(b=="[object Function]"||typeof a.call!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("call"))return"function"}else return"null";
+else if(c=="function"&&typeof a.call=="undefined")return"object";return c}function i(a){var c=g(a);return c=="array"||c=="object"&&typeof a.length=="number"}function j(a){return typeof a=="string"}function k(a){a=g(a);return a=="object"||a=="array"||a=="function"}Math.floor(Math.random()*2147483648).toString(36);var l=Date.now||function(){return+new Date};function m(a,c){function b(){}b.prototype=c.prototype;a.h=c.prototype;a.prototype=new b};function n(a){this.stack=Error().stack||"";if(a)this.message=String(a)}m(n,Error);n.prototype.name="CustomError";function o(a,c,b){var d={};for(var e in a)if(c.call(b,a[e],e,a))d[e]=a[e];return d}function p(a,c,b){var d={};for(var e in a)d[e]=c.call(b,a[e],e,a);return d}function q(a,c,b){for(var d in a)if(c.call(b,a[d],d,a))return d};function r(a,c){n.call(this,c);this.code=a;this.name=s[a]||s[13]}m(r,n);var s,t={NoSuchElementError:7,NoSuchFrameError:8,UnknownCommandError:9,StaleElementReferenceError:10,ElementNotVisibleError:11,InvalidElementStateError:12,UnknownError:13,ElementNotSelectableError:15,XPathLookupError:19,NoSuchWindowError:23,InvalidCookieDomainError:24,UnableToSetCookieError:25,ModalDialogOpenedError:26,ModalDialogOpenError:27,ScriptTimeoutError:28},u={};for(var v in t)u[t[v]]=v;s=u;
+r.prototype.toString=function(){return"["+this.name+"] "+this.message};function w(a){for(var c=1;c<arguments.length;c++){var b=String(arguments[c]).replace(/\$/g,"$$$$");a=a.replace(/\%s/,b)}return a};function x(a,c){c.unshift(a);n.call(this,w.apply(null,c));c.shift();this.i=a}m(x,n);x.prototype.name="AssertionError";function y(a,c){if(!a){var b=Array.prototype.slice.call(arguments,2),d="Assertion failed";if(c){d+=": "+c;var e=b}throw new x(""+d,e||[]);}return a};var z=Array.prototype,A=z.indexOf?function(a,c,b){y(a.length!=null);return z.indexOf.call(a,c,b)}:function(a,c,b){b=b==null?0:b<0?Math.max(0,a.length+b):b;if(j(a)){if(!j(c)||c.length!=1)return-1;return a.indexOf(c,b)}for(b=b;b<a.length;b++)if(b in a&&a[b]===c)return b;return-1},C=z.map?function(a,c,b){y(a.length!=null);return z.map.call(a,c,b)}:function(a,c,b){var d=a.length,e=Array(d),f=j(a)?a.split(""):a;for(var h=0;h<d;h++)if(h in f)e[h]=c.call(b,f[h],h,a);return e};var D="",E;if(E=/WebKit\/(\S+)/){var F=E.exec(this.navigator?this.navigator.userAgent:null);D=F?F[1]:""};var G="StopIteration"in this?this.StopIteration:Error("StopIteration");function H(){}H.prototype.next=function(){throw G;};function I(a,c,b,d,e){this.a=!!c;a&&J(this,a,d);this.d=e!=undefined?e:this.c||0;if(this.a)this.d*=-1;this.f=!b}m(I,H);I.prototype.b=null;I.prototype.c=0;I.prototype.e=false;function J(a,c,b,d){if(a.b=c)a.c=typeof b=="number"?b:a.b.nodeType!=1?0:a.a?-1:1;if(typeof d=="number")a.d=d}
+I.prototype.next=function(){var a;if(this.e){if(!this.b||this.f&&this.d==0)throw G;a=this.b;var c=this.a?-1:1;if(this.c==c){var b=this.a?a.lastChild:a.firstChild;b?J(this,b):J(this,a,c*-1)}else(b=this.a?a.previousSibling:a.nextSibling)?J(this,b):J(this,a.parentNode,c*-1);this.d+=this.c*(this.a?-1:1)}else this.e=true;a=this.b;if(!this.b)throw G;return a};
+I.prototype.splice=function(){var a=this.b,c=this.a?1:-1;if(this.c==c){this.c=c*-1;this.d+=this.c*(this.a?-1:1)}this.a=!this.a;I.prototype.next.call(this);this.a=!this.a;c=i(arguments[0])?arguments[0]:arguments;for(var b=c.length-1;b>=0;b--)a.parentNode&&a.parentNode.insertBefore(c[b],a.nextSibling);a&&a.parentNode&&a.parentNode.removeChild(a)};function K(a,c,b,d){I.call(this,a,c,b,null,d)}m(K,I);K.prototype.next=function(){do K.h.next.call(this);while(this.c==-1);return this.b};var L=["async","autofocus","autoplay","checked","compact","complete","controls","declare","defaultchecked","defaultselected","defer","disabled","draggable","ended","formnovalidate","hidden","indeterminate","iscontenteditable","ismap","itemscope","loop","multiple","muted","nohref","noresize","noshade","novalidate","nowrap","open","paused","pubdate","readonly","required","reversed","scoped","seamless","seeking","selected","spellcheck","truespeed","willvalidate"];
+function M(a,c){if(8==a.nodeType)return null;c=c.toLowerCase();if(c=="style"){var b=a.style.cssText.replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").toLowerCase();return b.charAt(b.length-1)==";"?b:b+";"}b=a.getAttributeNode(c);if(!b)return null;if(A(L,c)>=0)return"true";return b.specified?b.value:null}String.fromCharCode(160);function N(){}
+function O(a,c,b){switch(typeof c){case "string":P(a,c,b);break;case "number":b.push(isFinite(c)&&!isNaN(c)?c:"null");break;case "boolean":b.push(c);break;case "undefined":b.push("null");break;case "object":if(c==null){b.push("null");break}if(g(c)=="array"){var d=c.length;b.push("[");var e="";for(var f=0;f<d;f++){b.push(e);O(a,c[f],b);e=","}b.push("]");break}b.push("{");d="";for(e in c)if(Object.prototype.hasOwnProperty.call(c,e)){f=c[e];if(typeof f!="function"){b.push(d);P(a,e,b);b.push(":");O(a,
+f,b);d=","}}b.push("}");break;case "function":break;default:throw Error("Unknown type: "+typeof c);}}var Q={'"':'\\"',"\\":"\\\\","/":"\\/","\u0008":"\\b","\u000c":"\\f","\n":"\\n","\r":"\\r","\t":"\\t","\u000b":"\\u000b"},R=/\uffff/.test("\uffff")?/[\\\"\x00-\x1f\x7f-\uffff]/g:/[\\\"\x00-\x1f\x7f-\xff]/g;
+function P(a,c,b){b.push('"',c.replace(R,function(d){if(d in Q)return Q[d];var e=d.charCodeAt(0),f="\\u";if(e<16)f+="000";else if(e<256)f+="00";else if(e<4096)f+="0";return Q[d]=f+e.toString(16)}),'"')};function S(a){switch(g(a)){case "string":case "number":case "boolean":return a;case "function":return a.toString();case "array":return C(a,S);case "object":a=a;if("tagName"in a&&"nodeType"in a&&a.nodeType==1){var c={};c.ELEMENT=T(a);return c}if(i(a))return C(a,S);a=o(a,function(b,d){return typeof d=="number"||j(d)});return p(a,S);default:return null}}
+function U(a,c){if(g(a)=="array")return C(a,function(b){return U(b,c)});else if(k(a))return"ELEMENT"in a?V(a.ELEMENT,c):p(a,function(b){return U(b,c)});return a}function W(a){a=a||document;var c=a.$wdc_;if(!c){c=a.$wdc_={};c.g=l()}return c}function T(a){var c=W(a.ownerDocument),b=q(c,function(d){return d==a});if(!b){b=":wdc:"+c.g++;c[b]=a}return b}
+function V(a,c){a=decodeURIComponent(a);var b=c||document,d=W(b);if(!(a in d))throw new r(10,"Element does not exist in cache");var e=d[a];for(var f=e;f;){if(f==b.documentElement)return e;f=f.parentNode}delete d[a];throw new r(10,"Element is no longer attached to the DOM");};function X(a,c){var b=M,d=[a,c],e;try{if(j(b))b=new Function(b);var f=U(d),h=b.apply(null,f);e={status:0,value:S(h)}}catch(B){e={status:"code"in B?B.code:13,value:{message:B.message}}}b=[];O(new N,e,b);return b.join("")}var Y="_".split("."),Z=this;!(Y[0]in Z)&&Z.execScript&&Z.execScript("var "+Y[0]);for(var $;Y.length&&($=Y.shift());)if(!Y.length&&X!==undefined)Z[$]=X;else Z=Z[$]?Z[$]:Z[$]={};; return this._.apply(null,arguments);}.apply({navigator:typeof window!='undefined'?window.navigator:null}, arguments);}
diff --git a/core/res/res/raw/get_size_android.js b/core/res/res/raw/get_size_android.js
new file mode 100644
index 000000000000..78f61eefe2d2
--- /dev/null
+++ b/core/res/res/raw/get_size_android.js
@@ -0,0 +1,11 @@
+function(){return function(){function g(a){var b=typeof a;if(b=="object")if(a){if(a instanceof Array)return"array";else if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if(c=="[object Window]")return"object";if(c=="[object Array]"||typeof a.length=="number"&&typeof a.splice!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("splice"))return"array";if(c=="[object Function]"||typeof a.call!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("call"))return"function"}else return"null";
+else if(b=="function"&&typeof a.call=="undefined")return"object";return b}function h(a){var b=g(a);return b=="array"||b=="object"&&typeof a.length=="number"}function i(a){a=g(a);return a=="object"||a=="array"||a=="function"}Math.floor(Math.random()*2147483648).toString(36);var j=Date.now||function(){return+new Date};function l(a,b){function c(){}c.prototype=b.prototype;a.h=b.prototype;a.prototype=new c};function m(a){this.stack=Error().stack||"";if(a)this.message=String(a)}l(m,Error);m.prototype.name="CustomError";function n(a,b,c){var d={};for(var e in a)if(b.call(c,a[e],e,a))d[e]=a[e];return d}function o(a,b,c){var d={};for(var e in a)d[e]=b.call(c,a[e],e,a);return d}function p(a,b,c){for(var d in a)if(b.call(c,a[d],d,a))return d};function q(a,b){m.call(this,b);this.code=a;this.name=r[a]||r[13]}l(q,m);var r,s={NoSuchElementError:7,NoSuchFrameError:8,UnknownCommandError:9,StaleElementReferenceError:10,ElementNotVisibleError:11,InvalidElementStateError:12,UnknownError:13,ElementNotSelectableError:15,XPathLookupError:19,NoSuchWindowError:23,InvalidCookieDomainError:24,UnableToSetCookieError:25,ModalDialogOpenedError:26,ModalDialogOpenError:27,ScriptTimeoutError:28},t={};for(var u in s)t[s[u]]=u;r=t;
+q.prototype.toString=function(){return"["+this.name+"] "+this.message};function v(a){for(var b=1;b<arguments.length;b++){var c=String(arguments[b]).replace(/\$/g,"$$$$");a=a.replace(/\%s/,c)}return a};function w(a,b){b.unshift(a);m.call(this,v.apply(null,b));b.shift();this.i=a}l(w,m);w.prototype.name="AssertionError";function x(a,b){if(!a){var c=Array.prototype.slice.call(arguments,2),d="Assertion failed";if(b){d+=": "+b;var e=c}throw new w(""+d,e||[]);}return a};var y=Array.prototype,z=y.map?function(a,b,c){x(a.length!=null);return y.map.call(a,b,c)}:function(a,b,c){var d=a.length,e=Array(d),f=typeof a=="string"?a.split(""):a;for(var k=0;k<d;k++)if(k in f)e[k]=b.call(c,f[k],k,a);return e};var A="",B;if(B=/WebKit\/(\S+)/){var C=B.exec(this.navigator?this.navigator.userAgent:null);A=C?C[1]:""};function D(a,b){this.width=a;this.height=b}D.prototype.toString=function(){return"("+this.width+" x "+this.height+")"};D.prototype.floor=function(){this.width=Math.floor(this.width);this.height=Math.floor(this.height);return this};var E="StopIteration"in this?this.StopIteration:Error("StopIteration");function F(){}F.prototype.next=function(){throw E;};function G(a,b,c,d,e){this.a=!!b;a&&H(this,a,d);this.d=e!=undefined?e:this.c||0;if(this.a)this.d*=-1;this.f=!c}l(G,F);G.prototype.b=null;G.prototype.c=0;G.prototype.e=false;function H(a,b,c,d){if(a.b=b)a.c=typeof c=="number"?c:a.b.nodeType!=1?0:a.a?-1:1;if(typeof d=="number")a.d=d}
+G.prototype.next=function(){var a;if(this.e){if(!this.b||this.f&&this.d==0)throw E;a=this.b;var b=this.a?-1:1;if(this.c==b){var c=this.a?a.lastChild:a.firstChild;c?H(this,c):H(this,a,b*-1)}else(c=this.a?a.previousSibling:a.nextSibling)?H(this,c):H(this,a.parentNode,b*-1);this.d+=this.c*(this.a?-1:1)}else this.e=true;a=this.b;if(!this.b)throw E;return a};
+G.prototype.splice=function(){var a=this.b,b=this.a?1:-1;if(this.c==b){this.c=b*-1;this.d+=this.c*(this.a?-1:1)}this.a=!this.a;G.prototype.next.call(this);this.a=!this.a;b=h(arguments[0])?arguments[0]:arguments;for(var c=b.length-1;c>=0;c--)a.parentNode&&a.parentNode.insertBefore(b[c],a.nextSibling);a&&a.parentNode&&a.parentNode.removeChild(a)};function I(a,b,c,d){G.call(this,a,b,c,null,d)}l(I,G);I.prototype.next=function(){do I.h.next.call(this);while(this.c==-1);return this.b};function J(a){if(g(a.getBBox)=="function")return a.getBBox();var b;b:{b=a.nodeType==9?a:a.ownerDocument||a.document;if(b.defaultView&&b.defaultView.getComputedStyle)if(b=b.defaultView.getComputedStyle(a,null)){b=b.display||b.getPropertyValue("display");break b}b=""}if((b||(a.currentStyle?a.currentStyle.display:null)||a.style.display)!="none")a=new D(a.offsetWidth,a.offsetHeight);else{b=a.style;var c=b.display,d=b.visibility,e=b.position;b.visibility="hidden";b.position="absolute";b.display="inline";
+var f;f=a.offsetWidth;a=a.offsetHeight;b.display=c;b.position=e;b.visibility=d;a=new D(f,a)}return a}String.fromCharCode(160);function K(){}
+function L(a,b,c){switch(typeof b){case "string":M(a,b,c);break;case "number":c.push(isFinite(b)&&!isNaN(b)?b:"null");break;case "boolean":c.push(b);break;case "undefined":c.push("null");break;case "object":if(b==null){c.push("null");break}if(g(b)=="array"){var d=b.length;c.push("[");var e="";for(var f=0;f<d;f++){c.push(e);L(a,b[f],c);e=","}c.push("]");break}c.push("{");d="";for(e in b)if(Object.prototype.hasOwnProperty.call(b,e)){f=b[e];if(typeof f!="function"){c.push(d);M(a,e,c);c.push(":");L(a,
+f,c);d=","}}c.push("}");break;case "function":break;default:throw Error("Unknown type: "+typeof b);}}var N={'"':'\\"',"\\":"\\\\","/":"\\/","\u0008":"\\b","\u000c":"\\f","\n":"\\n","\r":"\\r","\t":"\\t","\u000b":"\\u000b"},O=/\uffff/.test("\uffff")?/[\\\"\x00-\x1f\x7f-\uffff]/g:/[\\\"\x00-\x1f\x7f-\xff]/g;
+function M(a,b,c){c.push('"',b.replace(O,function(d){if(d in N)return N[d];var e=d.charCodeAt(0),f="\\u";if(e<16)f+="000";else if(e<256)f+="00";else if(e<4096)f+="0";return N[d]=f+e.toString(16)}),'"')};function P(a){switch(g(a)){case "string":case "number":case "boolean":return a;case "function":return a.toString();case "array":return z(a,P);case "object":a=a;if("tagName"in a&&"nodeType"in a&&a.nodeType==1){var b={};b.ELEMENT=Q(a);return b}if(h(a))return z(a,P);a=n(a,function(c,d){return typeof d=="number"||typeof d=="string"});return o(a,P);default:return null}}
+function R(a,b){if(g(a)=="array")return z(a,function(c){return R(c,b)});else if(i(a))return"ELEMENT"in a?S(a.ELEMENT,b):o(a,function(c){return R(c,b)});return a}function T(a){a=a||document;var b=a.$wdc_;if(!b){b=a.$wdc_={};b.g=j()}return b}function Q(a){var b=T(a.ownerDocument),c=p(b,function(d){return d==a});if(!c){c=":wdc:"+b.g++;b[c]=a}return c}
+function S(a,b){a=decodeURIComponent(a);var c=b||document,d=T(c);if(!(a in d))throw new q(10,"Element does not exist in cache");var e=d[a];for(var f=e;f;){if(f==c.documentElement)return e;f=f.parentNode}delete d[a];throw new q(10,"Element is no longer attached to the DOM");};function U(a){var b=J;a=[a];var c;try{if(typeof b=="string")b=new Function(b);var d=R(a),e=b.apply(null,d);c={status:0,value:P(e)}}catch(f){c={status:"code"in f?f.code:13,value:{message:f.message}}}b=[];L(new K,c,b);return b.join("")}var V="_".split("."),W=this;!(V[0]in W)&&W.execScript&&W.execScript("var "+V[0]);for(var X;V.length&&(X=V.shift());)if(!V.length&&U!==undefined)W[X]=U;else W=W[X]?W[X]:W[X]={};; return this._.apply(null,arguments);}.apply({navigator:typeof window!='undefined'?window.navigator:null}, arguments);}
diff --git a/core/res/res/raw/get_text_android.js b/core/res/res/raw/get_text_android.js
new file mode 100644
index 000000000000..75c3fed5f038
--- /dev/null
+++ b/core/res/res/raw/get_text_android.js
@@ -0,0 +1,19 @@
+function(){return function(){function g(a){var b=typeof a;if(b=="object")if(a){if(a instanceof Array)return"array";else if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if(c=="[object Window]")return"object";if(c=="[object Array]"||typeof a.length=="number"&&typeof a.splice!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("splice"))return"array";if(c=="[object Function]"||typeof a.call!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("call"))return"function"}else return"null";
+else if(b=="function"&&typeof a.call=="undefined")return"object";return b}function i(a){var b=g(a);return b=="array"||b=="object"&&typeof a.length=="number"}function j(a){return typeof a=="string"}function aa(a){a=g(a);return a=="object"||a=="array"||a=="function"}Math.floor(Math.random()*2147483648).toString(36);var ba=Date.now||function(){return+new Date};function k(a,b){function c(){}c.prototype=b.prototype;a.h=b.prototype;a.prototype=new c};function l(a){this.stack=Error().stack||"";if(a)this.message=String(a)}k(l,Error);l.prototype.name="CustomError";function ca(a,b,c){var d={};for(var e in a)if(b.call(c,a[e],e,a))d[e]=a[e];return d}function m(a,b,c){var d={};for(var e in a)d[e]=b.call(c,a[e],e,a);return d}function da(a,b,c){for(var d in a)if(b.call(c,a[d],d,a))return d};function n(a,b){l.call(this,b);this.code=a;this.name=o[a]||o[13]}k(n,l);var o,p={NoSuchElementError:7,NoSuchFrameError:8,UnknownCommandError:9,StaleElementReferenceError:10,ElementNotVisibleError:11,InvalidElementStateError:12,UnknownError:13,ElementNotSelectableError:15,XPathLookupError:19,NoSuchWindowError:23,InvalidCookieDomainError:24,UnableToSetCookieError:25,ModalDialogOpenedError:26,ModalDialogOpenError:27,ScriptTimeoutError:28},q={};for(var r in p)q[p[r]]=r;o=q;
+n.prototype.toString=function(){return"["+this.name+"] "+this.message};var ea=window;function fa(a){for(var b=1;b<arguments.length;b++){var c=String(arguments[b]).replace(/\$/g,"$$$$");a=a.replace(/\%s/,c)}return a}function s(a){return a.replace(/^[\s\xa0]+|[\s\xa0]+$/g,"")}var t={};function ga(a){return t[a]||(t[a]=String(a).replace(/\-([a-z])/g,function(b,c){return c.toUpperCase()}))};function u(a,b){b.unshift(a);l.call(this,fa.apply(null,b));b.shift();this.i=a}k(u,l);u.prototype.name="AssertionError";function v(a,b){if(!a){var c=Array.prototype.slice.call(arguments,2),d="Assertion failed";if(b){d+=": "+b;var e=c}throw new u(""+d,e||[]);}return a};var w=Array.prototype,ha=w.indexOf?function(a,b,c){v(a.length!=null);return w.indexOf.call(a,b,c)}:function(a,b,c){c=c==null?0:c<0?Math.max(0,a.length+c):c;if(j(a)){if(!j(b)||b.length!=1)return-1;return a.indexOf(b,c)}for(c=c;c<a.length;c++)if(c in a&&a[c]===b)return c;return-1},ia=w.forEach?function(a,b,c){v(a.length!=null);w.forEach.call(a,b,c)}:function(a,b,c){var d=a.length,e=j(a)?a.split(""):a;for(var f=0;f<d;f++)f in e&&b.call(c,e[f],f,a)},x=w.map?function(a,b,c){v(a.length!=null);return w.map.call(a,
+b,c)}:function(a,b,c){var d=a.length,e=Array(d),f=j(a)?a.split(""):a;for(var h=0;h<d;h++)if(h in f)e[h]=b.call(c,f[h],h,a);return e},ja=w.some?function(a,b,c){v(a.length!=null);return w.some.call(a,b,c)}:function(a,b,c){var d=a.length,e=j(a)?a.split(""):a;for(var f=0;f<d;f++)if(f in e&&b.call(c,e[f],f,a))return true;return false};var y=true,ka="",z;if(y)z=/WebKit\/(\S+)/;if(z){var A=z.exec(this.navigator?this.navigator.userAgent:null);ka=A?A[1]:""};function B(a,b){this.width=a;this.height=b}B.prototype.toString=function(){return"("+this.width+" x "+this.height+")"};B.prototype.floor=function(){this.width=Math.floor(this.width);this.height=Math.floor(this.height);return this};function C(a){return a.nodeType==9?a:a.ownerDocument||a.document}function la(a,b){var c=[];return D(a,b,c,true)?c[0]:undefined}function D(a,b,c,d){if(a!=null){var e=0;for(var f;f=a.childNodes[e];e++){if(b(f)){c.push(f);if(d)return true}if(D(f,b,c,d))return true}}return false}function E(a,b,c,d){if(!c)a=a.parentNode;c=d==null;for(var e=0;a&&(c||e<=d);){if(b(a))return a;a=a.parentNode;e++}return null};function ma(a,b){try{var c;if(typeof b.selectSingleNode!="undefined"){var d=C(b);typeof d.setProperty!="undefined"&&d.setProperty("SelectionLanguage","XPath");c=b.selectSingleNode(a)}else if(document.implementation.hasFeature("XPath","3.0")){d=C(b);var e=d.createNSResolver(d.documentElement);c=d.evaluate(a,b,e,XPathResult.FIRST_ORDERED_NODE_TYPE,null).singleNodeValue}else c=null}catch(f){return null}if(!c)return null;if(c.nodeType!=1)throw Error("Returned node is not an element: "+a);return c};var F="StopIteration"in this?this.StopIteration:Error("StopIteration");function G(){}G.prototype.next=function(){throw F;};function H(a,b,c,d,e){this.a=!!b;a&&I(this,a,d);this.d=e!=undefined?e:this.c||0;if(this.a)this.d*=-1;this.f=!c}k(H,G);H.prototype.b=null;H.prototype.c=0;H.prototype.e=false;function I(a,b,c,d){if(a.b=b)a.c=typeof c=="number"?c:a.b.nodeType!=1?0:a.a?-1:1;if(typeof d=="number")a.d=d}
+H.prototype.next=function(){var a;if(this.e){if(!this.b||this.f&&this.d==0)throw F;a=this.b;var b=this.a?-1:1;if(this.c==b){var c=this.a?a.lastChild:a.firstChild;c?I(this,c):I(this,a,b*-1)}else(c=this.a?a.previousSibling:a.nextSibling)?I(this,c):I(this,a.parentNode,b*-1);this.d+=this.c*(this.a?-1:1)}else this.e=true;a=this.b;if(!this.b)throw F;return a};
+H.prototype.splice=function(){var a=this.b,b=this.a?1:-1;if(this.c==b){this.c=b*-1;this.d+=this.c*(this.a?-1:1)}this.a=!this.a;H.prototype.next.call(this);this.a=!this.a;b=i(arguments[0])?arguments[0]:arguments;for(var c=b.length-1;c>=0;c--)a.parentNode&&a.parentNode.insertBefore(b[c],a.nextSibling);a&&a.parentNode&&a.parentNode.removeChild(a)};function J(a,b,c,d){H.call(this,a,b,c,null,d)}k(J,H);J.prototype.next=function(){do J.h.next.call(this);while(this.c==-1);return this.b};function K(a,b){var c=C(a);if(c.defaultView&&c.defaultView.getComputedStyle)if(c=c.defaultView.getComputedStyle(a,null))return c[b]||c.getPropertyValue(b);return""};function L(a,b){return!!a&&a.nodeType==1&&(!b||a.tagName.toUpperCase()==b)}
+var na=["async","autofocus","autoplay","checked","compact","complete","controls","declare","defaultchecked","defaultselected","defer","disabled","draggable","ended","formnovalidate","hidden","indeterminate","iscontenteditable","ismap","itemscope","loop","multiple","muted","nohref","noresize","noshade","novalidate","nowrap","open","paused","pubdate","readonly","required","reversed","scoped","seamless","seeking","selected","spellcheck","truespeed","willvalidate"];
+function oa(a,b){if(8==a.nodeType)return null;b=b.toLowerCase();if(b=="style"){var c=s(a.style.cssText).toLowerCase();return c.charAt(c.length-1)==";"?c:c+";"}c=a.getAttributeNode(b);if(!c)return null;if(ha(na,b)>=0)return"true";return c.specified?c.value:null}function M(a){for(a=a.parentNode;a&&a.nodeType!=1&&a.nodeType!=9&&a.nodeType!=11;)a=a.parentNode;return L(a)?a:null}function N(a,b){b=ga(String(b));return K(a,b)||O(a,b)}
+function O(a,b){var c=(a.currentStyle||a.style)[b];if(c!="inherit")return c!==undefined?c:null;return(c=M(a))?O(c,b):null}
+function pa(a){if(g(a.getBBox)=="function")return a.getBBox();var b;if((K(a,"display")||(a.currentStyle?a.currentStyle.display:null)||a.style.display)!="none")b=new B(a.offsetWidth,a.offsetHeight);else{b=a.style;var c=b.display,d=b.visibility,e=b.position;b.visibility="hidden";b.position="absolute";b.display="inline";var f;f=a.offsetWidth;a=a.offsetHeight;b.display=c;b.position=e;b.visibility=d;b=new B(f,a)}return b}
+function P(a,b){function c(f){if(N(f,"display")=="none")return false;f=M(f);return!f||c(f)}function d(f){var h=pa(f);if(h.height>0&&h.width>0)return true;if(f.innerText||f.textContent)if(qa.test(f.innerText||f.textContent))return true;return y&&ja(f.childNodes,function(X){return L(X)&&d(X)})}if(!L(a))throw Error("Argument to isShown must be of type Element");if(L(a,"TITLE"))return(C(a)?C(a).parentWindow||C(a).defaultView:window)==ea;if(L(a,"OPTION")||L(a,"OPTGROUP")){var e=E(a,function(f){return L(f,
+"SELECT")});return!!e&&P(e)}if(L(a,"MAP")){if(!a.name)return false;e=C(a);e=e.evaluate?ma('/descendant::*[@usemap = "#'+a.name+'"]',e):la(e,function(f){return L(f)&&oa(f,"usemap")=="#"+a.name});return!!e&&P(e)}if(L(a,"AREA")){e=E(a,function(f){return L(f,"MAP")});return!!e&&P(e)}if(L(a,"INPUT")&&a.type.toLowerCase()=="hidden")return false;if(N(a,"visibility")=="hidden")return false;if(!c(a))return false;if(!b&&Q(a)==0)return false;if(!d(a))return false;return true}
+function ra(a){var b=[""];R(a,b);b=x(b,s);return s(b.join("\n"))}function R(a,b){if(L(a,"BR"))b.push("");else{var c=sa(a);c&&b[b.length-1]&&b.push("");ia(a.childNodes,function(d){if(d.nodeType==3){var e=M(d);if(e){P(e);if(e&&P(e)){d=d.nodeValue.replace(ta," ");e=b.pop();var f=e.length-1;if(f>=0&&e.indexOf(" ",f)==f&&d.lastIndexOf(" ",0)==0)d=d.substr(1);b.push(e+d)}}}else L(d)&&R(d,b)});c&&b[b.length-1]&&b.push("")}}function sa(a){a=N(a,"display");return a=="block"||a=="inline-block"}
+var S="[\\s\\xa0"+String.fromCharCode(160)+"]+",ta=RegExp(S,"g"),qa=RegExp("^"+S+"$");function Q(a){var b=1,c=N(a,"opacity");if(c)b=Number(c);if(a=M(a))b*=Q(a);return b};function ua(){}
+function T(a,b,c){switch(typeof b){case "string":va(a,b,c);break;case "number":c.push(isFinite(b)&&!isNaN(b)?b:"null");break;case "boolean":c.push(b);break;case "undefined":c.push("null");break;case "object":if(b==null){c.push("null");break}if(g(b)=="array"){var d=b.length;c.push("[");var e="";for(var f=0;f<d;f++){c.push(e);T(a,b[f],c);e=","}c.push("]");break}c.push("{");d="";for(e in b)if(Object.prototype.hasOwnProperty.call(b,e)){f=b[e];if(typeof f!="function"){c.push(d);va(a,e,c);c.push(":");T(a,
+f,c);d=","}}c.push("}");break;case "function":break;default:throw Error("Unknown type: "+typeof b);}}var U={'"':'\\"',"\\":"\\\\","/":"\\/","\u0008":"\\b","\u000c":"\\f","\n":"\\n","\r":"\\r","\t":"\\t","\u000b":"\\u000b"},wa=/\uffff/.test("\uffff")?/[\\\"\x00-\x1f\x7f-\uffff]/g:/[\\\"\x00-\x1f\x7f-\xff]/g;
+function va(a,b,c){c.push('"',b.replace(wa,function(d){if(d in U)return U[d];var e=d.charCodeAt(0),f="\\u";if(e<16)f+="000";else if(e<256)f+="00";else if(e<4096)f+="0";return U[d]=f+e.toString(16)}),'"')};function V(a){switch(g(a)){case "string":case "number":case "boolean":return a;case "function":return a.toString();case "array":return x(a,V);case "object":a=a;if("tagName"in a&&"nodeType"in a&&a.nodeType==1){var b={};b.ELEMENT=xa(a);return b}if(i(a))return x(a,V);a=ca(a,function(c,d){return typeof d=="number"||j(d)});return m(a,V);default:return null}}
+function W(a,b){if(g(a)=="array")return x(a,function(c){return W(c,b)});else if(aa(a))return"ELEMENT"in a?ya(a.ELEMENT,b):m(a,function(c){return W(c,b)});return a}function za(a){a=a||document;var b=a.$wdc_;if(!b){b=a.$wdc_={};b.g=ba()}return b}function xa(a){var b=za(a.ownerDocument),c=da(b,function(d){return d==a});if(!c){c=":wdc:"+b.g++;b[c]=a}return c}
+function ya(a,b){a=decodeURIComponent(a);var c=b||document,d=za(c);if(!(a in d))throw new n(10,"Element does not exist in cache");var e=d[a];for(var f=e;f;){if(f==c.documentElement)return e;f=f.parentNode}delete d[a];throw new n(10,"Element is no longer attached to the DOM");};function Aa(a){var b=ra;a=[a];var c;try{if(j(b))b=new Function(b);var d=W(a),e=b.apply(null,d);c={status:0,value:V(e)}}catch(f){c={status:"code"in f?f.code:13,value:{message:f.message}}}b=[];T(new ua,c,b);return b.join("")}var Y="_".split("."),Z=this;!(Y[0]in Z)&&Z.execScript&&Z.execScript("var "+Y[0]);for(var $;Y.length&&($=Y.shift());)if(!Y.length&&Aa!==undefined)Z[$]=Aa;else Z=Z[$]?Z[$]:Z[$]={};; return this._.apply(null,arguments);}.apply({navigator:typeof window!='undefined'?window.navigator:null}, arguments);}
diff --git a/core/res/res/raw/get_top_left_coordinates_android.js b/core/res/res/raw/get_top_left_coordinates_android.js
new file mode 100644
index 000000000000..23f96afe2b62
--- /dev/null
+++ b/core/res/res/raw/get_top_left_coordinates_android.js
@@ -0,0 +1,18 @@
+function(){return function(){var h=this;
+function j(a){var b=typeof a;if(b=="object")if(a){if(a instanceof Array)return"array";else if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if(c=="[object Window]")return"object";if(c=="[object Array]"||typeof a.length=="number"&&typeof a.splice!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("splice"))return"array";if(c=="[object Function]"||typeof a.call!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("call"))return"function"}else return"null";else if(b==
+"function"&&typeof a.call=="undefined")return"object";return b}function l(a){var b=j(a);return b=="array"||b=="object"&&typeof a.length=="number"}function aa(a){a=j(a);return a=="object"||a=="array"||a=="function"}Math.floor(Math.random()*2147483648).toString(36);var ba=Date.now||function(){return+new Date};function m(a,b){function c(){}c.prototype=b.prototype;a.j=b.prototype;a.prototype=new c};function n(a){this.stack=Error().stack||"";if(a)this.message=String(a)}m(n,Error);n.prototype.name="CustomError";function ca(a,b,c){var d={};for(var f in a)if(b.call(c,a[f],f,a))d[f]=a[f];return d}function o(a,b,c){var d={};for(var f in a)d[f]=b.call(c,a[f],f,a);return d}function da(a,b,c){for(var d in a)if(b.call(c,a[d],d,a))return d};function p(a,b){n.call(this,b);this.code=a;this.name=q[a]||q[13]}m(p,n);var q,r={NoSuchElementError:7,NoSuchFrameError:8,UnknownCommandError:9,StaleElementReferenceError:10,ElementNotVisibleError:11,InvalidElementStateError:12,UnknownError:13,ElementNotSelectableError:15,XPathLookupError:19,NoSuchWindowError:23,InvalidCookieDomainError:24,UnableToSetCookieError:25,ModalDialogOpenedError:26,ModalDialogOpenError:27,ScriptTimeoutError:28},s={};for(var t in r)s[r[t]]=t;q=s;
+p.prototype.toString=function(){return"["+this.name+"] "+this.message};function ea(a){for(var b=1;b<arguments.length;b++){var c=String(arguments[b]).replace(/\$/g,"$$$$");a=a.replace(/\%s/,c)}return a}function y(a,b){if(a<b)return-1;else if(a>b)return 1;return 0};function z(a,b){b.unshift(a);n.call(this,ea.apply(null,b));b.shift();this.k=a}m(z,n);z.prototype.name="AssertionError";function fa(a,b){if(!a){var c=Array.prototype.slice.call(arguments,2),d="Assertion failed";if(b){d+=": "+b;var f=c}throw new z(""+d,f||[]);}return a};var A=Array.prototype,B=A.map?function(a,b,c){fa(a.length!=null);return A.map.call(a,b,c)}:function(a,b,c){var d=a.length,f=Array(d),e=typeof a=="string"?a.split(""):a;for(var g=0;g<d;g++)if(g in e)f[g]=b.call(c,e[g],g,a);return f};var C,F="",G;if(G=/WebKit\/(\S+)/){var H=G.exec(h.navigator?h.navigator.userAgent:null);F=H?H[1]:""}C=F;var ga={};var ha;function I(a,b){this.x=a!==undefined?a:0;this.y=b!==undefined?b:0}I.prototype.toString=function(){return"("+this.x+", "+this.y+")"};function J(a,b){this.width=a;this.height=b}J.prototype.toString=function(){return"("+this.width+" x "+this.height+")"};J.prototype.floor=function(){this.width=Math.floor(this.width);this.height=Math.floor(this.height);return this};function K(a){return a?new ia(L(a)):ha||(ha=new ia)}function L(a){return a.nodeType==9?a:a.ownerDocument||a.document}function ia(a){this.e=a||h.document||document}function ja(a){a=a.e.body;return new I(a.scrollLeft,a.scrollTop)};var M="StopIteration"in h?h.StopIteration:Error("StopIteration");function ka(){}ka.prototype.next=function(){throw M;};function N(a,b,c,d,f){this.a=!!b;a&&O(this,a,d);this.d=f!=undefined?f:this.c||0;if(this.a)this.d*=-1;this.h=!c}m(N,ka);N.prototype.b=null;N.prototype.c=0;N.prototype.g=false;function O(a,b,c,d){if(a.b=b)a.c=typeof c=="number"?c:a.b.nodeType!=1?0:a.a?-1:1;if(typeof d=="number")a.d=d}
+N.prototype.next=function(){var a;if(this.g){if(!this.b||this.h&&this.d==0)throw M;a=this.b;var b=this.a?-1:1;if(this.c==b){var c=this.a?a.lastChild:a.firstChild;c?O(this,c):O(this,a,b*-1)}else(c=this.a?a.previousSibling:a.nextSibling)?O(this,c):O(this,a.parentNode,b*-1);this.d+=this.c*(this.a?-1:1)}else this.g=true;a=this.b;if(!this.b)throw M;return a};
+N.prototype.splice=function(){var a=this.b,b=this.a?1:-1;if(this.c==b){this.c=b*-1;this.d+=this.c*(this.a?-1:1)}this.a=!this.a;N.prototype.next.call(this);this.a=!this.a;b=l(arguments[0])?arguments[0]:arguments;for(var c=b.length-1;c>=0;c--)a.parentNode&&a.parentNode.insertBefore(b[c],a.nextSibling);a&&a.parentNode&&a.parentNode.removeChild(a)};function P(a,b,c,d){N.call(this,a,b,c,null,d)}m(P,N);P.prototype.next=function(){do P.j.next.call(this);while(this.c==-1);return this.b};function la(a,b,c,d){this.top=a;this.right=b;this.bottom=c;this.left=d}la.prototype.toString=function(){return"("+this.top+"t, "+this.right+"r, "+this.bottom+"b, "+this.left+"l)"};function Q(a,b,c,d){this.left=a;this.top=b;this.width=c;this.height=d}Q.prototype.toString=function(){return"("+this.left+", "+this.top+" - "+this.width+"w x "+this.height+"h)"};function R(a,b){var c=L(a);if(c.defaultView&&c.defaultView.getComputedStyle)if(c=c.defaultView.getComputedStyle(a,null))return c[b]||c.getPropertyValue(b);return""}function S(a,b){return R(a,b)||(a.currentStyle?a.currentStyle[b]:null)||a.style[b]}
+function ma(a){var b=L(a),c=S(a,"position"),d=c=="fixed"||c=="absolute";for(a=a.parentNode;a&&a!=b;a=a.parentNode){c=S(a,"position");d=d&&c=="static"&&a!=b.documentElement&&a!=b.body;if(!d&&(a.scrollWidth>a.clientWidth||a.scrollHeight>a.clientHeight||c=="fixed"||c=="absolute"))return a}return null}
+function T(a){var b=L(a),c=S(a,"position"),d=new I(0,0),f=(b?b.nodeType==9?b:L(b):document).documentElement;if(a==f)return d;if(a.getBoundingClientRect){a=a.getBoundingClientRect();b=ja(K(b));d.x=a.left+b.x;d.y=a.top+b.y}else if(b.getBoxObjectFor){a=b.getBoxObjectFor(a);b=b.getBoxObjectFor(f);d.x=a.screenX-b.screenX;d.y=a.screenY-b.screenY}else{var e=a;do{d.x+=e.offsetLeft;d.y+=e.offsetTop;if(e!=a){d.x+=e.clientLeft||0;d.y+=e.clientTop||0}if(S(e,"position")=="fixed"){d.x+=b.body.scrollLeft;d.y+=b.body.scrollTop;
+break}e=e.offsetParent}while(e&&e!=a);if(c=="absolute")d.y-=b.body.offsetTop;for(e=a;(e=ma(e))&&e!=b.body&&e!=f;){d.x-=e.scrollLeft;d.y-=e.scrollTop}}return d};String.fromCharCode(160);function na(a,b){b.scrollLeft+=Math.min(a.left,Math.max(a.left-a.width,0));b.scrollTop+=Math.min(a.top,Math.max(a.top-a.height,0))}
+function oa(a,b){var c;c=b?new Q(b.left,b.top,b.width,b.height):new Q(0,0,a.offsetWidth,a.offsetHeight);var d=L(a);for(var f=a.parentNode;f&&f!=d.body&&f!=d.documentElement;){var e=c,g=f,u=T(a),v=T(g),i=void 0;i=void 0;var k=void 0,D=void 0,E=void 0;E=R(g,"borderLeftWidth");D=R(g,"borderRightWidth");k=R(g,"borderTopWidth");i=R(g,"borderBottomWidth");i=new la(parseFloat(k),parseFloat(D),parseFloat(i),parseFloat(E));na(new Q(u.x+e.left-v.x-i.left,u.y+e.top-v.y-i.top,g.clientWidth-e.width,g.clientHeight-
+e.height),g);f=f.parentNode}f=T(a);e=K(d);e=(e.e.parentWindow||e.e.defaultView||window).document;if(!ga["500"]){g=0;u=String(C).replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").split(".");v=String("500").replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").split(".");i=Math.max(u.length,v.length);for(k=0;g==0&&k<i;k++){D=u[k]||"";E=v[k]||"";var sa=RegExp("(\\d*)(\\D*)","g"),ta=RegExp("(\\d*)(\\D*)","g");do{var w=sa.exec(D)||["","",""],x=ta.exec(E)||["","",""];if(w[0].length==0&&x[0].length==0)break;g=y(w[1].length==0?0:parseInt(w[1],
+10),x[1].length==0?0:parseInt(x[1],10))||y(w[2].length==0,x[2].length==0)||y(w[2],x[2])}while(g==0)}ga["500"]=g>=0}e=e.compatMode=="CSS1Compat"?e.documentElement:e.body;e=new J(e.clientWidth,e.clientHeight);na(new Q(f.x+c.left-d.body.scrollLeft,f.y+c.top-d.body.scrollTop,e.width-c.width,e.height-c.height),d.body);d=new I;if(a.nodeType==1)if(a.getBoundingClientRect){f=a.getBoundingClientRect();d.x=f.left;d.y=f.top}else{f=ja(K(a));e=T(a);d.x=e.x-f.x;d.y=e.y-f.y}else{f=j(a.f)=="function";e=a;if(a.targetTouches)e=
+a.targetTouches[0];else if(f&&a.f().targetTouches)e=a.f().targetTouches[0];d.x=e.clientX;d.y=e.clientY}return new I(d.x+c.left,d.y+c.top)};function pa(){}
+function U(a,b,c){switch(typeof b){case "string":qa(a,b,c);break;case "number":c.push(isFinite(b)&&!isNaN(b)?b:"null");break;case "boolean":c.push(b);break;case "undefined":c.push("null");break;case "object":if(b==null){c.push("null");break}if(j(b)=="array"){var d=b.length;c.push("[");var f="";for(var e=0;e<d;e++){c.push(f);U(a,b[e],c);f=","}c.push("]");break}c.push("{");d="";for(f in b)if(Object.prototype.hasOwnProperty.call(b,f)){e=b[f];if(typeof e!="function"){c.push(d);qa(a,f,c);c.push(":");U(a,
+e,c);d=","}}c.push("}");break;case "function":break;default:throw Error("Unknown type: "+typeof b);}}var V={'"':'\\"',"\\":"\\\\","/":"\\/","\u0008":"\\b","\u000c":"\\f","\n":"\\n","\r":"\\r","\t":"\\t","\u000b":"\\u000b"},ra=/\uffff/.test("\uffff")?/[\\\"\x00-\x1f\x7f-\uffff]/g:/[\\\"\x00-\x1f\x7f-\xff]/g;
+function qa(a,b,c){c.push('"',b.replace(ra,function(d){if(d in V)return V[d];var f=d.charCodeAt(0),e="\\u";if(f<16)e+="000";else if(f<256)e+="00";else if(f<4096)e+="0";return V[d]=e+f.toString(16)}),'"')};function W(a){switch(j(a)){case "string":case "number":case "boolean":return a;case "function":return a.toString();case "array":return B(a,W);case "object":a=a;if("tagName"in a&&"nodeType"in a&&a.nodeType==1){var b={};b.ELEMENT=ua(a);return b}if(l(a))return B(a,W);a=ca(a,function(c,d){return typeof d=="number"||typeof d=="string"});return o(a,W);default:return null}}
+function X(a,b){if(j(a)=="array")return B(a,function(c){return X(c,b)});else if(aa(a))return"ELEMENT"in a?va(a.ELEMENT,b):o(a,function(c){return X(c,b)});return a}function wa(a){a=a||document;var b=a.$wdc_;if(!b){b=a.$wdc_={};b.i=ba()}return b}function ua(a){var b=wa(a.ownerDocument),c=da(b,function(d){return d==a});if(!c){c=":wdc:"+b.i++;b[c]=a}return c}
+function va(a,b){a=decodeURIComponent(a);var c=b||document,d=wa(c);if(!(a in d))throw new p(10,"Element does not exist in cache");var f=d[a];for(var e=f;e;){if(e==c.documentElement)return f;e=e.parentNode}delete d[a];throw new p(10,"Element is no longer attached to the DOM");};function xa(a){var b=oa;a=[a];var c;try{if(typeof b=="string")b=new Function(b);var d=X(a),f=b.apply(null,d);c={status:0,value:W(f)}}catch(e){c={status:"code"in e?e.code:13,value:{message:e.message}}}b=[];U(new pa,c,b);return b.join("")}var Y="_".split("."),Z=h;!(Y[0]in Z)&&Z.execScript&&Z.execScript("var "+Y[0]);for(var $;Y.length&&($=Y.shift());)if(!Y.length&&xa!==undefined)Z[$]=xa;else Z=Z[$]?Z[$]:Z[$]={};; return this._.apply(null,arguments);}.apply({navigator:typeof window!='undefined'?window.navigator:null}, arguments);}
diff --git a/core/res/res/raw/get_value_of_css_property_android.js b/core/res/res/raw/get_value_of_css_property_android.js
new file mode 100644
index 000000000000..c156dec42fa2
--- /dev/null
+++ b/core/res/res/raw/get_value_of_css_property_android.js
@@ -0,0 +1,10 @@
+function(){return function(){function g(a){var c=typeof a;if(c=="object")if(a){if(a instanceof Array)return"array";else if(a instanceof Object)return c;var b=Object.prototype.toString.call(a);if(b=="[object Window]")return"object";if(b=="[object Array]"||typeof a.length=="number"&&typeof a.splice!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("splice"))return"array";if(b=="[object Function]"||typeof a.call!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("call"))return"function"}else return"null";
+else if(c=="function"&&typeof a.call=="undefined")return"object";return c}function i(a){var c=g(a);return c=="array"||c=="object"&&typeof a.length=="number"}function j(a){a=g(a);return a=="object"||a=="array"||a=="function"}Math.floor(Math.random()*2147483648).toString(36);var k=Date.now||function(){return+new Date};function l(a,c){function b(){}b.prototype=c.prototype;a.h=c.prototype;a.prototype=new b};function m(a){this.stack=Error().stack||"";if(a)this.message=String(a)}l(m,Error);m.prototype.name="CustomError";function n(a,c,b){var d={};for(var e in a)if(c.call(b,a[e],e,a))d[e]=a[e];return d}function o(a,c,b){var d={};for(var e in a)d[e]=c.call(b,a[e],e,a);return d}function p(a,c,b){for(var d in a)if(c.call(b,a[d],d,a))return d};function q(a,c){m.call(this,c);this.code=a;this.name=r[a]||r[13]}l(q,m);var r,s={NoSuchElementError:7,NoSuchFrameError:8,UnknownCommandError:9,StaleElementReferenceError:10,ElementNotVisibleError:11,InvalidElementStateError:12,UnknownError:13,ElementNotSelectableError:15,XPathLookupError:19,NoSuchWindowError:23,InvalidCookieDomainError:24,UnableToSetCookieError:25,ModalDialogOpenedError:26,ModalDialogOpenError:27,ScriptTimeoutError:28},t={};for(var u in s)t[s[u]]=u;r=t;
+q.prototype.toString=function(){return"["+this.name+"] "+this.message};function v(a){for(var c=1;c<arguments.length;c++){var b=String(arguments[c]).replace(/\$/g,"$$$$");a=a.replace(/\%s/,b)}return a};function w(a,c){c.unshift(a);m.call(this,v.apply(null,c));c.shift();this.i=a}l(w,m);w.prototype.name="AssertionError";function x(a,c){if(!a){var b=Array.prototype.slice.call(arguments,2),d="Assertion failed";if(c){d+=": "+c;var e=b}throw new w(""+d,e||[]);}return a};var y=Array.prototype,A=y.map?function(a,c,b){x(a.length!=null);return y.map.call(a,c,b)}:function(a,c,b){var d=a.length,e=Array(d),f=typeof a=="string"?a.split(""):a;for(var h=0;h<d;h++)if(h in f)e[h]=c.call(b,f[h],h,a);return e};var B="",C;if(C=/WebKit\/(\S+)/){var D=C.exec(this.navigator?this.navigator.userAgent:null);B=D?D[1]:""};var E="StopIteration"in this?this.StopIteration:Error("StopIteration");function F(){}F.prototype.next=function(){throw E;};function G(a,c,b,d,e){this.a=!!c;a&&H(this,a,d);this.d=e!=undefined?e:this.c||0;if(this.a)this.d*=-1;this.f=!b}l(G,F);G.prototype.b=null;G.prototype.c=0;G.prototype.e=false;function H(a,c,b,d){if(a.b=c)a.c=typeof b=="number"?b:a.b.nodeType!=1?0:a.a?-1:1;if(typeof d=="number")a.d=d}
+G.prototype.next=function(){var a;if(this.e){if(!this.b||this.f&&this.d==0)throw E;a=this.b;var c=this.a?-1:1;if(this.c==c){var b=this.a?a.lastChild:a.firstChild;b?H(this,b):H(this,a,c*-1)}else(b=this.a?a.previousSibling:a.nextSibling)?H(this,b):H(this,a.parentNode,c*-1);this.d+=this.c*(this.a?-1:1)}else this.e=true;a=this.b;if(!this.b)throw E;return a};
+G.prototype.splice=function(){var a=this.b,c=this.a?1:-1;if(this.c==c){this.c=c*-1;this.d+=this.c*(this.a?-1:1)}this.a=!this.a;G.prototype.next.call(this);this.a=!this.a;c=i(arguments[0])?arguments[0]:arguments;for(var b=c.length-1;b>=0;b--)a.parentNode&&a.parentNode.insertBefore(c[b],a.nextSibling);a&&a.parentNode&&a.parentNode.removeChild(a)};function I(a,c,b,d){G.call(this,a,c,b,null,d)}l(I,G);I.prototype.next=function(){do I.h.next.call(this);while(this.c==-1);return this.b};function J(a,c){var b=(a.currentStyle||a.style)[c];if(b!="inherit")return b!==undefined?b:null;for(b=a.parentNode;b&&b.nodeType!=1&&b.nodeType!=9&&b.nodeType!=11;)b=b.parentNode;return(b=b&&b.nodeType==1&&1?b:null)?J(b,c):null}String.fromCharCode(160);function K(){}
+function L(a,c,b){switch(typeof c){case "string":M(a,c,b);break;case "number":b.push(isFinite(c)&&!isNaN(c)?c:"null");break;case "boolean":b.push(c);break;case "undefined":b.push("null");break;case "object":if(c==null){b.push("null");break}if(g(c)=="array"){var d=c.length;b.push("[");var e="";for(var f=0;f<d;f++){b.push(e);L(a,c[f],b);e=","}b.push("]");break}b.push("{");d="";for(e in c)if(Object.prototype.hasOwnProperty.call(c,e)){f=c[e];if(typeof f!="function"){b.push(d);M(a,e,b);b.push(":");L(a,
+f,b);d=","}}b.push("}");break;case "function":break;default:throw Error("Unknown type: "+typeof c);}}var N={'"':'\\"',"\\":"\\\\","/":"\\/","\u0008":"\\b","\u000c":"\\f","\n":"\\n","\r":"\\r","\t":"\\t","\u000b":"\\u000b"},O=/\uffff/.test("\uffff")?/[\\\"\x00-\x1f\x7f-\uffff]/g:/[\\\"\x00-\x1f\x7f-\xff]/g;
+function M(a,c,b){b.push('"',c.replace(O,function(d){if(d in N)return N[d];var e=d.charCodeAt(0),f="\\u";if(e<16)f+="000";else if(e<256)f+="00";else if(e<4096)f+="0";return N[d]=f+e.toString(16)}),'"')};function P(a){switch(g(a)){case "string":case "number":case "boolean":return a;case "function":return a.toString();case "array":return A(a,P);case "object":a=a;if("tagName"in a&&"nodeType"in a&&a.nodeType==1){var c={};c.ELEMENT=Q(a);return c}if(i(a))return A(a,P);a=n(a,function(b,d){return typeof d=="number"||typeof d=="string"});return o(a,P);default:return null}}
+function R(a,c){if(g(a)=="array")return A(a,function(b){return R(b,c)});else if(j(a))return"ELEMENT"in a?S(a.ELEMENT,c):o(a,function(b){return R(b,c)});return a}function T(a){a=a||document;var c=a.$wdc_;if(!c){c=a.$wdc_={};c.g=k()}return c}function Q(a){var c=T(a.ownerDocument),b=p(c,function(d){return d==a});if(!b){b=":wdc:"+c.g++;c[b]=a}return b}
+function S(a,c){a=decodeURIComponent(a);var b=c||document,d=T(b);if(!(a in d))throw new q(10,"Element does not exist in cache");var e=d[a];for(var f=e;f;){if(f==b.documentElement)return e;f=f.parentNode}delete d[a];throw new q(10,"Element is no longer attached to the DOM");};function U(a,c){var b=J,d=[a,c],e;try{if(typeof b=="string")b=new Function(b);var f=R(d),h=b.apply(null,f);e={status:0,value:P(h)}}catch(z){e={status:"code"in z?z.code:13,value:{message:z.message}}}b=[];L(new K,e,b);return b.join("")}var V="_".split("."),W=this;!(V[0]in W)&&W.execScript&&W.execScript("var "+V[0]);for(var X;V.length&&(X=V.shift());)if(!V.length&&U!==undefined)W[X]=U;else W=W[X]?W[X]:W[X]={};; return this._.apply(null,arguments);}.apply({navigator:typeof window!='undefined'?window.navigator:null}, arguments);}
diff --git a/core/res/res/raw/is_enabled_android.js b/core/res/res/raw/is_enabled_android.js
new file mode 100644
index 000000000000..3f799f33ef9c
--- /dev/null
+++ b/core/res/res/raw/is_enabled_android.js
@@ -0,0 +1,12 @@
+function(){return function(){function g(a){var b=typeof a;if(b=="object")if(a){if(a instanceof Array)return"array";else if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if(c=="[object Window]")return"object";if(c=="[object Array]"||typeof a.length=="number"&&typeof a.splice!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("splice"))return"array";if(c=="[object Function]"||typeof a.call!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("call"))return"function"}else return"null";
+else if(b=="function"&&typeof a.call=="undefined")return"object";return b}function h(a){var b=g(a);return b=="array"||b=="object"&&typeof a.length=="number"}function i(a){return typeof a=="string"}function k(a){a=g(a);return a=="object"||a=="array"||a=="function"}Math.floor(Math.random()*2147483648).toString(36);var l=Date.now||function(){return+new Date};function m(a,b){function c(){}c.prototype=b.prototype;a.h=b.prototype;a.prototype=new c};function n(a){this.stack=Error().stack||"";if(a)this.message=String(a)}m(n,Error);n.prototype.name="CustomError";function o(a,b,c){var d={};for(var e in a)if(b.call(c,a[e],e,a))d[e]=a[e];return d}function p(a,b,c){var d={};for(var e in a)d[e]=b.call(c,a[e],e,a);return d}function q(a,b,c){for(var d in a)if(b.call(c,a[d],d,a))return d};function r(a,b){n.call(this,b);this.code=a;this.name=s[a]||s[13]}m(r,n);var s,t={NoSuchElementError:7,NoSuchFrameError:8,UnknownCommandError:9,StaleElementReferenceError:10,ElementNotVisibleError:11,InvalidElementStateError:12,UnknownError:13,ElementNotSelectableError:15,XPathLookupError:19,NoSuchWindowError:23,InvalidCookieDomainError:24,UnableToSetCookieError:25,ModalDialogOpenedError:26,ModalDialogOpenError:27,ScriptTimeoutError:28},u={};for(var v in t)u[t[v]]=v;s=u;
+r.prototype.toString=function(){return"["+this.name+"] "+this.message};function w(a){for(var b=1;b<arguments.length;b++){var c=String(arguments[b]).replace(/\$/g,"$$$$");a=a.replace(/\%s/,c)}return a};function x(a,b){b.unshift(a);n.call(this,w.apply(null,b));b.shift();this.i=a}m(x,n);x.prototype.name="AssertionError";function y(a,b){if(!a){var c=Array.prototype.slice.call(arguments,2),d="Assertion failed";if(b){d+=": "+b;var e=c}throw new x(""+d,e||[]);}return a};var z=Array.prototype,A=z.indexOf?function(a,b,c){y(a.length!=null);return z.indexOf.call(a,b,c)}:function(a,b,c){c=c==null?0:c<0?Math.max(0,a.length+c):c;if(i(a)){if(!i(b)||b.length!=1)return-1;return a.indexOf(b,c)}for(c=c;c<a.length;c++)if(c in a&&a[c]===b)return c;return-1},B=z.map?function(a,b,c){y(a.length!=null);return z.map.call(a,b,c)}:function(a,b,c){var d=a.length,e=Array(d),f=i(a)?a.split(""):a;for(var j=0;j<d;j++)if(j in f)e[j]=b.call(c,f[j],j,a);return e};var C="",D;if(D=/WebKit\/(\S+)/){var E=D.exec(this.navigator?this.navigator.userAgent:null);C=E?E[1]:""};var F="StopIteration"in this?this.StopIteration:Error("StopIteration");function G(){}G.prototype.next=function(){throw F;};function H(a,b,c,d,e){this.a=!!b;a&&I(this,a,d);this.d=e!=undefined?e:this.c||0;if(this.a)this.d*=-1;this.f=!c}m(H,G);H.prototype.b=null;H.prototype.c=0;H.prototype.e=false;function I(a,b,c,d){if(a.b=b)a.c=typeof c=="number"?c:a.b.nodeType!=1?0:a.a?-1:1;if(typeof d=="number")a.d=d}
+H.prototype.next=function(){var a;if(this.e){if(!this.b||this.f&&this.d==0)throw F;a=this.b;var b=this.a?-1:1;if(this.c==b){var c=this.a?a.lastChild:a.firstChild;c?I(this,c):I(this,a,b*-1)}else(c=this.a?a.previousSibling:a.nextSibling)?I(this,c):I(this,a.parentNode,b*-1);this.d+=this.c*(this.a?-1:1)}else this.e=true;a=this.b;if(!this.b)throw F;return a};
+H.prototype.splice=function(){var a=this.b,b=this.a?1:-1;if(this.c==b){this.c=b*-1;this.d+=this.c*(this.a?-1:1)}this.a=!this.a;H.prototype.next.call(this);this.a=!this.a;b=h(arguments[0])?arguments[0]:arguments;for(var c=b.length-1;c>=0;c--)a.parentNode&&a.parentNode.insertBefore(b[c],a.nextSibling);a&&a.parentNode&&a.parentNode.removeChild(a)};function J(a,b,c,d){H.call(this,a,b,c,null,d)}m(J,H);J.prototype.next=function(){do J.h.next.call(this);while(this.c==-1);return this.b};var K=["async","autofocus","autoplay","checked","compact","complete","controls","declare","defaultchecked","defaultselected","defer","disabled","draggable","ended","formnovalidate","hidden","indeterminate","iscontenteditable","ismap","itemscope","loop","multiple","muted","nohref","noresize","noshade","novalidate","nowrap","open","paused","pubdate","readonly","required","reversed","scoped","seamless","seeking","selected","spellcheck","truespeed","willvalidate"];
+function L(a,b){if(8==a.nodeType)return null;b=b.toLowerCase();if(b=="style"){var c=a.style.cssText.replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").toLowerCase();return c.charAt(c.length-1)==";"?c:c+";"}c=a.getAttributeNode(b);if(!c)return null;if(A(K,b)>=0)return"true";return c.specified?c.value:null}var M=["BUTTON","INPUT","OPTGROUP","OPTION","SELECT","TEXTAREA"];
+function N(a){var b=a.tagName.toUpperCase();if(!(A(M,b)>=0))return true;if(L(a,"disabled"))return false;if(a.parentNode&&a.parentNode.nodeType==1&&"OPTGROUP"==b||"OPTION"==b)return N(a.parentNode);return true}String.fromCharCode(160);function O(){}
+function P(a,b,c){switch(typeof b){case "string":Q(a,b,c);break;case "number":c.push(isFinite(b)&&!isNaN(b)?b:"null");break;case "boolean":c.push(b);break;case "undefined":c.push("null");break;case "object":if(b==null){c.push("null");break}if(g(b)=="array"){var d=b.length;c.push("[");var e="";for(var f=0;f<d;f++){c.push(e);P(a,b[f],c);e=","}c.push("]");break}c.push("{");d="";for(e in b)if(Object.prototype.hasOwnProperty.call(b,e)){f=b[e];if(typeof f!="function"){c.push(d);Q(a,e,c);c.push(":");P(a,
+f,c);d=","}}c.push("}");break;case "function":break;default:throw Error("Unknown type: "+typeof b);}}var R={'"':'\\"',"\\":"\\\\","/":"\\/","\u0008":"\\b","\u000c":"\\f","\n":"\\n","\r":"\\r","\t":"\\t","\u000b":"\\u000b"},S=/\uffff/.test("\uffff")?/[\\\"\x00-\x1f\x7f-\uffff]/g:/[\\\"\x00-\x1f\x7f-\xff]/g;
+function Q(a,b,c){c.push('"',b.replace(S,function(d){if(d in R)return R[d];var e=d.charCodeAt(0),f="\\u";if(e<16)f+="000";else if(e<256)f+="00";else if(e<4096)f+="0";return R[d]=f+e.toString(16)}),'"')};function T(a){switch(g(a)){case "string":case "number":case "boolean":return a;case "function":return a.toString();case "array":return B(a,T);case "object":a=a;if("tagName"in a&&"nodeType"in a&&a.nodeType==1){var b={};b.ELEMENT=U(a);return b}if(h(a))return B(a,T);a=o(a,function(c,d){return typeof d=="number"||i(d)});return p(a,T);default:return null}}
+function V(a,b){if(g(a)=="array")return B(a,function(c){return V(c,b)});else if(k(a))return"ELEMENT"in a?aa(a.ELEMENT,b):p(a,function(c){return V(c,b)});return a}function W(a){a=a||document;var b=a.$wdc_;if(!b){b=a.$wdc_={};b.g=l()}return b}function U(a){var b=W(a.ownerDocument),c=q(b,function(d){return d==a});if(!c){c=":wdc:"+b.g++;b[c]=a}return c}
+function aa(a,b){a=decodeURIComponent(a);var c=b||document,d=W(c);if(!(a in d))throw new r(10,"Element does not exist in cache");var e=d[a];for(var f=e;f;){if(f==c.documentElement)return e;f=f.parentNode}delete d[a];throw new r(10,"Element is no longer attached to the DOM");};function X(a){var b=N;a=[a];var c;try{if(i(b))b=new Function(b);var d=V(a),e=b.apply(null,d);c={status:0,value:T(e)}}catch(f){c={status:"code"in f?f.code:13,value:{message:f.message}}}b=[];P(new O,c,b);return b.join("")}var Y="_".split("."),Z=this;!(Y[0]in Z)&&Z.execScript&&Z.execScript("var "+Y[0]);for(var $;Y.length&&($=Y.shift());)if(!Y.length&&X!==undefined)Z[$]=X;else Z=Z[$]?Z[$]:Z[$]={};; return this._.apply(null,arguments);}.apply({navigator:typeof window!='undefined'?window.navigator:null}, arguments);}
diff --git a/core/res/res/raw/is_selected_android.js b/core/res/res/raw/is_selected_android.js
new file mode 100644
index 000000000000..0cc53b21357a
--- /dev/null
+++ b/core/res/res/raw/is_selected_android.js
@@ -0,0 +1,10 @@
+function(){return function(){function g(a){var b=typeof a;if(b=="object")if(a){if(a instanceof Array)return"array";else if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if(c=="[object Window]")return"object";if(c=="[object Array]"||typeof a.length=="number"&&typeof a.splice!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("splice"))return"array";if(c=="[object Function]"||typeof a.call!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("call"))return"function"}else return"null";
+else if(b=="function"&&typeof a.call=="undefined")return"object";return b}function h(a){var b=g(a);return b=="array"||b=="object"&&typeof a.length=="number"}function i(a){return typeof a=="string"}function k(a){a=g(a);return a=="object"||a=="array"||a=="function"}Math.floor(Math.random()*2147483648).toString(36);var l=Date.now||function(){return+new Date};function m(a,b){function c(){}c.prototype=b.prototype;a.h=b.prototype;a.prototype=new c};function n(a){this.stack=Error().stack||"";if(a)this.message=String(a)}m(n,Error);n.prototype.name="CustomError";function o(a,b,c){var d={};for(var e in a)if(b.call(c,a[e],e,a))d[e]=a[e];return d}function p(a,b,c){var d={};for(var e in a)d[e]=b.call(c,a[e],e,a);return d}function q(a,b,c){for(var d in a)if(b.call(c,a[d],d,a))return d};function r(a,b){n.call(this,b);this.code=a;this.name=s[a]||s[13]}m(r,n);var s,t={NoSuchElementError:7,NoSuchFrameError:8,UnknownCommandError:9,StaleElementReferenceError:10,ElementNotVisibleError:11,InvalidElementStateError:12,UnknownError:13,ElementNotSelectableError:15,XPathLookupError:19,NoSuchWindowError:23,InvalidCookieDomainError:24,UnableToSetCookieError:25,ModalDialogOpenedError:26,ModalDialogOpenError:27,ScriptTimeoutError:28},u={};for(var v in t)u[t[v]]=v;s=u;
+r.prototype.toString=function(){return"["+this.name+"] "+this.message};function w(a){for(var b=1;b<arguments.length;b++){var c=String(arguments[b]).replace(/\$/g,"$$$$");a=a.replace(/\%s/,c)}return a};function x(a,b){b.unshift(a);n.call(this,w.apply(null,b));b.shift();this.i=a}m(x,n);x.prototype.name="AssertionError";function y(a,b){if(!a){var c=Array.prototype.slice.call(arguments,2),d="Assertion failed";if(b){d+=": "+b;var e=c}throw new x(""+d,e||[]);}return a};var z=Array.prototype,A=z.indexOf?function(a,b,c){y(a.length!=null);return z.indexOf.call(a,b,c)}:function(a,b,c){c=c==null?0:c<0?Math.max(0,a.length+c):c;if(i(a)){if(!i(b)||b.length!=1)return-1;return a.indexOf(b,c)}for(c=c;c<a.length;c++)if(c in a&&a[c]===b)return c;return-1},B=z.map?function(a,b,c){y(a.length!=null);return z.map.call(a,b,c)}:function(a,b,c){var d=a.length,e=Array(d),f=i(a)?a.split(""):a;for(var j=0;j<d;j++)if(j in f)e[j]=b.call(c,f[j],j,a);return e};var C="",D;if(D=/WebKit\/(\S+)/){var E=D.exec(this.navigator?this.navigator.userAgent:null);C=E?E[1]:""};var F="StopIteration"in this?this.StopIteration:Error("StopIteration");function G(){}G.prototype.next=function(){throw F;};function H(a,b,c,d,e){this.a=!!b;a&&I(this,a,d);this.d=e!=undefined?e:this.c||0;if(this.a)this.d*=-1;this.f=!c}m(H,G);H.prototype.b=null;H.prototype.c=0;H.prototype.e=false;function I(a,b,c,d){if(a.b=b)a.c=typeof c=="number"?c:a.b.nodeType!=1?0:a.a?-1:1;if(typeof d=="number")a.d=d}
+H.prototype.next=function(){var a;if(this.e){if(!this.b||this.f&&this.d==0)throw F;a=this.b;var b=this.a?-1:1;if(this.c==b){var c=this.a?a.lastChild:a.firstChild;c?I(this,c):I(this,a,b*-1)}else(c=this.a?a.previousSibling:a.nextSibling)?I(this,c):I(this,a.parentNode,b*-1);this.d+=this.c*(this.a?-1:1)}else this.e=true;a=this.b;if(!this.b)throw F;return a};
+H.prototype.splice=function(){var a=this.b,b=this.a?1:-1;if(this.c==b){this.c=b*-1;this.d+=this.c*(this.a?-1:1)}this.a=!this.a;H.prototype.next.call(this);this.a=!this.a;b=h(arguments[0])?arguments[0]:arguments;for(var c=b.length-1;c>=0;c--)a.parentNode&&a.parentNode.insertBefore(b[c],a.nextSibling);a&&a.parentNode&&a.parentNode.removeChild(a)};function J(a,b,c,d){H.call(this,a,b,c,null,d)}m(J,H);J.prototype.next=function(){do J.h.next.call(this);while(this.c==-1);return this.b};var K={"class":"className",readonly:"readOnly"},L=["checked","disabled","draggable","hidden"];String.fromCharCode(160);function M(a){var b;if(a&&a.nodeType==1&&a.tagName.toUpperCase()=="OPTION")b=true;else if(a&&a.nodeType==1&&a.tagName.toUpperCase()=="INPUT"){b=a.type.toLowerCase();b=b=="checkbox"||b=="radio"}else b=false;if(!b)throw new r(15,"Element is not selectable");b="selected";var c=a.type&&a.type.toLowerCase();if("checkbox"==c||"radio"==c)b="checked";b=K[b]||b;a=a[b];a=a===undefined&&A(L,b)>=0?false:a;return!!a};function N(){}
+function O(a,b,c){switch(typeof b){case "string":P(a,b,c);break;case "number":c.push(isFinite(b)&&!isNaN(b)?b:"null");break;case "boolean":c.push(b);break;case "undefined":c.push("null");break;case "object":if(b==null){c.push("null");break}if(g(b)=="array"){var d=b.length;c.push("[");var e="";for(var f=0;f<d;f++){c.push(e);O(a,b[f],c);e=","}c.push("]");break}c.push("{");d="";for(e in b)if(Object.prototype.hasOwnProperty.call(b,e)){f=b[e];if(typeof f!="function"){c.push(d);P(a,e,c);c.push(":");O(a,
+f,c);d=","}}c.push("}");break;case "function":break;default:throw Error("Unknown type: "+typeof b);}}var Q={'"':'\\"',"\\":"\\\\","/":"\\/","\u0008":"\\b","\u000c":"\\f","\n":"\\n","\r":"\\r","\t":"\\t","\u000b":"\\u000b"},R=/\uffff/.test("\uffff")?/[\\\"\x00-\x1f\x7f-\uffff]/g:/[\\\"\x00-\x1f\x7f-\xff]/g;
+function P(a,b,c){c.push('"',b.replace(R,function(d){if(d in Q)return Q[d];var e=d.charCodeAt(0),f="\\u";if(e<16)f+="000";else if(e<256)f+="00";else if(e<4096)f+="0";return Q[d]=f+e.toString(16)}),'"')};function S(a){switch(g(a)){case "string":case "number":case "boolean":return a;case "function":return a.toString();case "array":return B(a,S);case "object":a=a;if("tagName"in a&&"nodeType"in a&&a.nodeType==1){var b={};b.ELEMENT=T(a);return b}if(h(a))return B(a,S);a=o(a,function(c,d){return typeof d=="number"||i(d)});return p(a,S);default:return null}}
+function U(a,b){if(g(a)=="array")return B(a,function(c){return U(c,b)});else if(k(a))return"ELEMENT"in a?V(a.ELEMENT,b):p(a,function(c){return U(c,b)});return a}function W(a){a=a||document;var b=a.$wdc_;if(!b){b=a.$wdc_={};b.g=l()}return b}function T(a){var b=W(a.ownerDocument),c=q(b,function(d){return d==a});if(!c){c=":wdc:"+b.g++;b[c]=a}return c}
+function V(a,b){a=decodeURIComponent(a);var c=b||document,d=W(c);if(!(a in d))throw new r(10,"Element does not exist in cache");var e=d[a];for(var f=e;f;){if(f==c.documentElement)return e;f=f.parentNode}delete d[a];throw new r(10,"Element is no longer attached to the DOM");};function X(a){var b=M;a=[a];var c;try{if(i(b))b=new Function(b);var d=U(a),e=b.apply(null,d);c={status:0,value:S(e)}}catch(f){c={status:"code"in f?f.code:13,value:{message:f.message}}}b=[];O(new N,c,b);return b.join("")}var Y="_".split("."),Z=this;!(Y[0]in Z)&&Z.execScript&&Z.execScript("var "+Y[0]);for(var $;Y.length&&($=Y.shift());)if(!Y.length&&X!==undefined)Z[$]=X;else Z=Z[$]?Z[$]:Z[$]={};; return this._.apply(null,arguments);}.apply({navigator:typeof window!='undefined'?window.navigator:null}, arguments);}
diff --git a/core/res/res/raw/set_selected_android.js b/core/res/res/raw/set_selected_android.js
new file mode 100644
index 000000000000..51774e0f07f8
--- /dev/null
+++ b/core/res/res/raw/set_selected_android.js
@@ -0,0 +1,26 @@
+function(){return function(){var l=this;
+function m(a){var b=typeof a;if(b=="object")if(a){if(a instanceof Array)return"array";else if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if(c=="[object Window]")return"object";if(c=="[object Array]"||typeof a.length=="number"&&typeof a.splice!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("splice"))return"array";if(c=="[object Function]"||typeof a.call!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("call"))return"function"}else return"null";else if(b==
+"function"&&typeof a.call=="undefined")return"object";return b}function o(a){var b=m(a);return b=="array"||b=="object"&&typeof a.length=="number"}function p(a){return typeof a=="string"}function q(a){a=m(a);return a=="object"||a=="array"||a=="function"}Math.floor(Math.random()*2147483648).toString(36);var aa=Date.now||function(){return+new Date};function r(a,b){function c(){}c.prototype=b.prototype;a.j=b.prototype;a.prototype=new c};function s(a){this.stack=Error().stack||"";if(a)this.message=String(a)}r(s,Error);s.prototype.name="CustomError";function ba(a,b,c){var d={};for(var f in a)if(b.call(c,a[f],f,a))d[f]=a[f];return d}function u(a,b,c){var d={};for(var f in a)d[f]=b.call(c,a[f],f,a);return d}function ca(a,b,c){for(var d in a)if(b.call(c,a[d],d,a))return d};function v(a,b){s.call(this,b);this.code=a;this.name=w[a]||w[13]}r(v,s);var w,da={NoSuchElementError:7,NoSuchFrameError:8,UnknownCommandError:9,StaleElementReferenceError:10,ElementNotVisibleError:11,InvalidElementStateError:12,UnknownError:13,ElementNotSelectableError:15,XPathLookupError:19,NoSuchWindowError:23,InvalidCookieDomainError:24,UnableToSetCookieError:25,ModalDialogOpenedError:26,ModalDialogOpenError:27,ScriptTimeoutError:28},ea={};for(var fa in da)ea[da[fa]]=fa;w=ea;
+v.prototype.toString=function(){return"["+this.name+"] "+this.message};var ga=window;function ha(a){for(var b=1;b<arguments.length;b++){var c=String(arguments[b]).replace(/\$/g,"$$$$");a=a.replace(/\%s/,c)}return a}var ia={};function ja(a){return ia[a]||(ia[a]=String(a).replace(/\-([a-z])/g,function(b,c){return c.toUpperCase()}))};function x(a,b){b.unshift(a);s.call(this,ha.apply(null,b));b.shift();this.m=a}r(x,s);x.prototype.name="AssertionError";function y(a,b){if(!a){var c=Array.prototype.slice.call(arguments,2),d="Assertion failed";if(b){d+=": "+b;var f=c}throw new x(""+d,f||[]);}return a};var z=Array.prototype,A=z.indexOf?function(a,b,c){y(a.length!=null);return z.indexOf.call(a,b,c)}:function(a,b,c){c=c==null?0:c<0?Math.max(0,a.length+c):c;if(p(a)){if(!p(b)||b.length!=1)return-1;return a.indexOf(b,c)}for(c=c;c<a.length;c++)if(c in a&&a[c]===b)return c;return-1},B=z.map?function(a,b,c){y(a.length!=null);return z.map.call(a,b,c)}:function(a,b,c){var d=a.length,f=Array(d),e=p(a)?a.split(""):a;for(var g=0;g<d;g++)if(g in e)f[g]=b.call(c,e[g],g,a);return f},ka=z.some?function(a,b,c){y(a.length!=
+null);return z.some.call(a,b,c)}:function(a,b,c){var d=a.length,f=p(a)?a.split(""):a;for(var e=0;e<d;e++)if(e in f&&b.call(c,f[e],e,a))return true;return false};var C=true,la="",D;if(C)D=/WebKit\/(\S+)/;if(D){var ma=D.exec(l.navigator?l.navigator.userAgent:null);la=ma?ma[1]:""};var E;function F(a,b){this.x=a!==undefined?a:0;this.y=b!==undefined?b:0}F.prototype.toString=function(){return"("+this.x+", "+this.y+")"};function G(a,b){this.width=a;this.height=b}G.prototype.toString=function(){return"("+this.width+" x "+this.height+")"};G.prototype.floor=function(){this.width=Math.floor(this.width);this.height=Math.floor(this.height);return this};function H(a){return a.nodeType==9?a:a.ownerDocument||a.document}function na(a,b){var c=[];return oa(a,b,c,true)?c[0]:undefined}function oa(a,b,c,d){if(a!=null){var f=0;for(var e;e=a.childNodes[f];f++){if(b(e)){c.push(e);if(d)return true}if(oa(e,b,c,d))return true}}return false}function I(a,b,c,d){if(!c)a=a.parentNode;c=d==null;for(var f=0;a&&(c||f<=d);){if(b(a))return a;a=a.parentNode;f++}return null}function J(a){this.e=a||l.document||document}
+function pa(a){a=!C&&a.e.compatMode=="CSS1Compat"?a.e.documentElement:a.e.body;return new F(a.scrollLeft,a.scrollTop)};function qa(a,b){try{var c;if(typeof b.selectSingleNode!="undefined"){var d=H(b);typeof d.setProperty!="undefined"&&d.setProperty("SelectionLanguage","XPath");c=b.selectSingleNode(a)}else if(document.implementation.hasFeature("XPath","3.0")){d=H(b);var f=d.createNSResolver(d.documentElement);c=d.evaluate(a,b,f,XPathResult.FIRST_ORDERED_NODE_TYPE,null).singleNodeValue}else c=null}catch(e){return null}if(!c)return null;if(c.nodeType!=1)throw Error("Returned node is not an element: "+a);return c};var K="StopIteration"in l?l.StopIteration:Error("StopIteration");function ra(){}ra.prototype.next=function(){throw K;};function L(a,b,c,d,f){this.a=!!b;a&&M(this,a,d);this.d=f!=undefined?f:this.c||0;if(this.a)this.d*=-1;this.h=!c}r(L,ra);L.prototype.b=null;L.prototype.c=0;L.prototype.g=false;function M(a,b,c,d){if(a.b=b)a.c=typeof c=="number"?c:a.b.nodeType!=1?0:a.a?-1:1;if(typeof d=="number")a.d=d}
+L.prototype.next=function(){var a;if(this.g){if(!this.b||this.h&&this.d==0)throw K;a=this.b;var b=this.a?-1:1;if(this.c==b){var c=this.a?a.lastChild:a.firstChild;c?M(this,c):M(this,a,b*-1)}else(c=this.a?a.previousSibling:a.nextSibling)?M(this,c):M(this,a.parentNode,b*-1);this.d+=this.c*(this.a?-1:1)}else this.g=true;a=this.b;if(!this.b)throw K;return a};
+L.prototype.splice=function(){var a=this.b,b=this.a?1:-1;if(this.c==b){this.c=b*-1;this.d+=this.c*(this.a?-1:1)}this.a=!this.a;L.prototype.next.call(this);this.a=!this.a;b=o(arguments[0])?arguments[0]:arguments;for(var c=b.length-1;c>=0;c--)a.parentNode&&a.parentNode.insertBefore(b[c],a.nextSibling);a&&a.parentNode&&a.parentNode.removeChild(a)};function N(a,b,c,d){L.call(this,a,b,c,null,d)}r(N,L);N.prototype.next=function(){do N.j.next.call(this);while(this.c==-1);return this.b};function sa(a,b){var c=H(a);if(c.defaultView&&c.defaultView.getComputedStyle)if(c=c.defaultView.getComputedStyle(a,null))return c[b]||c.getPropertyValue(b);return""}function O(a,b){return sa(a,b)||(a.currentStyle?a.currentStyle[b]:null)||a.style[b]}
+function ta(a){var b=H(a),c=O(a,"position"),d=c=="fixed"||c=="absolute";for(a=a.parentNode;a&&a!=b;a=a.parentNode){c=O(a,"position");d=d&&c=="static"&&a!=b.documentElement&&a!=b.body;if(!d&&(a.scrollWidth>a.clientWidth||a.scrollHeight>a.clientHeight||c=="fixed"||c=="absolute"))return a}return null};function P(a,b){return!!a&&a.nodeType==1&&(!b||a.tagName.toUpperCase()==b)}
+var ua={"class":"className",readonly:"readOnly"},va=["checked","disabled","draggable","hidden"],wa=["async","autofocus","autoplay","checked","compact","complete","controls","declare","defaultchecked","defaultselected","defer","disabled","draggable","ended","formnovalidate","hidden","indeterminate","iscontenteditable","ismap","itemscope","loop","multiple","muted","nohref","noresize","noshade","novalidate","nowrap","open","paused","pubdate","readonly","required","reversed","scoped","seamless","seeking",
+"selected","spellcheck","truespeed","willvalidate"];function xa(a,b){if(8==a.nodeType)return null;b=b.toLowerCase();if(b=="style"){var c=a.style.cssText.replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").toLowerCase();return c.charAt(c.length-1)==";"?c:c+";"}c=a.getAttributeNode(b);if(!c)return null;if(A(wa,b)>=0)return"true";return c.specified?c.value:null}var ya=["BUTTON","INPUT","OPTGROUP","OPTION","SELECT","TEXTAREA"];
+function za(a){var b=a.tagName.toUpperCase();if(!(A(ya,b)>=0))return true;if(xa(a,"disabled"))return false;if(a.parentNode&&a.parentNode.nodeType==1&&"OPTGROUP"==b||"OPTION"==b)return za(a.parentNode);return true}function Q(a){for(a=a.parentNode;a&&a.nodeType!=1&&a.nodeType!=9&&a.nodeType!=11;)a=a.parentNode;return P(a)?a:null}function R(a,b){b=ja(String(b));return sa(a,b)||Aa(a,b)}
+function Aa(a,b){var c=(a.currentStyle||a.style)[b];if(c!="inherit")return c!==undefined?c:null;return(c=Q(a))?Aa(c,b):null}function Ba(a){if(m(a.getBBox)=="function")return a.getBBox();var b;if(O(a,"display")!="none")b=new G(a.offsetWidth,a.offsetHeight);else{b=a.style;var c=b.display,d=b.visibility,f=b.position;b.visibility="hidden";b.position="absolute";b.display="inline";var e;e=a.offsetWidth;a=a.offsetHeight;b.display=c;b.position=f;b.visibility=d;b=new G(e,a)}return b}
+function S(a,b){function c(e){if(R(e,"display")=="none")return false;e=Q(e);return!e||c(e)}function d(e){var g=Ba(e);if(g.height>0&&g.width>0)return true;if(e.innerText||e.textContent)if(Ca.test(e.innerText||e.textContent))return true;return C&&ka(e.childNodes,function(k){return P(k)&&d(k)})}if(!P(a))throw Error("Argument to isShown must be of type Element");if(P(a,"TITLE"))return(H(a)?H(a).parentWindow||H(a).defaultView:window)==ga;if(P(a,"OPTION")||P(a,"OPTGROUP")){var f=I(a,function(e){return P(e,
+"SELECT")});return!!f&&S(f)}if(P(a,"MAP")){if(!a.name)return false;f=H(a);f=f.evaluate?qa('/descendant::*[@usemap = "#'+a.name+'"]',f):na(f,function(e){return P(e)&&xa(e,"usemap")=="#"+a.name});return!!f&&S(f)}if(P(a,"AREA")){f=I(a,function(e){return P(e,"MAP")});return!!f&&S(f)}if(P(a,"INPUT")&&a.type.toLowerCase()=="hidden")return false;if(R(a,"visibility")=="hidden")return false;if(!c(a))return false;if(!b&&Da(a)==0)return false;if(!d(a))return false;return true}
+var Ea="[\\s\\xa0"+String.fromCharCode(160)+"]+",Ca=RegExp("^"+Ea+"$");function Da(a){var b=1,c=R(a,"opacity");if(c)b=Number(c);if(a=Q(a))b*=Da(a);return b};var Fa=["dragstart","dragexit","mouseover","mouseout"];
+function T(a,b,c){var d=H(a),f=d?d.parentWindow||d.defaultView:window,e=new F;if(a.nodeType==1)if(a.getBoundingClientRect){var g=a.getBoundingClientRect();e.x=g.left;e.y=g.top}else{g=pa(a?new J(H(a)):E||(E=new J));var k,h=H(a);k=O(a,"position");var i=new F(0,0),t=(h?h.nodeType==9?h:H(h):document).documentElement;if(a!=t)if(a.getBoundingClientRect){k=a.getBoundingClientRect();h=pa(h?new J(H(h)):E||(E=new J));i.x=k.left+h.x;i.y=k.top+h.y}else if(h.getBoxObjectFor){k=h.getBoxObjectFor(a);h=h.getBoxObjectFor(t);
+i.x=k.screenX-h.screenX;i.y=k.screenY-h.screenY}else{var j=a;do{i.x+=j.offsetLeft;i.y+=j.offsetTop;if(j!=a){i.x+=j.clientLeft||0;i.y+=j.clientTop||0}if(C&&O(j,"position")=="fixed"){i.x+=h.body.scrollLeft;i.y+=h.body.scrollTop;break}j=j.offsetParent}while(j&&j!=a);if(C&&k=="absolute")i.y-=h.body.offsetTop;for(j=a;(j=ta(j))&&j!=h.body&&j!=t;){i.x-=j.scrollLeft;i.y-=j.scrollTop}}e.x=i.x-g.x;e.y=i.y-g.y}else{g=m(a.f)=="function";i=a;if(a.targetTouches)i=a.targetTouches[0];else if(g&&a.f().targetTouches)i=
+a.f().targetTouches[0];e.x=i.clientX;e.y=i.clientY}var n=c||{};c=(n.x||0)+e.x;e=(n.y||0)+e.y;g=n.button||0;i=n.bubble||true;k=null;if(A(Fa,b)>=0)k=n.related||null;h=!!n.alt;t=!!n.control;j=!!n.shift;n=!!n.meta;if(a.fireEvent&&d&&d.createEventObject){a=d.createEventObject();a.altKey=h;a.k=t;a.metaKey=n;a.shiftKey=j;a.clientX=c;a.clientY=e;a.button=g;a.relatedTarget=k}else{a=d.createEvent("MouseEvents");if(a.initMouseEvent)a.initMouseEvent(b,i,true,f,1,0,0,c,e,t,h,j,n,g,k);else{a.initEvent(b,i,true);
+a.shiftKey=j;a.metaKey=n;a.altKey=h;a.ctrlKey=t;a.button=g}}return a}function U(a,b,c){var d=c||{};c=d.keyCode||0;var f=d.charCode||0,e=!!d.alt,g=!!d.ctrl,k=!!d.shift;d=!!d.meta;a=H(a).createEvent("Events");a.initEvent(b,true,true);a.charCode=f;a.keyCode=c;a.altKey=e;a.ctrlKey=g;a.metaKey=d;a.shiftKey=k;return a}
+function Ga(a,b,c){var d=H(a),f=c||{};c=f.bubble!==false;var e=!!f.alt,g=!!f.control,k=!!f.shift;f=!!f.meta;if(a.fireEvent&&d&&d.createEventObject){a=d.createEventObject();a.altKey=e;a.l=g;a.metaKey=f;a.shiftKey=k}else{a=d.createEvent("HTMLEvents");a.initEvent(b,c,true);a.shiftKey=k;a.metaKey=f;a.altKey=e;a.ctrlKey=g}return a}var V={};V.click=T;V.keydown=U;V.keypress=U;V.keyup=U;V.mousedown=T;V.mousemove=T;V.mouseout=T;V.mouseover=T;V.mouseup=T;
+function Ha(a,b,c){c=(V[b]||Ga)(a,b,c);if(m(a.fireEvent)=="function"||q(a.fireEvent)){try{(H(a)?H(a).parentWindow||H(a).defaultView:window).event=c}catch(d){}a=a.fireEvent("on"+b,c)}else a=a.dispatchEvent(c);return a};function Ia(a){var b;if(P(a,"OPTION"))b=true;else if(P(a,"INPUT")){b=a.type.toLowerCase();b=b=="checkbox"||b=="radio"}else b=false;if(!b)throw new v(15,"Element is not selectable");b="selected";var c=a.type&&a.type.toLowerCase();if("checkbox"==c||"radio"==c)b="checked";b=ua[b]||b;a=a[b];a=a===undefined&&A(va,b)>=0?false:a;return!!a}function Ja(a){return P(a,"SELECT")}
+function Ka(a,b){if(!za(a))throw new v(12,"Element is not currently enabled and may not be manipulated");if(!S(a,true))throw new v(11,"Element is not currently visible and may not be manipulated");if(P(a,"INPUT")){var c=a.type.toLowerCase();if(c=="checkbox"||c=="radio"){if(a.checked!=b){if(a.type=="radio"&&!b)throw new v(12,"You may not deselect a radio button");if(b!=Ia(a)){a.checked=b;Ha(a,"change")}}}else throw new v(15,"You may not select an unselectable input element: "+a.type);}else if(P(a,
+"OPTION")){c=I(a,Ja);if(!c.multiple&&!b)throw new v(15,"You may not deselect an option within a select that does not support multiple selections.");if(b!=Ia(a)){a.selected=b;Ha(c,"change")}}else throw new v(15,"You may not select an unselectable element: "+a.tagName);};function W(a){switch(m(a)){case "string":case "number":case "boolean":return a;case "function":return a.toString();case "array":return B(a,W);case "object":a=a;if("tagName"in a&&"nodeType"in a&&a.nodeType==1){var b={};b.ELEMENT=La(a);return b}if(o(a))return B(a,W);a=ba(a,function(c,d){return typeof d=="number"||p(d)});return u(a,W);default:return null}}
+function X(a,b){if(m(a)=="array")return B(a,function(c){return X(c,b)});else if(q(a))return"ELEMENT"in a?Ma(a.ELEMENT,b):u(a,function(c){return X(c,b)});return a}function Na(a){a=a||document;var b=a.$wdc_;if(!b){b=a.$wdc_={};b.i=aa()}return b}function La(a){var b=Na(a.ownerDocument),c=ca(b,function(d){return d==a});if(!c){c=":wdc:"+b.i++;b[c]=a}return c}
+function Ma(a,b){a=decodeURIComponent(a);var c=b||document,d=Na(c);if(!(a in d))throw new v(10,"Element does not exist in cache");var f=d[a];for(var e=f;e;){if(e==c.documentElement)return f;e=e.parentNode}delete d[a];throw new v(10,"Element is no longer attached to the DOM");};function Oa(a,b){var c=Ka,d=[a,b];try{if(p(c))c=new Function(c);var f=X(d),e=c.apply(null,f);W(e)}catch(g){}}var Y="_".split("."),Z=l;!(Y[0]in Z)&&Z.execScript&&Z.execScript("var "+Y[0]);for(var $;Y.length&&($=Y.shift());)if(!Y.length&&Oa!==undefined)Z[$]=Oa;else Z=Z[$]?Z[$]:Z[$]={};; return this._.apply(null,arguments);}.apply({navigator:typeof window!='undefined'?window.navigator:null}, arguments);}
diff --git a/core/res/res/raw/toggle_android.js b/core/res/res/raw/toggle_android.js
new file mode 100644
index 000000000000..d4f493432c1b
--- /dev/null
+++ b/core/res/res/raw/toggle_android.js
@@ -0,0 +1,29 @@
+function(){return function(){var l=this;
+function m(a){var b=typeof a;if(b=="object")if(a){if(a instanceof Array)return"array";else if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if(c=="[object Window]")return"object";if(c=="[object Array]"||typeof a.length=="number"&&typeof a.splice!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("splice"))return"array";if(c=="[object Function]"||typeof a.call!="undefined"&&typeof a.propertyIsEnumerable!="undefined"&&!a.propertyIsEnumerable("call"))return"function"}else return"null";else if(b==
+"function"&&typeof a.call=="undefined")return"object";return b}function aa(a){var b=m(a);return b=="array"||b=="object"&&typeof a.length=="number"}function o(a){return typeof a=="string"}function ba(a){a=m(a);return a=="object"||a=="array"||a=="function"}Math.floor(Math.random()*2147483648).toString(36);var ca=Date.now||function(){return+new Date};function p(a,b){function c(){}c.prototype=b.prototype;a.j=b.prototype;a.prototype=new c};function q(a){this.stack=Error().stack||"";if(a)this.message=String(a)}p(q,Error);q.prototype.name="CustomError";function da(a,b,c){var d={};for(var f in a)if(b.call(c,a[f],f,a))d[f]=a[f];return d}function ea(a,b,c){var d={};for(var f in a)d[f]=b.call(c,a[f],f,a);return d}function fa(a,b,c){for(var d in a)if(b.call(c,a[d],d,a))return d};function r(a,b){q.call(this,b);this.code=a;this.name=s[a]||s[13]}p(r,q);var s,ga={NoSuchElementError:7,NoSuchFrameError:8,UnknownCommandError:9,StaleElementReferenceError:10,ElementNotVisibleError:11,InvalidElementStateError:12,UnknownError:13,ElementNotSelectableError:15,XPathLookupError:19,NoSuchWindowError:23,InvalidCookieDomainError:24,UnableToSetCookieError:25,ModalDialogOpenedError:26,ModalDialogOpenError:27,ScriptTimeoutError:28},ha={};for(var ia in ga)ha[ga[ia]]=ia;s=ha;
+r.prototype.toString=function(){return"["+this.name+"] "+this.message};var ja=window;function ka(a){for(var b=1;b<arguments.length;b++){var c=String(arguments[b]).replace(/\$/g,"$$$$");a=a.replace(/\%s/,c)}return a}var la={};function ma(a){return la[a]||(la[a]=String(a).replace(/\-([a-z])/g,function(b,c){return c.toUpperCase()}))};function u(a,b){b.unshift(a);q.call(this,ka.apply(null,b));b.shift();this.m=a}p(u,q);u.prototype.name="AssertionError";function v(a,b){if(!a){var c=Array.prototype.slice.call(arguments,2),d="Assertion failed";if(b){d+=": "+b;var f=c}throw new u(""+d,f||[]);}return a};var w=Array.prototype,x=w.indexOf?function(a,b,c){v(a.length!=null);return w.indexOf.call(a,b,c)}:function(a,b,c){c=c==null?0:c<0?Math.max(0,a.length+c):c;if(o(a)){if(!o(b)||b.length!=1)return-1;return a.indexOf(b,c)}for(c=c;c<a.length;c++)if(c in a&&a[c]===b)return c;return-1},y=w.map?function(a,b,c){v(a.length!=null);return w.map.call(a,b,c)}:function(a,b,c){var d=a.length,f=Array(d),e=o(a)?a.split(""):a;for(var g=0;g<d;g++)if(g in e)f[g]=b.call(c,e[g],g,a);return f},na=w.some?function(a,b,c){v(a.length!=
+null);return w.some.call(a,b,c)}:function(a,b,c){var d=a.length,f=o(a)?a.split(""):a;for(var e=0;e<d;e++)if(e in f&&b.call(c,f[e],e,a))return true;return false};var z=true,oa="",A;if(z)A=/WebKit\/(\S+)/;if(A){var pa=A.exec(l.navigator?l.navigator.userAgent:null);oa=pa?pa[1]:""};var B;function C(a,b){this.x=a!==undefined?a:0;this.y=b!==undefined?b:0}C.prototype.toString=function(){return"("+this.x+", "+this.y+")"};function D(a,b){this.width=a;this.height=b}D.prototype.toString=function(){return"("+this.width+" x "+this.height+")"};D.prototype.floor=function(){this.width=Math.floor(this.width);this.height=Math.floor(this.height);return this};function E(a){return a.nodeType==9?a:a.ownerDocument||a.document}function qa(a,b){var c=[];return ra(a,b,c,true)?c[0]:undefined}function ra(a,b,c,d){if(a!=null){var f=0;for(var e;e=a.childNodes[f];f++){if(b(e)){c.push(e);if(d)return true}if(ra(e,b,c,d))return true}}return false}function F(a,b,c,d){if(!c)a=a.parentNode;c=d==null;for(var f=0;a&&(c||f<=d);){if(b(a))return a;a=a.parentNode;f++}return null}function G(a){this.e=a||l.document||document}
+function sa(a){a=!z&&a.e.compatMode=="CSS1Compat"?a.e.documentElement:a.e.body;return new C(a.scrollLeft,a.scrollTop)};function ta(a,b){try{var c;if(typeof b.selectSingleNode!="undefined"){var d=E(b);typeof d.setProperty!="undefined"&&d.setProperty("SelectionLanguage","XPath");c=b.selectSingleNode(a)}else if(document.implementation.hasFeature("XPath","3.0")){d=E(b);var f=d.createNSResolver(d.documentElement);c=d.evaluate(a,b,f,XPathResult.FIRST_ORDERED_NODE_TYPE,null).singleNodeValue}else c=null}catch(e){return null}if(!c)return null;if(c.nodeType!=1)throw Error("Returned node is not an element: "+a);return c};var H="StopIteration"in l?l.StopIteration:Error("StopIteration");function ua(){}ua.prototype.next=function(){throw H;};function I(a,b,c,d,f){this.a=!!b;a&&J(this,a,d);this.d=f!=undefined?f:this.c||0;if(this.a)this.d*=-1;this.h=!c}p(I,ua);I.prototype.b=null;I.prototype.c=0;I.prototype.g=false;function J(a,b,c,d){if(a.b=b)a.c=typeof c=="number"?c:a.b.nodeType!=1?0:a.a?-1:1;if(typeof d=="number")a.d=d}
+I.prototype.next=function(){var a;if(this.g){if(!this.b||this.h&&this.d==0)throw H;a=this.b;var b=this.a?-1:1;if(this.c==b){var c=this.a?a.lastChild:a.firstChild;c?J(this,c):J(this,a,b*-1)}else(c=this.a?a.previousSibling:a.nextSibling)?J(this,c):J(this,a.parentNode,b*-1);this.d+=this.c*(this.a?-1:1)}else this.g=true;a=this.b;if(!this.b)throw H;return a};
+I.prototype.splice=function(){var a=this.b,b=this.a?1:-1;if(this.c==b){this.c=b*-1;this.d+=this.c*(this.a?-1:1)}this.a=!this.a;I.prototype.next.call(this);this.a=!this.a;b=aa(arguments[0])?arguments[0]:arguments;for(var c=b.length-1;c>=0;c--)a.parentNode&&a.parentNode.insertBefore(b[c],a.nextSibling);a&&a.parentNode&&a.parentNode.removeChild(a)};function K(a,b,c,d){I.call(this,a,b,c,null,d)}p(K,I);K.prototype.next=function(){do K.j.next.call(this);while(this.c==-1);return this.b};function va(a,b){var c=E(a);if(c.defaultView&&c.defaultView.getComputedStyle)if(c=c.defaultView.getComputedStyle(a,null))return c[b]||c.getPropertyValue(b);return""}function L(a,b){return va(a,b)||(a.currentStyle?a.currentStyle[b]:null)||a.style[b]}
+function wa(a){var b=E(a),c=L(a,"position"),d=c=="fixed"||c=="absolute";for(a=a.parentNode;a&&a!=b;a=a.parentNode){c=L(a,"position");d=d&&c=="static"&&a!=b.documentElement&&a!=b.body;if(!d&&(a.scrollWidth>a.clientWidth||a.scrollHeight>a.clientHeight||c=="fixed"||c=="absolute"))return a}return null};function M(a,b){return!!a&&a.nodeType==1&&(!b||a.tagName.toUpperCase()==b)}
+var xa={"class":"className",readonly:"readOnly"},ya=["checked","disabled","draggable","hidden"],za=["async","autofocus","autoplay","checked","compact","complete","controls","declare","defaultchecked","defaultselected","defer","disabled","draggable","ended","formnovalidate","hidden","indeterminate","iscontenteditable","ismap","itemscope","loop","multiple","muted","nohref","noresize","noshade","novalidate","nowrap","open","paused","pubdate","readonly","required","reversed","scoped","seamless","seeking",
+"selected","spellcheck","truespeed","willvalidate"];function Aa(a,b){if(8==a.nodeType)return null;b=b.toLowerCase();if(b=="style"){var c=a.style.cssText.replace(/^[\s\xa0]+|[\s\xa0]+$/g,"").toLowerCase();return c.charAt(c.length-1)==";"?c:c+";"}c=a.getAttributeNode(b);if(!c)return null;if(x(za,b)>=0)return"true";return c.specified?c.value:null}var Ba=["BUTTON","INPUT","OPTGROUP","OPTION","SELECT","TEXTAREA"];
+function Ca(a){var b=a.tagName.toUpperCase();if(!(x(Ba,b)>=0))return true;if(Aa(a,"disabled"))return false;if(a.parentNode&&a.parentNode.nodeType==1&&"OPTGROUP"==b||"OPTION"==b)return Ca(a.parentNode);return true}function N(a){for(a=a.parentNode;a&&a.nodeType!=1&&a.nodeType!=9&&a.nodeType!=11;)a=a.parentNode;return M(a)?a:null}function O(a,b){b=ma(String(b));return va(a,b)||Da(a,b)}
+function Da(a,b){var c=(a.currentStyle||a.style)[b];if(c!="inherit")return c!==undefined?c:null;return(c=N(a))?Da(c,b):null}function Ea(a){if(m(a.getBBox)=="function")return a.getBBox();var b;if(L(a,"display")!="none")b=new D(a.offsetWidth,a.offsetHeight);else{b=a.style;var c=b.display,d=b.visibility,f=b.position;b.visibility="hidden";b.position="absolute";b.display="inline";var e;e=a.offsetWidth;a=a.offsetHeight;b.display=c;b.position=f;b.visibility=d;b=new D(e,a)}return b}
+function P(a,b){function c(e){if(O(e,"display")=="none")return false;e=N(e);return!e||c(e)}function d(e){var g=Ea(e);if(g.height>0&&g.width>0)return true;if(e.innerText||e.textContent)if(Fa.test(e.innerText||e.textContent))return true;return z&&na(e.childNodes,function(k){return M(k)&&d(k)})}if(!M(a))throw Error("Argument to isShown must be of type Element");if(M(a,"TITLE"))return(E(a)?E(a).parentWindow||E(a).defaultView:window)==ja;if(M(a,"OPTION")||M(a,"OPTGROUP")){var f=F(a,function(e){return M(e,
+"SELECT")});return!!f&&P(f)}if(M(a,"MAP")){if(!a.name)return false;f=E(a);f=f.evaluate?ta('/descendant::*[@usemap = "#'+a.name+'"]',f):qa(f,function(e){return M(e)&&Aa(e,"usemap")=="#"+a.name});return!!f&&P(f)}if(M(a,"AREA")){f=F(a,function(e){return M(e,"MAP")});return!!f&&P(f)}if(M(a,"INPUT")&&a.type.toLowerCase()=="hidden")return false;if(O(a,"visibility")=="hidden")return false;if(!c(a))return false;if(!b&&Ga(a)==0)return false;if(!d(a))return false;return true}
+var Ha="[\\s\\xa0"+String.fromCharCode(160)+"]+",Fa=RegExp("^"+Ha+"$");function Ga(a){var b=1,c=O(a,"opacity");if(c)b=Number(c);if(a=N(a))b*=Ga(a);return b};var Ia=["dragstart","dragexit","mouseover","mouseout"];
+function Q(a,b,c){var d=E(a),f=d?d.parentWindow||d.defaultView:window,e=new C;if(a.nodeType==1)if(a.getBoundingClientRect){var g=a.getBoundingClientRect();e.x=g.left;e.y=g.top}else{g=sa(a?new G(E(a)):B||(B=new G));var k,h=E(a);k=L(a,"position");var i=new C(0,0),t=(h?h.nodeType==9?h:E(h):document).documentElement;if(a!=t)if(a.getBoundingClientRect){k=a.getBoundingClientRect();h=sa(h?new G(E(h)):B||(B=new G));i.x=k.left+h.x;i.y=k.top+h.y}else if(h.getBoxObjectFor){k=h.getBoxObjectFor(a);h=h.getBoxObjectFor(t);
+i.x=k.screenX-h.screenX;i.y=k.screenY-h.screenY}else{var j=a;do{i.x+=j.offsetLeft;i.y+=j.offsetTop;if(j!=a){i.x+=j.clientLeft||0;i.y+=j.clientTop||0}if(z&&L(j,"position")=="fixed"){i.x+=h.body.scrollLeft;i.y+=h.body.scrollTop;break}j=j.offsetParent}while(j&&j!=a);if(z&&k=="absolute")i.y-=h.body.offsetTop;for(j=a;(j=wa(j))&&j!=h.body&&j!=t;){i.x-=j.scrollLeft;i.y-=j.scrollTop}}e.x=i.x-g.x;e.y=i.y-g.y}else{g=m(a.f)=="function";i=a;if(a.targetTouches)i=a.targetTouches[0];else if(g&&a.f().targetTouches)i=
+a.f().targetTouches[0];e.x=i.clientX;e.y=i.clientY}var n=c||{};c=(n.x||0)+e.x;e=(n.y||0)+e.y;g=n.button||0;i=n.bubble||true;k=null;if(x(Ia,b)>=0)k=n.related||null;h=!!n.alt;t=!!n.control;j=!!n.shift;n=!!n.meta;if(a.fireEvent&&d&&d.createEventObject){a=d.createEventObject();a.altKey=h;a.k=t;a.metaKey=n;a.shiftKey=j;a.clientX=c;a.clientY=e;a.button=g;a.relatedTarget=k}else{a=d.createEvent("MouseEvents");if(a.initMouseEvent)a.initMouseEvent(b,i,true,f,1,0,0,c,e,t,h,j,n,g,k);else{a.initEvent(b,i,true);
+a.shiftKey=j;a.metaKey=n;a.altKey=h;a.ctrlKey=t;a.button=g}}return a}function R(a,b,c){var d=c||{};c=d.keyCode||0;var f=d.charCode||0,e=!!d.alt,g=!!d.ctrl,k=!!d.shift;d=!!d.meta;a=E(a).createEvent("Events");a.initEvent(b,true,true);a.charCode=f;a.keyCode=c;a.altKey=e;a.ctrlKey=g;a.metaKey=d;a.shiftKey=k;return a}
+function Ja(a,b,c){var d=E(a),f=c||{};c=f.bubble!==false;var e=!!f.alt,g=!!f.control,k=!!f.shift;f=!!f.meta;if(a.fireEvent&&d&&d.createEventObject){a=d.createEventObject();a.altKey=e;a.l=g;a.metaKey=f;a.shiftKey=k}else{a=d.createEvent("HTMLEvents");a.initEvent(b,c,true);a.shiftKey=k;a.metaKey=f;a.altKey=e;a.ctrlKey=g}return a}var S={};S.click=Q;S.keydown=R;S.keypress=R;S.keyup=R;S.mousedown=Q;S.mousemove=Q;S.mouseout=Q;S.mouseover=Q;S.mouseup=Q;
+function Ka(a,b,c){c=(S[b]||Ja)(a,b,c);if(m(a.fireEvent)=="function"||ba(a.fireEvent)){try{(E(a)?E(a).parentWindow||E(a).defaultView:window).event=c}catch(d){}a=a.fireEvent("on"+b,c)}else a=a.dispatchEvent(c);return a};function T(a){var b;if(M(a,"OPTION"))b=true;else if(M(a,"INPUT")){b=a.type.toLowerCase();b=b=="checkbox"||b=="radio"}else b=false;if(!b)throw new r(15,"Element is not selectable");b="selected";var c=a.type&&a.type.toLowerCase();if("checkbox"==c||"radio"==c)b="checked";b=xa[b]||b;a=a[b];a=a===undefined&&x(ya,b)>=0?false:a;return!!a}function La(a){return M(a,"SELECT")}
+function Ma(a){if(M(a,"INPUT")&&"radio"==a.type)throw new r(12,"You may not toggle a radio button");var b=!T(a);if(!Ca(a))throw new r(12,"Element is not currently enabled and may not be manipulated");if(!P(a,true))throw new r(11,"Element is not currently visible and may not be manipulated");if(M(a,"INPUT")){var c=a.type.toLowerCase();if(c=="checkbox"||c=="radio"){if(a.checked!=b){if(a.type=="radio"&&!b)throw new r(12,"You may not deselect a radio button");if(b!=T(a)){a.checked=b;Ka(a,"change")}}}else throw new r(15,
+"You may not select an unselectable input element: "+a.type);}else if(M(a,"OPTION")){c=F(a,La);if(!c.multiple&&!b)throw new r(15,"You may not deselect an option within a select that does not support multiple selections.");if(b!=T(a)){a.selected=b;Ka(c,"change")}}else throw new r(15,"You may not select an unselectable element: "+a.tagName);return T(a)};function Na(){}
+function U(a,b,c){switch(typeof b){case "string":Oa(a,b,c);break;case "number":c.push(isFinite(b)&&!isNaN(b)?b:"null");break;case "boolean":c.push(b);break;case "undefined":c.push("null");break;case "object":if(b==null){c.push("null");break}if(m(b)=="array"){var d=b.length;c.push("[");var f="";for(var e=0;e<d;e++){c.push(f);U(a,b[e],c);f=","}c.push("]");break}c.push("{");d="";for(f in b)if(Object.prototype.hasOwnProperty.call(b,f)){e=b[f];if(typeof e!="function"){c.push(d);Oa(a,f,c);c.push(":");U(a,
+e,c);d=","}}c.push("}");break;case "function":break;default:throw Error("Unknown type: "+typeof b);}}var V={'"':'\\"',"\\":"\\\\","/":"\\/","\u0008":"\\b","\u000c":"\\f","\n":"\\n","\r":"\\r","\t":"\\t","\u000b":"\\u000b"},Pa=/\uffff/.test("\uffff")?/[\\\"\x00-\x1f\x7f-\uffff]/g:/[\\\"\x00-\x1f\x7f-\xff]/g;
+function Oa(a,b,c){c.push('"',b.replace(Pa,function(d){if(d in V)return V[d];var f=d.charCodeAt(0),e="\\u";if(f<16)e+="000";else if(f<256)e+="00";else if(f<4096)e+="0";return V[d]=e+f.toString(16)}),'"')};function W(a){switch(m(a)){case "string":case "number":case "boolean":return a;case "function":return a.toString();case "array":return y(a,W);case "object":a=a;if("tagName"in a&&"nodeType"in a&&a.nodeType==1){var b={};b.ELEMENT=Qa(a);return b}if(aa(a))return y(a,W);a=da(a,function(c,d){return typeof d=="number"||o(d)});return ea(a,W);default:return null}}
+function X(a,b){if(m(a)=="array")return y(a,function(c){return X(c,b)});else if(ba(a))return"ELEMENT"in a?Ra(a.ELEMENT,b):ea(a,function(c){return X(c,b)});return a}function Sa(a){a=a||document;var b=a.$wdc_;if(!b){b=a.$wdc_={};b.i=ca()}return b}function Qa(a){var b=Sa(a.ownerDocument),c=fa(b,function(d){return d==a});if(!c){c=":wdc:"+b.i++;b[c]=a}return c}
+function Ra(a,b){a=decodeURIComponent(a);var c=b||document,d=Sa(c);if(!(a in d))throw new r(10,"Element does not exist in cache");var f=d[a];for(var e=f;e;){if(e==c.documentElement)return f;e=e.parentNode}delete d[a];throw new r(10,"Element is no longer attached to the DOM");};function Ta(a){var b=Ma;a=[a];var c;try{if(o(b))b=new Function(b);var d=X(a),f=b.apply(null,d);c={status:0,value:W(f)}}catch(e){c={status:"code"in e?e.code:13,value:{message:e.message}}}b=[];U(new Na,c,b);return b.join("")}var Y="_".split("."),Z=l;!(Y[0]in Z)&&Z.execScript&&Z.execScript("var "+Y[0]);for(var $;Y.length&&($=Y.shift());)if(!Y.length&&Ta!==undefined)Z[$]=Ta;else Z=Z[$]?Z[$]:Z[$]={};; return this._.apply(null,arguments);}.apply({navigator:typeof window!='undefined'?window.navigator:null}, arguments);}
diff --git a/core/res/res/raw/webdriver_readme.txt b/core/res/res/raw/webdriver_readme.txt
new file mode 100644
index 000000000000..0ab66030d0ce
--- /dev/null
+++ b/core/res/res/raw/webdriver_readme.txt
@@ -0,0 +1,37 @@
+The JavaScript files *_android.js are used in frameworks/base/core/java/android/webkit/webdriver/
+. Those files contain closure compiled JavaScript from
+http://selenium.googlecode.com. They are under the Apache 2.0 licence:
+/** @license
+Copyright 2010 WebDriver committers
+Copyright 2010 Google Inc.
+
+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.
+*/
+
+The licence is not included in the compiled code to minimize the size
+of JavaScript injected into web pages.
+
+Those files can be generated by doing the following:
+$svn checkout http://selenium.googlecode.com/svn/trunk/ .
+$./go //javascript/webdriver-atoms/inject:<js_fragment_name>
+
+Where <js_fragment_name> should be replaced by the actual name of the fragment to
+generate. For example to generate is_selected_android.js, execute:
+$./go //javascript/webdriver-atoms/inject:is_selected
+
+The build file for those rules is under the following:
+http://code.google.com/p/selenium/source/browse/trunk/javascript/webdriver-atoms/inject/build.desc
+Every js_fragment rule generates a JavaScript file containing the corresponding
+JavaScript code snippet.
+
+The current version of the files was generated using revision 11823.
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 3731aaa5a785..b0bd0f48d2a8 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"للسماح للتطبيق باسترداد معلومات حول المهام المُشغلة الحالية والحديثة. قد يسمح ذلك للتطبيقات الضارة باكتشاف معلومات خاصة حول التطبيقات الأخرى."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"إعادة ترتيب التطبيقات التي قيد التشغيل"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"للسماح لتطبيق ما بنقل المهام إلى المقدمة والخلفية. قد تفرض التطبيقات الضارة نفسها إلى المقدمة بدون تحكم منك."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"تمكين تصحيح أخطاء التطبيق"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"للسماح لتطبيق ما بتشغيل تصحيح الأخطاء لتطبيق آخر. قد تستخدم التطبيقات الضارة ذلك لإنهاء التطبيقات الأخرى."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"تغيير إعدادات واجهة المستخدم"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 0173f45c01e4..2c2035ef1719 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Разрешава на приложението да извлича информация за задачите, изпълнявани понастоящем и неотдавна. Може да позволи на злонамерените приложения да открият поверителна информация за други приложения."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"пренареждане на изпълняваните приложения"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Разрешава на приложението да прехвърля задачи на преден и на заден план. Злонамерените приложения могат сами да се изведат на преден план без ваша намеса."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"активиране на отстраняването на грешки в приложения"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Разрешава на приложението да включва отстраняването на грешки в друго приложение. Злонамерените приложения могат да използват това, за да прекратят други приложения."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"промяна на настройките ви за потребителския интерфейс"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index e94e7e502ae1..46b3342df0ec 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Permet a l\'aplicació recuperar informació sobre les tasques que s\'executen actualment i que s\'han executat recentment. Pot permetre a les aplicacions malicioses descobrir informació privada sobre altres aplicacions."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"canviar l\'ordre de les aplicacions en execució"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Permet a una aplicació desplaçar tasques al primer i al segon terme. Les aplicacions malicioses poden aparèixer en primer terme sense que ho controleu."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"activar la depuració d\'aplicacions"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Permet a una aplicació activar la depuració per a una altra aplicació. Les aplicacions malicioses poden utilitzar-ho per destruir altres aplicacions."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"canviar la configuració de la IU"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 0102536c5f61..a25640a88a5b 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Umožňuje aplikaci načíst informace o aktuálně a nedávno spuštěných úlohách. Toto nastavení může škodlivým aplikacím umožnit odhalení soukromých informací o jiných aplikacích."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"změna uspořádání spuštěných aplikací"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Umožňuje aplikaci přesouvat úlohy do popředí či pozadí. Škodlivé aplikace mohou vynutit své přesunutí do popředí bez vašeho přičinění."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"povolit ladění aplikací"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Umožňuje aplikaci povolit ladění jiné aplikace. Škodlivé aplikace mohou pomocí tohoto nastavení ukončit jiné aplikace."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"změna vašeho nastavení uživatelského rozhraní"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 93b59aa4e6ed..1017d81a0161 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Tillader, at et program henter oplysninger om nuværende og for nyligt kørende opgaver. Tillader, at eventuelt ondsindede programmer finder private oplysninger om andre programmer."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"omorganiser kørende programmer"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Tillader, at et program flytter opgaver til forgrunden og baggrunden. Ondsindede programmer kan tvinge dem selv til forgrunden uden din kontrol."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"aktiver programfejlretning"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Tillader, at et program slår fejlretning af andet program til. Ondsindede programmer kan bruge dette til at standse andre programmer."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"skift indstillinger for brugergrænsefladen"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index db3e9d9d6765..d86fa076e23c 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -151,7 +151,7 @@
<string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Flugmodus"</string>
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flugmodus ist AN."</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flugmodus ist AUS."</string>
- <string name="status_bar_notification_info_overflow" msgid="5833510281787786290">"100 +"</string>
+ <string name="status_bar_notification_info_overflow" msgid="5833510281787786290">"Mehr als 100"</string>
<string name="safeMode" msgid="2788228061547930246">"Abgesicherter Modus"</string>
<string name="android_system_label" msgid="6577375335728551336">"Android-System"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Kostenpflichtige Dienste"</string>
@@ -161,7 +161,7 @@
<string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Ihre persönlichen Informationen"</string>
<string name="permgroupdesc_personalInfo" product="tablet" msgid="6975389054186265786">"Direkter Zugriff auf die Kontakte und den Kalender Ihres Tablets"</string>
<string name="permgroupdesc_personalInfo" product="default" msgid="5488050357388806068">"Direkter Zugriff auf die Kontakte und den Kalender Ihres Telefons"</string>
- <string name="permgrouplab_location" msgid="635149742436692049">"Ihren Standort"</string>
+ <string name="permgrouplab_location" msgid="635149742436692049">"Meinen Standort"</string>
<string name="permgroupdesc_location" msgid="2430258821648348660">"Ihren physischen Standort überwachen"</string>
<string name="permgrouplab_network" msgid="5808983377727109831">"Netzwerkkommunikation"</string>
<string name="permgroupdesc_network" msgid="5035763698958415998">"Ermöglicht Anwendungen den Zugriff auf verschiedene Netzwerkfunktionen"</string>
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Ermöglicht der Anwendung, Informationen zu aktuellen und kürzlich ausführten Aufgaben abzurufen. Schädliche Anwendungen können so eventuell geheime Informationen zu anderen Anwendungen entdecken."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"Laufende Anwendungen neu ordnen"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Ermöglicht einer Anwendung, Aufgaben in den Vorder- und Hintergrund zu verschieben. Schädliche Anwendungen können so ohne Ihr Zutun eine Anzeige im Vordergrund erzwingen."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"Fehlerbeseitigung für Anwendung aktivieren"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Ermöglicht einer Anwendung, die Fehlerbeseitigung für eine andere Anwendung zu aktivieren. Schädliche Anwendungen können so andere Anwendungen löschen."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"UI-Einstellungen ändern"</string>
@@ -465,7 +469,7 @@
<string name="permdesc_sdcardWrite" product="nosdcard" msgid="6594393334785738252">"Ermöglicht der Anwendung Schreiben in USB-Speicher"</string>
<string name="permdesc_sdcardWrite" product="default" msgid="6643963204976471878">"Ermöglicht einer Anwendung, auf die SD-Karte zu schreiben"</string>
<string name="permlab_mediaStorageWrite" product="default" msgid="6859839199706879015">"Intern. Mediensp. änd./löschen"</string>
- <string name="permdesc_mediaStorageWrite" product="default" msgid="8232008512478316233">"Ermöglicht es einer Anwendung, den Inhalt des internen Medienspeichers zu ändern"</string>
+ <string name="permdesc_mediaStorageWrite" product="default" msgid="8232008512478316233">"Ermöglicht einer Anwendung, den Inhalt des internen Medienspeichers zu ändern"</string>
<string name="permlab_cache_filesystem" msgid="5656487264819669824">"Zugriff auf das Cache-Dateisystem"</string>
<string name="permdesc_cache_filesystem" msgid="1624734528435659906">"Gewährt einer Anwendung Lese- und Schreibzugriff auf das Cache-Dateisystem."</string>
<string name="permlab_use_sip" msgid="5986952362795870502">"Internetanrufe tätigen/annehmen"</string>
@@ -966,7 +970,7 @@
<string name="l2tp_ipsec_psk_vpn_description" msgid="3945043564008303239">"L2TP/IPSec-VPN mit vorinstalliertem Schlüssel"</string>
<string name="l2tp_ipsec_crt_vpn_description" msgid="5382714073103653577">"L2TP/IPSec-VPN mit Zertifikat"</string>
<string name="upload_file" msgid="2897957172366730416">"Datei auswählen"</string>
- <string name="no_file_chosen" msgid="6363648562170759465">"Keine Datei ausgewählt"</string>
+ <string name="no_file_chosen" msgid="6363648562170759465">"Keine ausgewählt"</string>
<string name="reset" msgid="2448168080964209908">"Zurücksetzen"</string>
<string name="submit" msgid="1602335572089911941">"Senden"</string>
<string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Automodus aktiviert"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 571dc4347f09..a5d292772b44 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Επιτρέπει σε μια εφαρμογή να ανακτήσει πληροφορίες σχετικά με τις τρέχουσες εκτελούμενες εργασίες και στις εργασίες που έχουν πρόσφατα εκτελεστεί. Ενδέχεται να δώσει τη δυνατότητα σε κακόβουλες εφαρμογές να ανακαλύψουν ιδιωτικές πληροφορίες σχετικά με άλλες εφαρμογές."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"αναδιάταξη εκτελούμενων εφαρμογών"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Επιτρέπει σε μια εφαρμογή τη μετακίνηση εργασιών στο προσκήνιο και στο φόντο. Κακόβουλες εφαρμογές μπορούν να προωθηθούν στο προσκήνιο χωρίς να μπορείτε να τις ελέγξετε."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"ενεργοποίηση εντοπισμού σφαλμάτων εφαρμογής"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Επιτρέπει σε μια εφαρμογή να ενεργοποιήσει τον εντοπισμό σφαλμάτων για μια άλλη εφαρμογή. Κακόβουλες εφαρμογές μπορούν να το χρησιμοποιήσουν για να τερματίσουν άλλες εφαρμογές."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"αλλαγή των ρυθμίσεων του UI"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 7015d4836268..f6ed3255b675 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Allows application to retrieve information about currently and recently running tasks. May allow malicious applications to discover private information about other applications."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"reorder applications running"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Allows an application to move tasks to the foreground and background. Malicious applications can force themselves to the front without your control."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"enable application debugging"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Allows an application to turn on debugging for another application. Malicious applications can use this to kill other applications."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"change your UI settings"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 0052b181533e..820f5e213197 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Admite que la aplicación recupere información sobre tareas en ejecución actuales y recientes. Puede permitir que las aplicaciones maliciosas descubran información privada sobre otras aplicaciones."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"reorganizar aplicaciones en ejecución"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Admite una aplicación que mueve tareas hacia el frente y el fondo. Las aplicaciones maliciosas pueden provocar su propio movimiento hacia el frente sin tu control."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"activar la depuración de la aplicación"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Admite una aplicación que activa la depuración en otra aplicación. Las aplicaciones maliciosas pueden utilizarlo para suprimir otras aplicaciones."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"cambiar tu configuración de la interfaz de usuario"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index bdca91fd9345..2e187a5f0827 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Permite que la aplicación recupere información sobre tareas que se están ejecutando en este momento o que se han ejecutado recientemente. Puede permitir que las aplicaciones malintencionadas vean información privada sobre otras aplicaciones."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"reorganizar aplicaciones en ejecución"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Permite que una aplicación mueva tareas a segundo plano y a primer plano. Las aplicaciones malintencionadas pueden aparecer en primer plano sin tu control."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"habilitar depuración de aplicación"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Permite que una aplicación active la depuración de otra aplicación. Las aplicaciones malintencionadas pueden utilizar este permiso para desactivar otras aplicaciones."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"cambiar la configuración de la interfaz de usuario"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 1f3ca7ea9263..726bbabccb54 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"به برنامه کاربردی اجازه می دهد اطلاعات مربوط به کارهای در حال اجرای فعلی و کارهای اخیر را بازیابی کند. ممکن است برنامه های مضر بتوانند اطلاعات خصوصی مربوط به شما را در ارتباط به سایر برنامه ها مشاهده کنند."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"ترتیب بندی مجدد برنامه های در حال اجرا"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"به یک برنامه کاربردی اجازه می دهد تا وظایف را به پیش زمینه و پس زمینه منتقل کند. برنامه های مضر می توانند بدون کنترل شما خودشان را به پیش زمینه منتقل کنند."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"فعال کردن رفع عیب برنامه"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"به یک برنامه کاربردی اجازه می دهد رفع عیب را برای یک برنامه دیگر فعال کند. برنامه های مضر می توانند از این ویژگی برای از بین بردن سایر برنامه ها استفاده کنند."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"تغییر تنظیمات UI"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index c9b6826ea186..1c99fc64c7e7 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Antaa sovelluksen noutaa tietoja käynnissä olevista ja äskettäin käynnissä olleista tehtävistä. Haitalliset sovellukset saattavat saada selville yksityisiä tietoja muista sovelluksista."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"muuttaa käynnissä olevien sovelluksien järjestystä"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Antaa sovelluksen siirtää tehtäviä etualalle ja taustalle. Haitalliset sovellukset voivat tunkeutua etualalle väkisin."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"ota sovelluksen vianetsintä käyttöön"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Antaa sovelluksen käynnistää toisen sovelluksen vianetsinnän. Haitalliset sovellukset saattavat sulkea muita sovelluksia."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"muuta käyttöliittymäsi asetuksia"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index b38ae93770b8..ab33b5c63bf5 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Permet à l\'application de récupérer des informations sur des tâches en cours d\'exécution ou récemment utilisées. Des applications malveillantes peuvent ainsi obtenir des informations d\'ordre privé concernant d\'autres applications."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"Réorganisation des applications en cours d\'exécution"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Permet à une application de placer des tâches au premier plan ou en arrière-plan. Des applications malveillantes peuvent se placer inopinément au premier plan sans votre autorisation."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"Activation du débogage de l\'application"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Permet à une application d\'activer le mode de débogage d\'une autre application. Des applications malveillantes peuvent utiliser cette fonctionnalité pour interrompre d\'autres applications de façon inopinée."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"Modification des paramètres de l\'IU"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index d8c64f0e9df0..69543641b549 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Aplikaciji omogućuje dohvaćanje podataka o trenutačno ili nedavno pokrenutim zadacima. Zlonamjernim aplikacijama može omogućiti otkrivanje privatnih podataka o drugim aplikacijama."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"promjena redoslijeda pokrenutih aplikacija"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Aplikaciji omogućuje premještanje zadataka u prvi plan ili u pozadinu. Zlonamjerne aplikacije mogu se prisilno postaviti u prednji plan bez vašeg znanja."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"omogućavanje uklanjanja programskih pogrešaka u aplikacijama"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Aplikaciji omogućuje uključivanje značajke uklanjanja programske pogreške za drugu aplikaciju. Zlonamjerne aplikacije to mogu koristiti za uklanjanje drugih aplikacija."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"promjena postavki korisničkog sučelja"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index ea4f81f7ad86..55b7cc2b92f2 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Lehetővé teszi az alkalmazás számára a jelenleg és a nemrég futó feladatok adatainak lekérését. A rosszindulatú alkalmazások privát adatokhoz juthatnak más alkalmazásokból."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"futó alkalmazások átrendezése"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Lehetővé teszi egy 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>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"hibakeresés engedélyezése alkalmazásoknál"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Lehetővé teszi egy 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>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 4d5352ab019c..50a1aad9854c 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Mengizinkan aplikasi mengambil informasi tentang tugas yang sedang dan baru saja dijalankan. Aplikasi hasad dapat menemukan informasi bajakan tentang aplikasi lain."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"atur urutan aplikasi yang berjalan"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Mengizinkan aplikasi memindah tugas ke latar depan dan latar belakang. Aplikasi hasad dapat memaksa dirinya ke latar depan tanpa sepengetahuan Anda."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"aktifkan debugging aplikasi"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Mengizinkan aplikasi menghidupkan debug untuk aplikasi lain. Aplikasi hasad dapat menggunakan ini untuk menghentikan aplikasi penting lainnya."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"ubah setelan UI Anda"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 3196dbe8a9e3..be7234e20715 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Consente all\'applicazione di recuperare informazioni sulle attività in esecuzione ed eseguite di recente. Le applicazioni dannose potrebbero essere in grado di scoprire informazioni riservate su altre applicazioni."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"riordinamento applicazioni in esecuz."</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Consente a un\'applicazione di spostare attività in primo e secondo piano. Le applicazioni dannose possono imporsi ponendosi automaticamente in primo piano."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"attivazione debug delle applicazioni"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Consente a un\'applicazione di attivare il debug per un\'altra applicazione. Le applicazioni dannose possono sfruttare questa possibilità per interrompere altre applicazioni."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"modifica impostazioni UI"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 07fab9e2c2eb..e7751821ce10 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"מאפשר ליישום לאחזר מידע על משימות הפועלות כעת ושפעלו לאחרונה. עלול לאפשר ליישומים זדוניים לגלות מידע פרטי על יישומים אחרים."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"שנה את סדר היישומים הפועלים"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"מאפשר ליישום להעביר משימות לחזית ולרקע. יישומים זדוניים עלולים לאלץ את עצמם לחזית מבלי שתוכל לשלוט בהם."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"הפוך איתור באגים ביישום לפעיל"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"מאפשר ליישום להפעיל איתור באגים עבור יישום אחר. יישומים זדוניים יכולים להשתמש ביכולת זו כדי להשמיד יישומים אחרים."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"שנה את הגדרות ממשק המשתמש"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index c6a5f9519a7d..fb302528dcbb 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"現在実行中または最近実行したタスクに関する情報の取得をアプリケーションに許可します。悪意のあるアプリケーションが他のアプリケーションの非公開情報を取得する恐れがあります。"</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"実行中のアプリケーションの順序の変更"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"タスクをフォアグラウンドやバックグラウンドに移動することをアプリケーションに許可します。悪意のあるアプリケーションが優先されて、コントロールできなくなる恐れがあります。"</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"アプリケーションのデバッグを有効にする"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"別のアプリケーションをデバッグモードにすることをアプリケーションに許可します。悪意のあるアプリケーションが別のアプリケーションを終了させる恐れがあります。"</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"UI設定の変更"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 1b7051ed86e1..af83195fdacb 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"애플리케이션이 현재 실행 중이거나 최근에 실행된 작업에 대한 정보를 검색할 수 있도록 합니다. 이 경우 악성 애플리케이션이 다른 애플리케이션에 대한 개인 정보를 검색할 수 있습니다."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"실행 중인 애플리케이션 순서 재지정"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"애플리케이션이 작업을 포그라운드나 백그라운드로 이동할 수 있도록 합니다. 이 경우 악성 애플리케이션이 사용자의 조작 없이 앞으로 이동할 수 있습니다."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"애플리케이션 디버깅 사용"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"애플리케이션이 다른 애플리케이션에 대해 디버깅을 사용할 수 있도록 합니다. 이 경우 악성 애플리케이션이 다른 애플리케이션을 중지시킬 수 있습니다."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"UI 설정 변경"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 850a6c9e468f..7d8983007b67 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Leidžia programai nuskaityti informaciją apie dabar ir neseniai veikusias užduotis. Gali leisti kenkėjiškoms programoms atrasti privačią informaciją apie kitas programas."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"iš naujo užsakyti veikiančias programas"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Leidžia programai perkelti užduotis į aktyvųjį langą ir foną. Kenkėjiškos programos gali persikelti į priekį jums nieko nedarant."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"įgalinti programos derinimą"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Leidžia programai įjungti kitos programos derinimą. Kenkėjiškos programos tai gali naudoti, kad nutrauktų kitas programas."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"keisti UI nustatymus"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index a4936ac47b8a..ccc5fc179f75 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Ļauj lietojumprogrammai izgūt informāciju par pašlaik un nesen darbinātajiem uzdevumiem. Var atļaut lietojumprogrammām atklāt privātu informāciju par citām lietojumprogrammām."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"pārkārtot aktīvās lietojumprogrammas"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Ļauj lietojumprogrammai pārvietot uzdevumus priekšplānā vai fonā. Ļaunprātīgas lietojumprogrammas var tikt parādītas priekšplānā bez jūsu vadības."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"iespējot lietojumprogrammas atkļūdošanu"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Ļauj lietojumprogrammai ieslēgt citas lietojumprogrammas atkļūdošanu. Ļaunprātīgas lietojumprogrammas var to izmantot, lai pārtrauktu citu lietojumprogrammu darbību."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"mainīt lietotāja saskarnes iestatījumus"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 3b15f8852190..1c6d93966aa4 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Tillater applikasjonen å hente informasjon om aktive og nylig kjørte programmer. Kan tillate ondsinnede applikasjoner å oppdage privat informasjon om andre applikasjoner."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"omordne kjørende applikasjoner"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Tillater applikasjonen å flytte programmer til forgrunnen eller bakgrunnen. Ondsinnede applikasjoner kan tvinge seg selv til fronten."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"aktiver applikasjonsdebugging"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Lar applikasjonen skru på debugging for en annen applikasjon. Ondsinnede applikasjoner kan bruke dette til å drepe andre applikasjoner."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"endre innstillingene for brukergrensesnitt"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 5ca1e4d1be41..3b612fa472ad 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Hiermee kan een app informatie over huidige en recent uitgevoerde taken ophalen. Schadelijke apps kunnen op deze manier mogelijk privé-informatie over andere apps achterhalen."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"actieve toepassingen opnieuw indelen"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Hiermee kan een 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>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"foutopsporing in toepassingen inschakelen"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Hiermee kan een 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>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 043faafce74d..d939ce6649c0 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Umożliwia aplikacji pobieranie informacji na temat obecnie i ostatnio uruchomionych zadań. Może pozwolić szkodliwym aplikacjom na uzyskanie prywatnych informacji na temat innych aplikacji."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"zmienianie porządku uruchomionych aplikacji"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Pozwala aplikacji na przenoszenie zadań z tła na pierwszy plan. Szkodliwe aplikacje mogą wymusić działanie pierwszoplanowe bez kontroli użytkownika."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"włączenie debugowania aplikacji"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Pozwala aplikacji na włączenie debugowania innej aplikacji. Szkodliwe aplikacje mogą to wykorzystać do wyłączenia innych programów."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"zmienianie ustawień interfejsu użytkownika"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 1e2bd2253bd1..c49dc45b6e2a 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Permite à aplicação obter informações sobre tarefas actualmente em execução e recentemente executadas. Pode permitir que aplicações maliciosas descubram informações privadas sobre outras aplicações."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"reordenar aplicações em execução"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Permite a uma aplicação mover tarefas do primeiro e do segundo planos. Algumas aplicações maliciosas podem impor-se no primeiro plano sem o controlo do utilizador."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"activar depuração da aplicação"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Permite a uma aplicação activar a depuração para outra aplicação. Algumas aplicações maliciosas podem utilizar este item para eliminar outras aplicações."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"alterar definições da IU"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index fd3775aeee46..32e331405776 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Permite que o aplicativo recupere as informações sobre tarefas em execução no momento ou recentemente. Pode permitir que aplicativos maliciosos descubram informações particulares sobre outros aplicativos."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"reorganizar aplicativos em execução"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Permite que um aplicativo mova as tarefas para o primeiro e para o segundo planos. Aplicativos maliciosos podem se forçar à frente sem o seu controle."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"ativar depuração do aplicativo"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Permite que um aplicativo ative a depuração de outro aplicativo. Aplicativos maliciosos podem usar isso para encerrar outros aplicativos."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"alterar as suas configurações de UI"</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index bc1e133213a7..87796f71097c 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -208,6 +208,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Permetta a l\'applicaziun da recuperar infurmaziuns davart incumbensas che vegnan exequidas u èn gist vegnidas exequidas. Applicaziuns donnegiusas pon uschia obtegnair infurmaziuns privatas concernent autras applicaziuns."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"reorganisar las applicaziuns che vegnan exequidas"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Permetta ad ina applicaziun da spustar las incumbensas en il fund davant u en il fund davos. Applicaziuns donnegiusas pon sa mussar en il fund davant senza Vossa autorisaziun."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"activar il debugging da l\'applicaziun"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Permetta ad ina applicaziun dad activar il debugging per autras applicaziuns. Applicaziuns donnegiusas pon uschia serrar autras applicaziuns."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"modifitgar ils parameters da la UI"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index b38812810c3e..e07374ee24dd 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Permite aplicaţiei să regăsească informaţii despre activităţile rulate curent şi recent. Poate permite aplicaţiilor rău-intenţionate să descopere informaţii confidenţiale despre alte aplicaţii."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"reordonare aplicaţii aflate în derulare"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Permite unei aplicaţii să mute activităţile în prim-plan şi în fundal. Aplicaţiile rău-intenţionate ar putea să apară forţat în prim-plan, fără ca dvs. să puteţi controla acest lucru."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"activare depanare aplicaţie"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Permite unei aplicaţii să activeze depanarea pentru o altă aplicaţie. Aplicaţiile rău-intenţionate ar putea să utilizeze această permisiune pentru a închide alte aplicaţii."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"modificare setări UI"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 8e8f87fd47e5..7227a34eadf7 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Позволяет приложению получать сведения о последних и текущих задачах. Вредоносные приложения могут получить доступ к конфиденциальной информации о других приложениях."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"изменять порядок запущенных приложений"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Позволяет приложению переключать режим выполнения задачи с активного на фоновый. Вредоносные приложения могут установить для себя активный режим без уведомления."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"запускать отладку приложения"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Позволяет приложению запускать процесс отладки другого приложения. Вредоносные приложения могут использовать эту возможность для остановки других приложений."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"изменять настройки пользовательского интерфейса"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 8a37fd11c7ed..9a58c36d6721 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Umožňuje aplikácii načítať informácie o aktuálne a nedávno spustených úlohách. Toto nastavenie môže škodlivým aplikáciám umožniť odhaliť súkromné informácie o iných aplikáciách."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"zmena usporiadania spustených aplikácií"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Umožňuje aplikácii presúvať úlohy do popredia alebo pozadia. Škodlivé aplikácie môžu vynútiť svoje presunutia do popredia bez vášho pričinenia."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"povoliť ladenie aplikácií"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Umožňuje aplikácii povoliť ladenie inej aplikácie. Škodlivé aplikácie môžu pomocou tohto nastavenia ukončiť iné aplikácie."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"zmeny vašich nastavení používateľského rozhrania"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 6ee4ac0338ef..6c2830bd780d 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Programu dovoljuje pridobivanje informacij o trenutnih in nedavno izvajajočih se opravilih. Zlonamerni programi lahko odkrijejo zasebne podatke o drugih programih."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"preurejanje programov, ki se izvajajo"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Programu dovoljuje premikanje opravil v ospredje in ozadje. Zlonamerni programi se lahko brez vašega nadzora vsilijo v ospredje."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"omogočanje iskanja in odpravljanja napak v programu"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Programu dovoljuje vklop funkcije iskanja in odpravljanja napak za drug program. Zlonamerni programi lahko to uporabijo za zapiranje drugih programov."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"spreminjanje nastavitev UV"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 6faf9daa168f..f67979b40afa 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Омогућава да апликација преузима информације о тренутно и недавно покренутим задацима. На тај начин злонамерне апликације могу да стекну увид у приватне информације о другим апликацијама."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"промена редоследа покретања апликација"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Омогућава да апликација премешта задатке у први план и позадину. Злонамерне апликације могу на тај начин да принудно пређу у први план, при чему ви нећете имати контролу над тим."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"омогућавање отклањања грешака у апликацији"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Омогућава да апликација укључи отклањање грешака за другу апликацију. Злонамерне апликације могу то да злоупотребе и искористе за онемогућавање других апликација."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"промена подешавања корисничког интерфејса"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index fcc1fddfb7f2..041391802672 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Tillåter att program hämtar information om uppgifter som körs och har körts. Skadliga program kan upptäcka privat information om andra program."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"byt ordning på appar som körs"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Tillåter att ett program flyttar uppgifter till förgrunden eller bakgrunden. Skadliga program kan tvinga sig till förgrunden utan att du kan styra det."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"aktivera felsökning av appar"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Tillåter att ett program aktiverar felsökning för ett annat program. Skadliga program kan använda detta för att avsluta andra program."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"ändra dina gränssnittsinställningar"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index fae3853bc485..aab60b5e0583 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"อนุญาตให้แอปพลิเคชันเรียกดูข้อมูลเกี่ยวกับงานที่ทำเมื่อไม่นานมานี้และที่กำลังทำอยู่ วิธีนี้อาจทำให้แอปพลิเคชันที่เป็นอันตรายพบข้อมูลที่เป็นความลับเกี่ยวกับแอปพลิเคชันอื่นได้"</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"จัดลำดับแอปพลิเคชันที่ทำงานอยู่ใหม่"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"อนุญาตให้แอปพลิเคชันย้ายงานไปที่ด้านหน้าและพื้นหลัง แอปพลิเคชันที่เป็นอันตรายสามารถบังคับตัวเองให้อยู่ด้านหน้าได้โดยไม่ต้องให้คุณควบคุม"</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"เปิดใช้งานการแก้ไขข้อบกพร่องของแอปพลิเคชัน"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"อนุญาตให้แอปพลิเคชันเปิดการแก้ไขข้อบกพร่องสำหรับแอปพลิเคชันอื่น แอปพลิเคชันที่เป็นอันตรายอาจใช้วิธีนี้จบการทำงานแอปพลิเคชันอื่น"</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"เปลี่ยนการตั้งค่า UI ของคุณ"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 5d4a9162370c..10c34384acea 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Pinapayagan ang application na ibalik ang impormasyon tungkol sa mga kasalukuyan at kamakailang tumatakbong gawain. Maaaring payagan ang mga nakakahamak na application na tuklasin ang pribadong impormasyon tungkol sa ibang mga application."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"muling pagsunud-sunurin ang mga tumatakbong application"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Pinapayagan ang isang application na ilipat ang mga gawain sa foreground at background. Mapupuwersa ng mga nakakahamak na application ang mga sarili nito sa harapan nang wala ng iyong kontrol."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"paganahin ang debugging ng application"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Pinapayagan ang isang application na i-on ang debugging para sa isa pang application. Magagamit ito ng mga nakakahamak na application upang alisin ang ibang mga application."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"baguhin ang iyong mga setting ng UI"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index ad4eee7946ab..20ddef3ea5fc 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Uygulamaların şu anda ve yakın geçmişte çalışmakta olan işlemler hakkında bilgi almasına izin verir. Kötü amaçlı uygulamaların diğer uygulamalar ile ilgili gizli bilgileri keşfetmesine izin verebilir."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"çalışan uygulamaları yeniden sırala"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Uygulamaların görevleri ön plana ve arka plana taşımasına izin verir. Kötü amaçlı uygulamalar kendilerini sizin denetiminiz dışında zorla ön plana çıkarabilir."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"uygulama hata ayıklamayı etkinleştir"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Bir uygulamanın başka bir uygulama için hata ayıklamayı çalıştırmasına izin verir. Kötü amaçlı uygulamalar bu işlevi başka uygulamaları kapatmak için kullanabilir."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"kullanıcı arayüzü ayarlarınızı değiştirin"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 60cea7bb2bd0..b7230048076b 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Дозволяє програмі отримувати інформацію про теперішні й останні завдання. Може дозволити шкідливим програмам дізнаватися приватну інформацію про інші програми."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"змін. порядок запущених програм"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Дозволяє програмі робити завдання активними та фоновими. Шкідливі програми можуть примусово ставати активними без контролю з вашого боку."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"увімк. налагодження програми"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Дозволяє програмі вмикати налагодження для іншої програми. Шкідливі програми можуть використовувати це для заверш. роботи ін. програм."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"змін. налашт. інтерф. кор."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 8070767d54e4..f200fdd0a6b3 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"Cho phép ứng dụng truy xuất thông tin về các công việc hiện đang chạy. Có thể cho phép các ứng dụng độc hại phát hiện thông tin riêng tư về các ứng dụng khác."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"sắp xếp lại các ứng dụng đang chạy"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Cho phép ứng dụng di chuyển công việc lên trên nền và dưới nền. Các ứng dụng độc hại có thể tự hiện lên trước mà không cần sự kiểm soát của bạn."</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"cho phép gỡ lỗi ứng dụng"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Cho phép ứng dụng bật gỡ lỗi cho ứng dụng khác. Các ứng dụng độc hại có thể sử dụng quyền này đề loại bỏ các ứ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>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index fce5fcaad946..124bd8e88a3e 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"允许应用程序检索有关当前和最近运行的任务的信息。恶意应用程序可借此发现有关其他应用程序的保密信息。"</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"对正在运行的应用程序重新排序"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"允许应用程序将任务移至前端和后台。恶意应用程序可借此强行进入前端,而不受您的控制。"</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"启用应用程序调试"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"允许应用程序启动对其他应用程序的调试。恶意应用程序可借此终止其他应用程序。"</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"更改用户界面设置"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index f87c2f67156d..33825c74b4bf 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -204,6 +204,10 @@
<string name="permdesc_getTasks" msgid="7048711358713443341">"允許應用程式取得最近執行任務的資訊。請注意:惡意程式可能利用此功能找出其他應用程式的隱私資訊。"</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"重新安排執行中的應用程式"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"允許應用程式將工作移至前端或背景作業。請注意:惡意程式可能使用此功能自行把自己拉到前端。"</string>
+ <!-- no translation found for permlab_removeTasks (4802740047161700683) -->
+ <skip />
+ <!-- no translation found for permdesc_removeTasks (2000332928514575461) -->
+ <skip />
<string name="permlab_setDebugApp" msgid="4339730312925176742">"啟用應用程式偵錯"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"允許應用程式為其他程式開啟偵錯功能。請注意:惡意程式可利用此功能終止其他應用程式。"</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"變更介面設定"</string>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 80beaa54f548..9b04f7803e6b 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1169,6 +1169,10 @@
component specific values). -->
<attr name="enabled" />
<attr name="exported" />
+ <!-- If set to true, this service with be automatically stopped
+ when the user remove a task rooted in an activity owned by
+ the application. The default is false. -->
+ <attr name="stopWithTask" format="boolean" />
</declare-styleable>
<!-- The <code>receiver</code> tag declares an
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index d5c374d813f2..778d9344d1de 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1656,6 +1656,7 @@
<public type="attr" name="state_hovered" />
<public type="attr" name="state_drag_can_accept" />
<public type="attr" name="state_drag_hovered" />
+ <public type="attr" name="stopWithTask" />
<public type="style" name="Theme.Holo.Light.NoActionBar" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 8ef9a3b247b4..bc419ec419ee 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -506,6 +506,13 @@
tasks to the foreground and background. Malicious applications can force
themselves to the front without your control.</string>
+ <!-- Title of an application permission, allowing an application to remove/kill tasks -->
+ <string name="permlab_removeTasks">stop running applications</string>
+ <!-- Description of an application permission, allowing an application to remove/kill tasks -->
+ <string name="permdesc_removeTasks">Allows an application to remove
+ tasks and kill their applications. Malicious applications can disrupt
+ the behavior of other applications.</string>
+
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_setDebugApp">enable application debugging</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
index 3667c7be304b..d22356dfe230 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/AccessPointParserHelper.java
@@ -182,6 +182,7 @@ public class AccessPointParserHelper {
}
config.proxySettings = ProxySettings.NONE;
networks.add(config);
+ mLinkProperties = null;
}
}
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
index e13820060737..adf1883c8a5e 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
@@ -242,10 +242,10 @@ public class ConnectivityManagerTestActivity extends Activity {
initializeNetworkStates();
- if (mWifiManager.isWifiEnabled()) {
- log("Clear Wifi before we start the test.");
- removeConfiguredNetworksAndDisableWifi();
- }
+ mWifiManager.setWifiEnabled(true);
+ log("Clear Wifi before we start the test.");
+ sleep(SHORT_TIMEOUT);
+ removeConfiguredNetworksAndDisableWifi();
mWifiRegexs = mCM.getTetherableWifiRegexs();
}
@@ -633,13 +633,13 @@ public class ConnectivityManagerTestActivity extends Activity {
* Disconnect from the current AP and remove configured networks.
*/
public boolean disconnectAP() {
- if (mWifiManager.isWifiEnabled()) {
- // remove saved networks
- List<WifiConfiguration> wifiConfigList = mWifiManager.getConfiguredNetworks();
- for (WifiConfiguration wifiConfig: wifiConfigList) {
- log("remove wifi configuration: " + wifiConfig.toString());
- mWifiManager.forgetNetwork(wifiConfig.networkId);
- }
+ // remove saved networks
+ List<WifiConfiguration> wifiConfigList = mWifiManager.getConfiguredNetworks();
+ log("size of wifiConfigList: " + wifiConfigList.size());
+ for (WifiConfiguration wifiConfig: wifiConfigList) {
+ log("remove wifi configuration: " + wifiConfig.networkId);
+ int netId = wifiConfig.networkId;
+ mWifiManager.forgetNetwork(netId);
}
return true;
}
@@ -655,20 +655,23 @@ public class ConnectivityManagerTestActivity extends Activity {
* Remove configured networks and disable wifi
*/
public boolean removeConfiguredNetworksAndDisableWifi() {
- if (!disconnectAP()) {
- return false;
- }
- // Disable Wifi
- if (!mWifiManager.setWifiEnabled(false)) {
- return false;
- }
- // Wait for the actions to be completed
- try {
- Thread.sleep(SHORT_TIMEOUT);
- } catch (InterruptedException e) {}
+ if (!disconnectAP()) {
+ return false;
+ }
+ sleep(SHORT_TIMEOUT);
+ if (!mWifiManager.setWifiEnabled(false)) {
+ return false;
+ }
+ sleep(SHORT_TIMEOUT);
return true;
}
+ private void sleep(long sleeptime) {
+ try {
+ Thread.sleep(sleeptime);
+ } catch (InterruptedException e) {}
+ }
+
/**
* Set airplane mode
*/
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
index fe79e6c43300..22b17597bc24 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/WifiConnectionTest.java
@@ -72,10 +72,8 @@ public class WifiConnectionTest
@Override
public void setUp() throws Exception {
super.setUp();
- log("before we launch the test activity, we preserve all the configured networks.");
mRunner = ((ConnectivityManagerTestRunner)getInstrumentation());
mWifiManager = (WifiManager) mRunner.getContext().getSystemService(Context.WIFI_SERVICE);
- enabledNetworks = getEnabledNetworks(mWifiManager.getConfiguredNetworks());
mAct = getActivity();
mWifiManager.asyncConnect(mAct, new WifiServiceHandler());
@@ -123,42 +121,9 @@ public class WifiConnectionTest
public void tearDown() throws Exception {
log("tearDown()");
mAct.removeConfiguredNetworksAndDisableWifi();
- reEnableNetworks(enabledNetworks);
super.tearDown();
}
- private Set<WifiConfiguration> getEnabledNetworks(List<WifiConfiguration> configuredNetworks) {
- Set<WifiConfiguration> networks = new HashSet<WifiConfiguration>();
- for (WifiConfiguration wifiConfig : configuredNetworks) {
- if (wifiConfig.status == Status.ENABLED || wifiConfig.status == Status.CURRENT) {
- networks.add(wifiConfig);
- log("remembering enabled network " + wifiConfig.SSID +
- " status is " + wifiConfig.status);
- }
- }
- return networks;
- }
-
- private void reEnableNetworks(Set<WifiConfiguration> enabledNetworks) {
- if (!mWifiManager.isWifiEnabled()) {
- log("reEnableNetworks: enable Wifi");
- mWifiManager.setWifiEnabled(true);
- sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT,
- "interruped while waiting for wifi to be enabled");
- }
-
- for (WifiConfiguration config : enabledNetworks) {
- if (DEBUG) {
- log("recover wifi configuration: " + config.toString());
- }
- config.SSID = "\"" + config.SSID + "\"";
- config.networkId = -1;
- mWifiManager.connectNetwork(config);
- sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT,
- "interruped while connecting to " + config.SSID);
- }
- }
-
/**
* Connect to the provided Wi-Fi network
* @param config is the network configuration
diff --git a/core/tests/coretests/src/com/android/internal/util/HierarchicalStateMachineTest.java b/core/tests/coretests/src/com/android/internal/util/StateMachineTest.java
index b6f8be577e41..ab6b2b6f1fbd 100644
--- a/core/tests/coretests/src/com/android/internal/util/HierarchicalStateMachineTest.java
+++ b/core/tests/coretests/src/com/android/internal/util/StateMachineTest.java
@@ -22,9 +22,9 @@ import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
-import com.android.internal.util.HierarchicalState;
-import com.android.internal.util.HierarchicalStateMachine;
-import com.android.internal.util.HierarchicalStateMachine.ProcessedMessageInfo;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+import com.android.internal.util.StateMachine.ProcessedMessageInfo;
import android.test.suitebuilder.annotation.MediumTest;
import android.test.suitebuilder.annotation.SmallTest;
@@ -33,9 +33,9 @@ import android.util.Log;
import junit.framework.TestCase;
/**
- * Test for HierarchicalStateMachine.
+ * Test for StateMachine.
*/
-public class HierarchicalStateMachineTest extends TestCase {
+public class StateMachineTest extends TestCase {
private static final int TEST_CMD_1 = 1;
private static final int TEST_CMD_2 = 2;
private static final int TEST_CMD_3 = 3;
@@ -45,12 +45,12 @@ public class HierarchicalStateMachineTest extends TestCase {
private static final boolean DBG = true;
private static final boolean WAIT_FOR_DEBUGGER = false;
- private static final String TAG = "HierarchicalStateMachineTest";
+ private static final String TAG = "StateMachineTest";
/**
* Tests that we can quit the state machine.
*/
- class StateMachineQuitTest extends HierarchicalStateMachine {
+ class StateMachineQuitTest extends StateMachine {
private int mQuitCount = 0;
StateMachineQuitTest(String name) {
@@ -65,8 +65,9 @@ public class HierarchicalStateMachineTest extends TestCase {
setInitialState(mS1);
}
- class S1 extends HierarchicalState {
- @Override protected boolean processMessage(Message message) {
+ class S1 extends State {
+ @Override
+ public boolean processMessage(Message message) {
if (isQuit(message)) {
mQuitCount += 1;
if (mQuitCount > 2) {
@@ -129,18 +130,18 @@ public class HierarchicalStateMachineTest extends TestCase {
// The first two message didn't quit and were handled by mS1
pmi = smQuitTest.getProcessedMessageInfo(6);
- assertEquals(HierarchicalStateMachine.HSM_QUIT_CMD, pmi.getWhat());
+ assertEquals(StateMachine.SM_QUIT_CMD, pmi.getWhat());
assertEquals(smQuitTest.mS1, pmi.getState());
assertEquals(smQuitTest.mS1, pmi.getOriginalState());
pmi = smQuitTest.getProcessedMessageInfo(7);
- assertEquals(HierarchicalStateMachine.HSM_QUIT_CMD, pmi.getWhat());
+ assertEquals(StateMachine.SM_QUIT_CMD, pmi.getWhat());
assertEquals(smQuitTest.mS1, pmi.getState());
assertEquals(smQuitTest.mS1, pmi.getOriginalState());
// The last message was never handled so the states are null
pmi = smQuitTest.getProcessedMessageInfo(8);
- assertEquals(HierarchicalStateMachine.HSM_QUIT_CMD, pmi.getWhat());
+ assertEquals(StateMachine.SM_QUIT_CMD, pmi.getWhat());
assertEquals(null, pmi.getState());
assertEquals(null, pmi.getOriginalState());
@@ -150,7 +151,7 @@ public class HierarchicalStateMachineTest extends TestCase {
/**
* Test enter/exit can use transitionTo
*/
- class StateMachineEnterExitTransitionToTest extends HierarchicalStateMachine {
+ class StateMachineEnterExitTransitionToTest extends StateMachine {
StateMachineEnterExitTransitionToTest(String name) {
super(name);
mThisSm = this;
@@ -166,34 +167,38 @@ public class HierarchicalStateMachineTest extends TestCase {
setInitialState(mS1);
}
- class S1 extends HierarchicalState {
- @Override protected void enter() {
+ class S1 extends State {
+ @Override
+ public void enter() {
// Test that message is HSM_INIT_CMD
- assertEquals(HSM_INIT_CMD, getCurrentMessage().what);
+ assertEquals(SM_INIT_CMD, getCurrentMessage().what);
// Test that a transition in enter and the initial state works
mS1EnterCount += 1;
transitionTo(mS2);
Log.d(TAG, "S1.enter");
}
- @Override protected void exit() {
+ @Override
+ public void exit() {
// Test that message is HSM_INIT_CMD
- assertEquals(HSM_INIT_CMD, getCurrentMessage().what);
+ assertEquals(SM_INIT_CMD, getCurrentMessage().what);
mS1ExitCount += 1;
Log.d(TAG, "S1.exit");
}
}
- class S2 extends HierarchicalState {
- @Override protected void enter() {
+ class S2 extends State {
+ @Override
+ public void enter() {
// Test that message is HSM_INIT_CMD
- assertEquals(HSM_INIT_CMD, getCurrentMessage().what);
+ assertEquals(SM_INIT_CMD, getCurrentMessage().what);
mS2EnterCount += 1;
Log.d(TAG, "S2.enter");
}
- @Override protected void exit() {
+ @Override
+ public void exit() {
// Test that message is TEST_CMD_1
assertEquals(TEST_CMD_1, getCurrentMessage().what);
@@ -202,7 +207,8 @@ public class HierarchicalStateMachineTest extends TestCase {
transitionTo(mS4);
Log.d(TAG, "S2.exit");
}
- @Override protected boolean processMessage(Message message) {
+ @Override
+ public boolean processMessage(Message message) {
// Start a transition to S3 but it will be
// changed to a transition to S4 in exit
transitionTo(mS3);
@@ -211,28 +217,32 @@ public class HierarchicalStateMachineTest extends TestCase {
}
}
- class S3 extends HierarchicalState {
- @Override protected void enter() {
+ class S3 extends State {
+ @Override
+ public void enter() {
// Test that we can do halting in an enter/exit
transitionToHaltingState();
mS3EnterCount += 1;
Log.d(TAG, "S3.enter");
}
- @Override protected void exit() {
+ @Override
+ public void exit() {
mS3ExitCount += 1;
Log.d(TAG, "S3.exit");
}
}
- class S4 extends HierarchicalState {
- @Override protected void enter() {
+ class S4 extends State {
+ @Override
+ public void enter() {
// Test that we can do halting in an enter/exit
transitionToHaltingState();
mS4EnterCount += 1;
Log.d(TAG, "S4.enter");
}
- @Override protected void exit() {
+ @Override
+ public void exit() {
mS4ExitCount += 1;
Log.d(TAG, "S4.exit");
}
@@ -310,7 +320,7 @@ public class HierarchicalStateMachineTest extends TestCase {
/**
* Tests that ProcessedMessage works as a circular buffer.
*/
- class StateMachine0 extends HierarchicalStateMachine {
+ class StateMachine0 extends StateMachine {
StateMachine0(String name) {
super(name);
mThisSm = this;
@@ -324,8 +334,9 @@ public class HierarchicalStateMachineTest extends TestCase {
setInitialState(mS1);
}
- class S1 extends HierarchicalState {
- @Override protected boolean processMessage(Message message) {
+ class S1 extends State {
+ @Override
+ public boolean processMessage(Message message) {
if (message.what == TEST_CMD_6) {
transitionToHaltingState();
}
@@ -394,7 +405,7 @@ public class HierarchicalStateMachineTest extends TestCase {
* in state mS1. With the first message it transitions to
* itself which causes it to be exited and reentered.
*/
- class StateMachine1 extends HierarchicalStateMachine {
+ class StateMachine1 extends StateMachine {
StateMachine1(String name) {
super(name);
mThisSm = this;
@@ -408,12 +419,17 @@ public class HierarchicalStateMachineTest extends TestCase {
if (DBG) Log.d(TAG, "StateMachine1: ctor X");
}
- class S1 extends HierarchicalState {
- @Override protected void enter() {
+ class S1 extends State {
+ @Override
+ public void enter() {
mEnterCount++;
}
-
- @Override protected boolean processMessage(Message message) {
+ @Override
+ public void exit() {
+ mExitCount++;
+ }
+ @Override
+ public boolean processMessage(Message message) {
if (message.what == TEST_CMD_1) {
assertEquals(1, mEnterCount);
assertEquals(0, mExitCount);
@@ -425,10 +441,6 @@ public class HierarchicalStateMachineTest extends TestCase {
}
return HANDLED;
}
-
- @Override protected void exit() {
- mExitCount++;
- }
}
@Override
@@ -493,7 +505,7 @@ public class HierarchicalStateMachineTest extends TestCase {
* mS2 then receives both of the deferred messages first TEST_CMD_1 and
* then TEST_CMD_2.
*/
- class StateMachine2 extends HierarchicalStateMachine {
+ class StateMachine2 extends StateMachine {
StateMachine2(String name) {
super(name);
mThisSm = this;
@@ -508,26 +520,28 @@ public class HierarchicalStateMachineTest extends TestCase {
if (DBG) Log.d(TAG, "StateMachine2: ctor X");
}
- class S1 extends HierarchicalState {
- @Override protected void enter() {
+ class S1 extends State {
+ @Override
+ public void enter() {
mDidEnter = true;
}
-
- @Override protected boolean processMessage(Message message) {
+ @Override
+ public void exit() {
+ mDidExit = true;
+ }
+ @Override
+ public boolean processMessage(Message message) {
deferMessage(message);
if (message.what == TEST_CMD_2) {
transitionTo(mS2);
}
return HANDLED;
}
-
- @Override protected void exit() {
- mDidExit = true;
- }
}
- class S2 extends HierarchicalState {
- @Override protected boolean processMessage(Message message) {
+ class S2 extends State {
+ @Override
+ public boolean processMessage(Message message) {
if (message.what == TEST_CMD_2) {
transitionToHaltingState();
}
@@ -598,7 +612,7 @@ public class HierarchicalStateMachineTest extends TestCase {
* Test that unhandled messages in a child are handled by the parent.
* When TEST_CMD_2 is received.
*/
- class StateMachine3 extends HierarchicalStateMachine {
+ class StateMachine3 extends StateMachine {
StateMachine3(String name) {
super(name);
mThisSm = this;
@@ -615,8 +629,9 @@ public class HierarchicalStateMachineTest extends TestCase {
if (DBG) Log.d(TAG, "StateMachine3: ctor X");
}
- class ParentState extends HierarchicalState {
- @Override protected boolean processMessage(Message message) {
+ class ParentState extends State {
+ @Override
+ public boolean processMessage(Message message) {
if (message.what == TEST_CMD_2) {
transitionToHaltingState();
}
@@ -624,8 +639,9 @@ public class HierarchicalStateMachineTest extends TestCase {
}
}
- class ChildState extends HierarchicalState {
- @Override protected boolean processMessage(Message message) {
+ class ChildState extends State {
+ @Override
+ public boolean processMessage(Message message) {
return NOT_HANDLED;
}
}
@@ -682,7 +698,7 @@ public class HierarchicalStateMachineTest extends TestCase {
* with transition from child 1 to child 2 and child 2
* lets the parent handle the messages.
*/
- class StateMachine4 extends HierarchicalStateMachine {
+ class StateMachine4 extends StateMachine {
StateMachine4(String name) {
super(name);
mThisSm = this;
@@ -700,8 +716,9 @@ public class HierarchicalStateMachineTest extends TestCase {
if (DBG) Log.d(TAG, "StateMachine4: ctor X");
}
- class ParentState extends HierarchicalState {
- @Override protected boolean processMessage(Message message) {
+ class ParentState extends State {
+ @Override
+ public boolean processMessage(Message message) {
if (message.what == TEST_CMD_2) {
transitionToHaltingState();
}
@@ -709,15 +726,17 @@ public class HierarchicalStateMachineTest extends TestCase {
}
}
- class ChildState1 extends HierarchicalState {
- @Override protected boolean processMessage(Message message) {
+ class ChildState1 extends State {
+ @Override
+ public boolean processMessage(Message message) {
transitionTo(mChildState2);
return HANDLED;
}
}
- class ChildState2 extends HierarchicalState {
- @Override protected boolean processMessage(Message message) {
+ class ChildState2 extends State {
+ @Override
+ public boolean processMessage(Message message) {
return NOT_HANDLED;
}
}
@@ -775,7 +794,7 @@ public class HierarchicalStateMachineTest extends TestCase {
* Test transition from one child to another of a "complex"
* hierarchy with two parents and multiple children.
*/
- class StateMachine5 extends HierarchicalStateMachine {
+ class StateMachine5 extends StateMachine {
StateMachine5(String name) {
super(name);
mThisSm = this;
@@ -797,23 +816,32 @@ public class HierarchicalStateMachineTest extends TestCase {
if (DBG) Log.d(TAG, "StateMachine5: ctor X");
}
- class ParentState1 extends HierarchicalState {
- @Override protected void enter() {
+ class ParentState1 extends State {
+ @Override
+ public void enter() {
mParentState1EnterCount += 1;
}
- @Override protected boolean processMessage(Message message) {
- return HANDLED;
- }
- @Override protected void exit() {
+ @Override
+ public void exit() {
mParentState1ExitCount += 1;
}
+ @Override
+ public boolean processMessage(Message message) {
+ return HANDLED;
+ }
}
- class ChildState1 extends HierarchicalState {
- @Override protected void enter() {
+ class ChildState1 extends State {
+ @Override
+ public void enter() {
mChildState1EnterCount += 1;
}
- @Override protected boolean processMessage(Message message) {
+ @Override
+ public void exit() {
+ mChildState1ExitCount += 1;
+ }
+ @Override
+ public boolean processMessage(Message message) {
assertEquals(1, mParentState1EnterCount);
assertEquals(0, mParentState1ExitCount);
assertEquals(1, mChildState1EnterCount);
@@ -832,16 +860,19 @@ public class HierarchicalStateMachineTest extends TestCase {
transitionTo(mChildState2);
return HANDLED;
}
- @Override protected void exit() {
- mChildState1ExitCount += 1;
- }
}
- class ChildState2 extends HierarchicalState {
- @Override protected void enter() {
+ class ChildState2 extends State {
+ @Override
+ public void enter() {
mChildState2EnterCount += 1;
}
- @Override protected boolean processMessage(Message message) {
+ @Override
+ public void exit() {
+ mChildState2ExitCount += 1;
+ }
+ @Override
+ public boolean processMessage(Message message) {
assertEquals(1, mParentState1EnterCount);
assertEquals(0, mParentState1ExitCount);
assertEquals(1, mChildState1EnterCount);
@@ -860,16 +891,19 @@ public class HierarchicalStateMachineTest extends TestCase {
transitionTo(mChildState5);
return HANDLED;
}
- @Override protected void exit() {
- mChildState2ExitCount += 1;
- }
}
- class ParentState2 extends HierarchicalState {
- @Override protected void enter() {
+ class ParentState2 extends State {
+ @Override
+ public void enter() {
mParentState2EnterCount += 1;
}
- @Override protected boolean processMessage(Message message) {
+ @Override
+ public void exit() {
+ mParentState2ExitCount += 1;
+ }
+ @Override
+ public boolean processMessage(Message message) {
assertEquals(1, mParentState1EnterCount);
assertEquals(1, mParentState1ExitCount);
assertEquals(1, mChildState1EnterCount);
@@ -888,16 +922,19 @@ public class HierarchicalStateMachineTest extends TestCase {
transitionToHaltingState();
return HANDLED;
}
- @Override protected void exit() {
- mParentState2ExitCount += 1;
- }
}
- class ChildState3 extends HierarchicalState {
- @Override protected void enter() {
+ class ChildState3 extends State {
+ @Override
+ public void enter() {
mChildState3EnterCount += 1;
}
- @Override protected boolean processMessage(Message message) {
+ @Override
+ public void exit() {
+ mChildState3ExitCount += 1;
+ }
+ @Override
+ public boolean processMessage(Message message) {
assertEquals(1, mParentState1EnterCount);
assertEquals(1, mParentState1ExitCount);
assertEquals(1, mChildState1EnterCount);
@@ -916,16 +953,19 @@ public class HierarchicalStateMachineTest extends TestCase {
transitionTo(mChildState4);
return HANDLED;
}
- @Override protected void exit() {
- mChildState3ExitCount += 1;
- }
}
- class ChildState4 extends HierarchicalState {
- @Override protected void enter() {
+ class ChildState4 extends State {
+ @Override
+ public void enter() {
mChildState4EnterCount += 1;
}
- @Override protected boolean processMessage(Message message) {
+ @Override
+ public void exit() {
+ mChildState4ExitCount += 1;
+ }
+ @Override
+ public boolean processMessage(Message message) {
assertEquals(1, mParentState1EnterCount);
assertEquals(1, mParentState1ExitCount);
assertEquals(1, mChildState1EnterCount);
@@ -944,16 +984,19 @@ public class HierarchicalStateMachineTest extends TestCase {
transitionTo(mParentState2);
return HANDLED;
}
- @Override protected void exit() {
- mChildState4ExitCount += 1;
- }
}
- class ChildState5 extends HierarchicalState {
- @Override protected void enter() {
+ class ChildState5 extends State {
+ @Override
+ public void enter() {
mChildState5EnterCount += 1;
}
- @Override protected boolean processMessage(Message message) {
+ @Override
+ public void exit() {
+ mChildState5ExitCount += 1;
+ }
+ @Override
+ public boolean processMessage(Message message) {
assertEquals(1, mParentState1EnterCount);
assertEquals(1, mParentState1ExitCount);
assertEquals(1, mChildState1EnterCount);
@@ -972,9 +1015,6 @@ public class HierarchicalStateMachineTest extends TestCase {
transitionTo(mChildState3);
return HANDLED;
}
- @Override protected void exit() {
- mChildState5ExitCount += 1;
- }
}
@Override
@@ -1089,7 +1129,7 @@ public class HierarchicalStateMachineTest extends TestCase {
* after construction and before any other messages arrive and that
* sendMessageDelayed works.
*/
- class StateMachine6 extends HierarchicalStateMachine {
+ class StateMachine6 extends StateMachine {
StateMachine6(String name) {
super(name);
mThisSm = this;
@@ -1103,13 +1143,13 @@ public class HierarchicalStateMachineTest extends TestCase {
if (DBG) Log.d(TAG, "StateMachine6: ctor X");
}
- class S1 extends HierarchicalState {
-
- @Override protected void enter() {
+ class S1 extends State {
+ @Override
+ public void enter() {
sendMessage(TEST_CMD_1);
}
-
- @Override protected boolean processMessage(Message message) {
+ @Override
+ public boolean processMessage(Message message) {
if (message.what == TEST_CMD_1) {
mArrivalTimeMsg1 = SystemClock.elapsedRealtime();
} else if (message.what == TEST_CMD_2) {
@@ -1118,9 +1158,6 @@ public class HierarchicalStateMachineTest extends TestCase {
}
return HANDLED;
}
-
- @Override protected void exit() {
- }
}
@Override
@@ -1178,7 +1215,7 @@ public class HierarchicalStateMachineTest extends TestCase {
* Test that enter is invoked immediately after exit. This validates
* that enter can be used to send a watch dog message for its state.
*/
- class StateMachine7 extends HierarchicalStateMachine {
+ class StateMachine7 extends StateMachine {
private final int SM7_DELAY_TIME = 250;
StateMachine7(String name) {
@@ -1195,24 +1232,26 @@ public class HierarchicalStateMachineTest extends TestCase {
if (DBG) Log.d(TAG, "StateMachine7: ctor X");
}
- class S1 extends HierarchicalState {
- @Override protected boolean processMessage(Message message) {
+ class S1 extends State {
+ @Override
+ public void exit() {
+ sendMessage(TEST_CMD_2);
+ }
+ @Override
+ public boolean processMessage(Message message) {
transitionTo(mS2);
return HANDLED;
}
- @Override protected void exit() {
- sendMessage(TEST_CMD_2);
- }
}
- class S2 extends HierarchicalState {
-
- @Override protected void enter() {
+ class S2 extends State {
+ @Override
+ public void enter() {
// Send a delayed message as a watch dog
sendMessageDelayed(TEST_CMD_3, SM7_DELAY_TIME);
}
-
- @Override protected boolean processMessage(Message message) {
+ @Override
+ public boolean processMessage(Message message) {
if (message.what == TEST_CMD_2) {
mMsgCount += 1;
mArrivalTimeMsg2 = SystemClock.elapsedRealtime();
@@ -1226,9 +1265,6 @@ public class HierarchicalStateMachineTest extends TestCase {
}
return HANDLED;
}
-
- @Override protected void exit() {
- }
}
@Override
@@ -1286,7 +1322,7 @@ public class HierarchicalStateMachineTest extends TestCase {
/**
* Test unhandledMessage.
*/
- class StateMachineUnhandledMessage extends HierarchicalStateMachine {
+ class StateMachineUnhandledMessage extends StateMachine {
StateMachineUnhandledMessage(String name) {
super(name);
mThisSm = this;
@@ -1298,13 +1334,14 @@ public class HierarchicalStateMachineTest extends TestCase {
// Set the initial state
setInitialState(mS1);
}
-
- @Override protected void unhandledMessage(Message message) {
+ @Override
+ public void unhandledMessage(Message message) {
mUnhandledMessageCount += 1;
}
- class S1 extends HierarchicalState {
- @Override protected boolean processMessage(Message message) {
+ class S1 extends State {
+ @Override
+ public boolean processMessage(Message message) {
if (message.what == TEST_CMD_2) {
transitionToHaltingState();
}
@@ -1359,7 +1396,7 @@ public class HierarchicalStateMachineTest extends TestCase {
* will be used to notify testStateMachineSharedThread that the test is
* complete.
*/
- class StateMachineSharedThread extends HierarchicalStateMachine {
+ class StateMachineSharedThread extends StateMachine {
StateMachineSharedThread(String name, Looper looper, int maxCount) {
super(name, looper);
mMaxCount = maxCount;
@@ -1372,8 +1409,9 @@ public class HierarchicalStateMachineTest extends TestCase {
setInitialState(mS1);
}
- class S1 extends HierarchicalState {
- @Override protected boolean processMessage(Message message) {
+ class S1 extends State {
+ @Override
+ public boolean processMessage(Message message) {
if (message.what == TEST_CMD_4) {
transitionToHaltingState();
}
@@ -1503,7 +1541,7 @@ public class HierarchicalStateMachineTest extends TestCase {
}
}
-class Hsm1 extends HierarchicalStateMachine {
+class Hsm1 extends StateMachine {
private static final String TAG = "hsm1";
public static final int CMD_1 = 1;
@@ -1535,11 +1573,17 @@ class Hsm1 extends HierarchicalStateMachine {
Log.d(TAG, "ctor X");
}
- class P1 extends HierarchicalState {
- @Override protected void enter() {
+ class P1 extends State {
+ @Override
+ public void enter() {
Log.d(TAG, "P1.enter");
}
- @Override protected boolean processMessage(Message message) {
+ @Override
+ public void exit() {
+ Log.d(TAG, "P1.exit");
+ }
+ @Override
+ public boolean processMessage(Message message) {
boolean retVal;
Log.d(TAG, "P1.processMessage what=" + message.what);
switch(message.what) {
@@ -1557,16 +1601,19 @@ class Hsm1 extends HierarchicalStateMachine {
}
return retVal;
}
- @Override protected void exit() {
- Log.d(TAG, "P1.exit");
- }
}
- class S1 extends HierarchicalState {
- @Override protected void enter() {
+ class S1 extends State {
+ @Override
+ public void enter() {
Log.d(TAG, "S1.enter");
}
- @Override protected boolean processMessage(Message message) {
+ @Override
+ public void exit() {
+ Log.d(TAG, "S1.exit");
+ }
+ @Override
+ public boolean processMessage(Message message) {
Log.d(TAG, "S1.processMessage what=" + message.what);
if (message.what == CMD_1) {
// Transition to ourself to show that enter/exit is called
@@ -1577,16 +1624,19 @@ class Hsm1 extends HierarchicalStateMachine {
return NOT_HANDLED;
}
}
- @Override protected void exit() {
- Log.d(TAG, "S1.exit");
- }
}
- class S2 extends HierarchicalState {
- @Override protected void enter() {
+ class S2 extends State {
+ @Override
+ public void enter() {
Log.d(TAG, "S2.enter");
}
- @Override protected boolean processMessage(Message message) {
+ @Override
+ public void exit() {
+ Log.d(TAG, "S2.exit");
+ }
+ @Override
+ public boolean processMessage(Message message) {
boolean retVal;
Log.d(TAG, "S2.processMessage what=" + message.what);
switch(message.what) {
@@ -1605,17 +1655,20 @@ class Hsm1 extends HierarchicalStateMachine {
}
return retVal;
}
- @Override protected void exit() {
- Log.d(TAG, "S2.exit");
- }
}
- class P2 extends HierarchicalState {
- @Override protected void enter() {
+ class P2 extends State {
+ @Override
+ public void enter() {
Log.d(TAG, "P2.enter");
sendMessage(CMD_5);
}
- @Override protected boolean processMessage(Message message) {
+ @Override
+ public void exit() {
+ Log.d(TAG, "P2.exit");
+ }
+ @Override
+ public boolean processMessage(Message message) {
Log.d(TAG, "P2.processMessage what=" + message.what);
switch(message.what) {
case(CMD_3):
@@ -1628,9 +1681,6 @@ class Hsm1 extends HierarchicalStateMachine {
}
return HANDLED;
}
- @Override protected void exit() {
- Log.d(TAG, "P2.exit");
- }
}
@Override
diff --git a/core/tests/overlaytests/Android.mk b/core/tests/overlaytests/Android.mk
new file mode 100644
index 000000000000..bf694426cbce
--- /dev/null
+++ b/core/tests/overlaytests/Android.mk
@@ -0,0 +1,4 @@
+# Dummy makefile to halt recursive directory traversal.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
diff --git a/core/tests/overlaytests/OverlayTest/Android.mk b/core/tests/overlaytests/OverlayTest/Android.mk
new file mode 100644
index 000000000000..f7f67f67624f
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTest/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_PACKAGE_NAME := OverlayTest
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/OverlayTest/AndroidManifest.xml b/core/tests/overlaytests/OverlayTest/AndroidManifest.xml
new file mode 100644
index 000000000000..9edba12ffa8f
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTest/AndroidManifest.xml
@@ -0,0 +1,10 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.overlaytest">
+ <uses-permission android:name="android.permission.RUN_INSTRUMENTATION"/>
+ <application>
+ <uses-library android:name="android.test.runner"/>
+ </application>
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.overlaytest"
+ android:label="Runtime resource overlay tests"/>
+</manifest>
diff --git a/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java
new file mode 100644
index 000000000000..85b49ce5c9b8
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java
@@ -0,0 +1,118 @@
+package com.android.overlaytest;
+
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.test.AndroidTestCase;
+import java.io.InputStream;
+import java.util.Locale;
+
+public abstract class OverlayBaseTest extends AndroidTestCase {
+ private Resources mResources;
+ protected boolean mWithOverlay; // will be set by subclasses
+
+ protected void setUp() {
+ mResources = getContext().getResources();
+ }
+
+ private int calculateRawResourceChecksum(int resId) throws Throwable {
+ InputStream input = null;
+ try {
+ input = mResources.openRawResource(resId);
+ int ch, checksum = 0;
+ while ((ch = input.read()) != -1) {
+ checksum = (checksum + ch) % 0xffddbb00;
+ }
+ return checksum;
+ } finally {
+ input.close();
+ }
+ }
+
+ private void setLocale(String code) {
+ Locale locale = new Locale(code);
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ mResources.updateConfiguration(config, mResources.getDisplayMetrics());
+ }
+
+ private void assertResource(int resId, boolean ewo, boolean ew) throws Throwable {
+ boolean expected = mWithOverlay ? ew : ewo;
+ boolean actual = mResources.getBoolean(resId);
+ assertEquals(expected, actual);
+ }
+
+ private void assertResource(int resId, String ewo, String ew) throws Throwable {
+ String expected = mWithOverlay ? ew : ewo;
+ String actual = mResources.getString(resId);
+ assertEquals(expected, actual);
+ }
+
+ private void assertResource(int resId, int[] ewo, int[] ew) throws Throwable {
+ int[] expected = mWithOverlay ? ew : ewo;
+ int[] actual = mResources.getIntArray(resId);
+ assertEquals("length:", expected.length, actual.length);
+ for (int i = 0; i < actual.length; ++i) {
+ assertEquals("index " + i + ":", actual[i], expected[i]);
+ }
+ }
+
+ public void testBooleanOverlay() throws Throwable {
+ // config_automatic_brightness_available has overlay (default config)
+ final int resId = com.android.internal.R.bool.config_automatic_brightness_available;
+ assertResource(resId, false, true);
+ }
+
+ public void testBoolean() throws Throwable {
+ // config_bypass_keyguard_if_slider_open has no overlay
+ final int resId = com.android.internal.R.bool.config_bypass_keyguard_if_slider_open;
+ assertResource(resId, true, true);
+ }
+
+ public void testStringOverlay() throws Throwable {
+ // phoneTypeCar has an overlay (default config), which shouldn't shadow
+ // the Swedish translation
+ final int resId = com.android.internal.R.string.phoneTypeCar;
+ setLocale("sv_SE");
+ assertResource(resId, "Bil", "Bil");
+ }
+
+ public void testStringSwedishOverlay() throws Throwable {
+ // phoneTypeWork has overlay (no default config, only for lang=sv)
+ final int resId = com.android.internal.R.string.phoneTypeWork;
+ setLocale("en_US");
+ assertResource(resId, "Work", "Work");
+ setLocale("sv_SE");
+ assertResource(resId, "Arbete", "Jobb");
+ }
+
+ public void testString() throws Throwable {
+ // phoneTypeHome has no overlay
+ final int resId = com.android.internal.R.string.phoneTypeHome;
+ setLocale("en_US");
+ assertResource(resId, "Home", "Home");
+ setLocale("sv_SE");
+ assertResource(resId, "Hem", "Hem");
+ }
+
+ public void testIntegerArrayOverlay() throws Throwable {
+ // config_scrollBarrierVibePattern has overlay (default config)
+ final int resId = com.android.internal.R.array.config_scrollBarrierVibePattern;
+ assertResource(resId, new int[]{0, 15, 10, 10}, new int[]{100, 200, 300});
+ }
+
+ public void testIntegerArray() throws Throwable {
+ // config_virtualKeyVibePattern has no overlay
+ final int resId = com.android.internal.R.array.config_virtualKeyVibePattern;
+ final int[] expected = {0, 10, 20, 30};
+ assertResource(resId, expected, expected);
+ }
+
+ public void testAsset() throws Throwable {
+ // drawable/default_background.jpg has overlay (default config)
+ final int resId = com.android.internal.R.drawable.default_wallpaper;
+ int actual = calculateRawResourceChecksum(resId);
+ int expected = mWithOverlay ? 0x000051da : 0x0014ebce;
+ assertEquals(expected, actual);
+ }
+}
diff --git a/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithOverlayTest.java b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithOverlayTest.java
new file mode 100644
index 000000000000..1292d03394ac
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithOverlayTest.java
@@ -0,0 +1,7 @@
+package com.android.overlaytest;
+
+public class WithOverlayTest extends OverlayBaseTest {
+ public WithOverlayTest() {
+ mWithOverlay = true;
+ }
+}
diff --git a/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithoutOverlayTest.java b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithoutOverlayTest.java
new file mode 100644
index 000000000000..630ff8fa83bb
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithoutOverlayTest.java
@@ -0,0 +1,7 @@
+package com.android.overlaytest;
+
+public class WithoutOverlayTest extends OverlayBaseTest {
+ public WithoutOverlayTest() {
+ mWithOverlay = false;
+ }
+}
diff --git a/core/tests/overlaytests/OverlayTestOverlay/Android.mk b/core/tests/overlaytests/OverlayTestOverlay/Android.mk
new file mode 100644
index 000000000000..cf32c9f93c68
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTestOverlay/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := com.android.overlaytest.overlay
+
+LOCAL_AAPT_FLAGS := -o
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/OverlayTestOverlay/AndroidManifest.xml b/core/tests/overlaytests/OverlayTestOverlay/AndroidManifest.xml
new file mode 100644
index 000000000000..bcbb0d15fe10
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTestOverlay/AndroidManifest.xml
@@ -0,0 +1,6 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.overlaytest.overlay"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <overlay-package android:name="android"/>
+</manifest>
diff --git a/core/tests/overlaytests/OverlayTestOverlay/res/drawable/default_wallpaper.jpg b/core/tests/overlaytests/OverlayTestOverlay/res/drawable/default_wallpaper.jpg
new file mode 100644
index 000000000000..0d944d02d633
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTestOverlay/res/drawable/default_wallpaper.jpg
Binary files differ
diff --git a/core/tests/overlaytests/OverlayTestOverlay/res/values-sv/config.xml b/core/tests/overlaytests/OverlayTestOverlay/res/values-sv/config.xml
new file mode 100644
index 000000000000..bc5236738bf7
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTestOverlay/res/values-sv/config.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="phoneTypeWork">Jobb</string>
+</resources>
diff --git a/core/tests/overlaytests/OverlayTestOverlay/res/values/config.xml b/core/tests/overlaytests/OverlayTestOverlay/res/values/config.xml
new file mode 100644
index 000000000000..794f475a7926
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTestOverlay/res/values/config.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <bool name="config_automatic_brightness_available">true</bool>
+ <string name="phoneTypeCar">Automobile</string>
+ <integer-array name="config_scrollBarrierVibePattern">
+ <item>100</item>
+ <item>200</item>
+ <item>300</item>
+ </integer-array>
+ <!-- The following integer does not exist in the original package. Idmap
+ generation should therefore ignore it. -->
+ <integer name="integer_not_in_original_package">0</integer>
+</resources>
diff --git a/core/tests/overlaytests/README b/core/tests/overlaytests/README
new file mode 100644
index 000000000000..4b3e6f235657
--- /dev/null
+++ b/core/tests/overlaytests/README
@@ -0,0 +1,15 @@
+Unit tests for runtime resource overlay
+=======================================
+
+As of this writing, runtime resource overlay is only triggered for
+/system/framework/framework-res.apk. Because of this, installation of
+overlay packages require the Android platform be rebooted. However, the
+regular unit tests (triggered via development/testrunner/runtest.py)
+cannot handle reboots. As a workaround, this directory contains a shell
+script which will trigger the tests in a non-standard way.
+
+Once runtime resource overlay may be applied to applications, the tests
+in this directory should be moved to core/tests/coretests. Also, by
+applying runtime resource overlay to a dedicated test application, the
+test cases would not need to assume default values for non-overlaid
+resources.
diff --git a/core/tests/overlaytests/runtests.sh b/core/tests/overlaytests/runtests.sh
new file mode 100755
index 000000000000..0ad9efb0938e
--- /dev/null
+++ b/core/tests/overlaytests/runtests.sh
@@ -0,0 +1,89 @@
+#!/bin/bash
+
+adb="adb"
+if [[ $# -gt 0 ]]; then
+ adb="adb $*" # for setting -e, -d or -s <serial>
+fi
+
+function atexit()
+{
+ local retval=$?
+
+ if [[ $retval -eq 0 ]]; then
+ rm $log
+ else
+ echo "There were errors, please check log at $log"
+ fi
+}
+
+log=$(mktemp)
+trap "atexit" EXIT
+failures=0
+
+function compile_module()
+{
+ local android_mk="$1"
+
+ echo "Compiling .${android_mk:${#PWD}}"
+ ONE_SHOT_MAKEFILE="$android_mk" make -C "../../../../../" files | tee -a $log
+ if [[ ${PIPESTATUS[0]} -ne 0 ]]; then
+ exit 1
+ fi
+}
+
+function wait_for_boot_completed()
+{
+ echo "Rebooting device"
+ $adb wait-for-device logcat -c
+ $adb wait-for-device logcat | grep -m 1 -e 'PowerManagerService.*bootCompleted' >/dev/null
+}
+
+function disable_overlay()
+{
+ echo "Disabling overlay"
+ $adb shell rm /vendor/overlay/framework/framework-res.apk
+ $adb shell rm /data/resource-cache/vendor@overlay@framework@framework-res.apk@idmap
+}
+
+function enable_overlay()
+{
+ echo "Enabling overlay"
+ $adb shell ln -s /data/app/com.android.overlaytest.overlay.apk /vendor/overlay/framework/framework-res.apk
+}
+
+function instrument()
+{
+ local class="$1"
+
+ echo "Instrumenting $class"
+ $adb shell am instrument -w -e class $class com.android.overlaytest/android.test.InstrumentationTestRunner | tee -a $log
+}
+
+function sync()
+{
+ echo "Syncing to device"
+ $adb remount | tee -a $log
+ $adb sync data | tee -a $log
+}
+
+# build and sync
+compile_module "$PWD/OverlayTest/Android.mk"
+compile_module "$PWD/OverlayTestOverlay/Android.mk"
+sync
+
+# instrument test (without overlay)
+$adb shell stop
+disable_overlay
+$adb shell start
+wait_for_boot_completed
+instrument "com.android.overlaytest.WithoutOverlayTest"
+
+# instrument test (with overlay)
+$adb shell stop
+enable_overlay
+$adb shell start
+wait_for_boot_completed
+instrument "com.android.overlaytest.WithOverlayTest"
+
+# cleanup
+exit $(grep -c -e '^FAILURES' $log)
diff --git a/docs/html/guide/developing/tools/logcat.jd b/docs/html/guide/developing/tools/logcat.jd
index d4ee68af76c2..546e3eacd2ae 100644
--- a/docs/html/guide/developing/tools/logcat.jd
+++ b/docs/html/guide/developing/tools/logcat.jd
@@ -2,7 +2,6 @@ page.title=logcat
parent.title=Tools
parent.link=index.html
@jd:body
-<div></div>
<p>The Android logging system provides a mechanism for collecting and viewing system debug
output. Logs from various applications and portions of the system are collected in a series of
@@ -23,7 +22,7 @@ For more
<p>You can run <code>logcat</code> as an adb command or directly in a shell prompt
of your emulator or connected device. To view log output using adb, navigate to your SDK
- <code>platform-tools/</code> directory and execute:/p>
+ <code>platform-tools/</code> directory and execute:</p>
<pre>
$ adb logcat
</pre>
diff --git a/docs/html/guide/market/billing/billing_admin.jd b/docs/html/guide/market/billing/billing_admin.jd
index 723113dc80e4..939bbaa03e68 100755
--- a/docs/html/guide/market/billing/billing_admin.jd
+++ b/docs/html/guide/market/billing/billing_admin.jd
@@ -97,7 +97,7 @@ file</a>.</p>
<img src="{@docRoot}images/billing_list_form.png" height="840" id="figure3" />
<p class="img-caption">
- f<strong>Figure 3.</strong> The Create New In-app Product page lets you add items to an
+ <strong>Figure 3.</strong> The Create New In-app Product page lets you add items to an
application's product list.
</p>
diff --git a/docs/html/guide/market/billing/billing_integrate.jd b/docs/html/guide/market/billing/billing_integrate.jd
index f57ebe374dd4..59344bae7770 100755
--- a/docs/html/guide/market/billing/billing_integrate.jd
+++ b/docs/html/guide/market/billing/billing_integrate.jd
@@ -163,11 +163,11 @@ Selected</strong> to begin the download.</p>
<p>When the download is complete, the Android SDK and AVD Manager saves the component into the
following directory:</p>
-<p><code>&lt;sdk&gt;/google-market_billing/</code></p>
+<p><code>&lt;sdk&gt;/extras/google/market_billing/</code></p>
<p>If you want to see an end-to-end demonstration of in-app billing before you integrate in-app
billing into your own application, you can build and run the sample application. Building and
-running the sample application involves three tasks:<p>
+running the sample application involves three tasks:</p>
<ul>
<li>Configuring and building the sample application.</li>
@@ -501,7 +501,7 @@ protected Bundle makeRequestBundle(String method) {
<p>To use this helper method, you pass in a <code>String</code> that corresponds to one of the five
types of billing requests. The method returns a Bundle that has the three required keys defined. The
-following sections show you how to use this helper method when you send a billing request.<p>
+following sections show you how to use this helper method when you send a billing request.</p>
<p class="caution"><strong>Important</strong>: You must make all in-app billing requests from your
application's main thread.</p>
diff --git a/docs/html/guide/practices/design/accessibility.jd b/docs/html/guide/practices/design/accessibility.jd
index a2b314e39d90..a66a974a32d0 100644
--- a/docs/html/guide/practices/design/accessibility.jd
+++ b/docs/html/guide/practices/design/accessibility.jd
@@ -60,8 +60,9 @@ access-related problems:</p>
<li>Make all of your user interface controls accessible with a trackball or directional
controller (d-pad).</li>
<li>Label your {@link android.widget.ImageButton}, {@link android.widget.EditText}, and other input
-widgets using the <a href="{@docRoot}reference/android/view/View#attr_android:contentDescription"
->{@code android:contentDescription}</a> attribute.</li>
+widgets using the <a
+href="{@docRoot}reference/android/view/View.html#attr_android:contentDescription">{@code
+android:contentDescription}</a> attribute.</li>
</ul>
@@ -100,8 +101,9 @@ request that a widget be given focus. Such methods include:</p>
</ul>
<p>When working with a view that is not focusable by default, you can make it focusable from the XML
-layout file by setting the <a href="{@docRoot}reference/android/view/View#attr_android:focusable"
->{@code android:focusable}</a> attribute to {@code "true"}.</p>
+layout file by setting the <a
+href="{@docRoot}reference/android/view/View.html#attr_android:focusable">{@code
+android:focusable}</a> attribute to {@code "true"}.</p>
@@ -181,13 +183,13 @@ a label near it that indicates its purpose. When a visually impaired user acces
application, these visual cues are often useless.</p>
<p>To provide textual information about these widgets (as an alternative to the visual cues), you
-should use the <a href="{@docRoot}reference/android/view/View#attr_android:contentDescription"
+should use the <a href="{@docRoot}reference/android/view/View.html#attr_android:contentDescription"
>{@code android:contentDescription}</a> attribute. The text you provide in this attribute
is not visible on the screen, but if a user has enabled accessibility speech tools then the
description in this attribute is read aloud to the user.</p>
<p>You should set the <a
-href="{@docRoot}reference/android/view/View#attr_android:contentDescription" >{@code
+href="{@docRoot}reference/android/view/View.html#attr_android:contentDescription" >{@code
android:contentDescription}</a> attribute on every {@link android.widget.ImageButton}, {@link
android.widget.EditText}, {@link android.widget.CheckBox}, and on any other input widgets that might
benefit users with extra information.</p>
diff --git a/docs/html/guide/practices/design/jni.jd b/docs/html/guide/practices/design/jni.jd
new file mode 100644
index 000000000000..3e9ddc4ba1d1
--- /dev/null
+++ b/docs/html/guide/practices/design/jni.jd
@@ -0,0 +1,715 @@
+page.title=JNI Tips
+@jd:body
+
+<div id="qv-wrapper">
+<div id="qv">
+
+<h2>In this document</h2>
+<ol>
+ <li><a href="#what">What is JNI?</a></li>
+ <li><a href="#JavaVM_and_JNIEnv">JavaVM and JNIEnv</a></li>
+ <li><a href="#threads">Threads</a></li>
+ <li><a href="#jclass_jmethodID_and_jfieldID">jclass, jmethodID, and jfieldID</a></li>
+ <li><a href="#local_and_global_references">Local and Global References</a></li>
+ <li><a href="#UTF_8_and_UTF_16_strings">UTF-8 and UTF-16 Strings</a></li>
+ <li><a href="#arrays">Primitive Arrays</a></li>
+ <li><a href="#region_calls">Region Calls</a></li>
+ <li><a href="#exceptions">Exceptions</a></li>
+ <li><a href="#extended_checking">Extended Checking</a> </li>
+ <li><a href="#native_libraries">Native Libraries</a></li>
+ <li><a href="#64_bit">64-bit Considerations</a></li>
+ <li><a href="#unsupported">Unsupported Features</a></li>
+ <li><a href="#faq_ULE">FAQ: UnsatisfiedLinkError</a></li>
+ <li><a href="#faq_FindClass">FAQ: FindClass didn't find my class</a></li>
+ <li><a href="#faq_sharing">FAQ: Sharing raw data with native code</a></li>
+</ol>
+
+</div>
+</div>
+
+<a name="what_is_jni" id="what_is_jni"></a>
+<h2>What is JNI?</h2>
+
+<p>JNI is the Java Native Interface. It defines a way for code written in the
+Java programming language to interact with native
+code, e.g. functions written in C/C++. It's VM-neutral, has support for loading code from
+dynamic shared libraries, and while cumbersome at times is reasonably efficient.</p>
+
+<p>You really should read through the
+<a href="http://java.sun.com/javase/6/docs/technotes/guides/jni/spec/jniTOC.html">JNI spec for J2SE 6</a>
+to get a sense for how JNI works and what features are available. Some
+aspects of the interface aren't immediately obvious on
+first reading, so you may find the next few sections handy.
+The more detailed <i>JNI Programmer's Guide and Specification</i> can be found
+<a href="http://java.sun.com/docs/books/jni/html/jniTOC.html">here</a>.</p>
+
+
+<a name="JavaVM_and_JNIEnv" id="JavaVM_and_JNIEnv"></a>
+<h2>JavaVM and JNIEnv</h2>
+
+<p>JNI defines two key data structures, "JavaVM" and "JNIEnv". Both of these are essentially
+pointers to pointers to function tables. (In the C++ version, they're classes with a
+pointer to a function table and a member function for each JNI function that indirects through
+the table.) The JavaVM provides the "invocation interface" functions,
+which allow you to create and destroy the VM. In theory you can have multiple VMs per process,
+but Android's VM only allows one.</p>
+
+<p>The JNIEnv provides most of the JNI functions. Your native functions all receive a JNIEnv as
+the first argument.</p>
+
+<p>On some VMs, the JNIEnv is used for thread-local storage. For this reason, <strong>you cannot share a JNIEnv between threads</strong>.
+If a piece of code has no other way to get its JNIEnv, you should share
+the JavaVM, and use JavaVM-&gt;GetEnv to discover the thread's JNIEnv. (Assuming it has one; see <code>AttachCurrentThread</code> below.)</p>
+
+<p>The C declarations of JNIEnv and JavaVM are different from the C++
+declarations. "jni.h" provides different typedefs
+depending on whether it's included into ".c" or ".cpp". For this reason it's a bad idea to
+include JNIEnv arguments in header files included by both languages. (Put another way: if your
+header file requires "#ifdef __cplusplus", you may have to do some extra work if anything in
+that header refers to JNIEnv.)</p>
+
+<a name="threads" id="threads"></a>
+<h2>Threads</h2>
+
+<p>All VM threads are Linux threads, scheduled by the kernel. They're usually
+started using Java language features (notably <code>Thread.start()</code>),
+but they can also be created elsewhere and then attached to the VM. For
+example, a thread started with <code>pthread_create</code> can be attached
+with the JNI <code>AttachCurrentThread</code> or
+<code>AttachCurrentThreadAsDaemon</code> functions. Until a thread is
+attached to the VM, it has no JNIEnv, and
+<strong>cannot make JNI calls</strong>.</p>
+
+<p>Attaching a natively-created thread causes the VM to allocate and initialize
+a <code>Thread</code> object, add it to the "main" <code>ThreadGroup</code>,
+and add the thread to the set that is visible to the debugger. Calling
+<code>AttachCurrentThread</code> on an already-attached thread is a no-op.</p>
+
+<p>The Dalvik VM does not suspend threads executing native code. If
+garbage collection is in progress, or the debugger has issued a suspend
+request, the VM will pause the thread the next time it makes a JNI call.</p>
+
+<p>Threads attached through JNI <strong>must call
+<code>DetachCurrentThread</code> before they exit</strong>.
+If coding this directly is awkward, in Android &gt;= 2.0 ("Eclair") you
+can use <code>pthread_key_create</code> to define a destructor
+function that will be called before the thread exits, and
+call <code>DetachCurrentThread</code> from there. (Use that
+key with <code>pthread_setspecific</code> to store the JNIEnv in
+thread-local-storage; that way it'll be passed into your destructor as
+the argument.)</p>
+
+
+<a name="jclass_jmethodID_and_jfieldID" id="jclass_jmethodID_and_jfieldID"></a>
+<h2>jclass, jmethodID, and jfieldID</h2>
+
+<p>If you want to access an object's field from native code, you would do the following:</p>
+
+<ul>
+<li> Get the class object reference for the class with <code>FindClass</code></li>
+<li> Get the field ID for the field with <code>GetFieldID</code></li>
+<li> Get the contents of the field with something appropriate, e.g.
+<code>GetIntField</code></li>
+</ul>
+
+<p>Similarly, to call a method, you'd first get a class object reference and then a method ID. The IDs are often just
+pointers to internal VM data structures. Looking them up may require several string
+comparisons, but once you have them the actual call to get the field or invoke the method
+is very quick.</p>
+
+<p>If performance is important, it's useful to look the values up once and cache the results
+in your native code. Because we are limiting ourselves to one VM per process, it's reasonable
+to store this data in a static local structure.</p>
+
+<p>The class references, field IDs, and method IDs are guaranteed valid until the class is unloaded. Classes
+are only unloaded if all classes associated with a ClassLoader can be garbage collected,
+which is rare but will not be impossible in our system. Note however that
+the <code>jclass</code>
+is a class reference and <strong>must be protected</strong> with a call
+to <code>NewGlobalRef</code> (see the next section).</p>
+
+<p>If you would like to cache the IDs when a class is loaded, and automatically re-cache them
+if the class is ever unloaded and reloaded, the correct way to initialize
+the IDs is to add a piece of code that looks like this to the appropriate class:</p>
+
+<pre> /*
+ * We use a class initializer to allow the native code to cache some
+ * field offsets.
+ */
+
+ /*
+ * A native function that looks up and caches interesting
+ * class/field/method IDs for this class. Returns false on failure.
+ */
+ native private static boolean nativeClassInit();
+
+ /*
+ * Invoke the native initializer when the class is loaded.
+ */
+ static {
+ if (!nativeClassInit())
+ throw new RuntimeException("native init failed");
+ }</pre>
+
+<p>Create a nativeClassInit method in your C/C++ code that performs the ID lookups. The code
+will be executed once, when the class is initialized. If the class is ever unloaded and
+then reloaded, it will be executed again. (See the implementation of java.io.FileDescriptor
+for an example in our source tree.)</p>
+
+<a name="local_and_global_references" id="local_and_global_references"></a>
+<h2>Local and Global References</h2>
+
+<p>Every object that JNI returns is a "local reference". This means that it's valid for the
+duration of the current native method in the current thread.
+<strong>Even if the object itself continues to live on after the native method returns, the reference is not valid.</strong>
+This applies to all sub-classes of <code>jobject</code>, including
+<code>jclass</code>, <code>jstring</code>, and <code>jarray</code>.
+(Dalvik VM will warn you about most reference mis-uses when extended JNI
+checks are enabled.)</p>
+
+<p>If you want to hold on to a reference for a longer period, you must use
+a "global" reference. The <code>NewGlobalRef</code> function takes the
+local reference as an argument and returns a global one.
+The global reference is guaranteed to be valid until you call
+<code>DeleteGlobalRef</code>.</p>
+
+<p>This pattern is commonly used when caching copies of class objects obtained
+from <code>FindClass</code>, e.g.:</p>
+<pre>jclass* localClass = env-&gt;FindClass("MyClass");
+jclass* globalClass = (jclass*) env-&gt;NewGlobalRef(localClass);</pre>
+
+<p>All JNI methods accept both local and global references as arguments.
+It's possible for references to the same object to have different values;
+for example, the return values from consecutive calls to
+<code>NewGlobalRef</code> on the same object may be different.
+<strong>To see if two references refer to the same object,
+you must use the <code>IsSameObject</code> function.</strong> Never compare
+references with "==" in native code.</p>
+
+<p>One consequence of this is that you
+<strong>must not assume object references are constant or unique</strong>
+in native code. The 32-bit value representing an object may be different
+from one invocation of a method to the next, and it's possible that two
+different objects could have the same 32-bit value on consecutive calls. Do
+not use <code>jobject</code> values as keys.</p>
+
+<p>Programmers are required to "not excessively allocate" local references. In practical terms this means
+that if you're creating large numbers of local references, perhaps while running through an array of
+Objects, you should free them manually with
+<code>DeleteLocalRef</code> instead of letting JNI do it for you. The
+VM is only required to reserve slots for
+16 local references, so if you need more than that you should either delete as you go or use
+<code>EnsureLocalCapacity</code> to reserve more.</p>
+
+<p>Note: method and field IDs are just 32-bit identifiers, not object
+references, and should not be passed to <code>NewGlobalRef</code>. The raw data
+pointers returned by functions like <code>GetStringUTFChars</code>
+and <code>GetByteArrayElements</code> are also not objects.</p>
+
+<p>One unusual case deserves separate mention. If you attach a native
+thread to the VM with AttachCurrentThread, the code you are running will
+never "return" to the VM until the thread detaches from the VM. Any local
+references you create will have to be deleted manually unless you're going
+to detach the thread soon.</p>
+
+<a name="UTF_8_and_UTF_16_strings" id="UTF_8_and_UTF_16_strings"></a>
+<h2>UTF-8 and UTF-16 Strings</h2>
+
+<p>The Java programming language uses UTF-16. For convenience, JNI provides methods that work with "modified UTF-8" encoding
+as well. (Some VMs use the modified UTF-8 internally to store strings; ours do not.) The
+modified encoding only supports the 8- and 16-bit forms, and stores ASCII NUL values in a 16-bit encoding.
+The nice thing about it is that you can count on having C-style zero-terminated strings,
+suitable for use with standard libc string functions. The down side is that you cannot pass
+arbitrary UTF-8 data into the VM and expect it to work correctly.</p>
+
+<p>It's usually best to operate with UTF-16 strings. With our current VMs, the
+<code>GetStringChars</code> method
+does not require a copy, whereas <code>GetStringUTFChars</code> requires a malloc and a UTF conversion. Note that
+<strong>UTF-16 strings are not zero-terminated</strong>, and \u0000 is allowed,
+so you need to hang on to the string length as well as
+the string pointer.</p>
+
+<p><strong>Don't forget to Release the strings you Get</strong>. The
+string functions return <code>jchar*</code> or <code>jbyte*</code>, which
+are C-style pointers to primitive data rather than local references. They
+are guaranteed valid until Release is called, which means they are not
+released when the native method returns.</p>
+
+<p><strong>Data passed to NewStringUTF must be in "modified" UTF-8 format</strong>. A
+common mistake is reading character data from a file or network stream
+and handing it to <code>NewStringUTF</code> without filtering it.
+Unless you know the data is 7-bit ASCII, you need to strip out high-ASCII
+characters or convert them to proper "modified" UTF-8 form. If you don't,
+the UTF-16 conversion will likely not be what you expect. The extended
+JNI checks will scan strings and warn you about invalid data, but they
+won't catch everything.</p>
+
+<a name="arrays" id="arrays"></a>
+<h2>Primitive Arrays</h2>
+
+<p>JNI provides functions for accessing the contents of array objects.
+While arrays of objects must be accessed one entry at a time, arrays of
+primitives can be read and written directly as if they were declared in C.</p>
+
+<p>To make the interface as efficient as possible without constraining
+the VM implementation,
+the <code>Get&lt;PrimitiveType&gt;ArrayElements</code> family of calls
+allows the VM to either return a pointer to the actual elements, or
+allocate some memory and make a copy. Either way, the raw pointer returned
+is guaranteed to be valid until the corresponding <code>Release</code> call
+is issued (which implies that, if the data wasn't copied, the array object
+will be pinned down and can't be relocated as part of compacting the heap).
+<strong>You must Release every array you Get.</strong> Also, if the Get
+call fails, you must ensure that your code doesn't try to Release a NULL
+pointer later.</p>
+
+<p>You can determine whether or not the data was copied by passing in a
+non-NULL pointer for the <code>isCopy</code> argument. This is rarely
+useful.</p>
+
+<p>The <code>Release</code> call takes a <code>mode</code> argument that can
+have one of three values. The actions performed by the VM depend upon
+whether it returned a pointer to the actual data or a copy of it:</p>
+
+<ul>
+ <li><code>0</code>
+ <ul>
+ <li>Actual: the array object is un-pinned.
+ <li>Copy: data is copied back. The buffer with the copy is freed.
+ </ul>
+ <li><code>JNI_COMMIT</code>
+ <ul>
+ <li>Actual: does nothing.
+ <li>Copy: data is copied back. The buffer with the copy
+ <strong>is not freed</strong>.
+ </ul>
+ <li><code>JNI_ABORT</code>
+ <ul>
+ <li>Actual: the array object is un-pinned. Earlier
+ writes are <strong>not</strong> aborted.
+ <li>Copy: the buffer with the copy is freed; any changes to it are lost.
+ </ul>
+</ul>
+
+<p>One reason for checking the <code>isCopy</code> flag is to know if
+you need to call <code>Release</code> with <code>JNI_COMMIT</code>
+after making changes to an array &mdash; if you're alternating between making
+changes and executing code that uses the contents of the array, you may be
+able to
+skip the no-op commit. Another possible reason for checking the flag is for
+efficient handling of <code>JNI_ABORT</code>. For example, you might want
+to get an array, modify it in place, pass pieces to other functions, and
+then discard the changes. If you know that JNI is making a new copy for
+you, there's no need to create another "editable" copy. If JNI is passing
+you the original, then you do need to make your own copy.</p>
+
+<p>Some have asserted that you can skip the <code>Release</code> call if
+<code>*isCopy</code> is false. This is not the case. If no copy buffer was
+allocated, then the original memory must be pinned down and can't be moved by
+the garbage collector.</p>
+
+<p>Also note that the <code>JNI_COMMIT</code> flag does NOT release the array,
+and you will need to call <code>Release</code> again with a different flag
+eventually.</p>
+
+
+<a name="region_calls" id="region_calls"></a>
+<h2>Region Calls</h2>
+
+<p>There is an alternative to calls like <code>Get&lt;Type&gt;ArrayElements</code>
+and <code>GetStringChars</code> that may be very helpful when all you want
+to do is copy data in or out. Consider the following:</p>
+
+<pre>
+ jbyte* data = env->GetByteArrayElements(array, NULL);
+ if (data != NULL) {
+ memcpy(buffer, data, len);
+ env->ReleaseByteArrayElements(array, data, JNI_ABORT);
+ }</pre>
+
+<p>This grabs the array, copies the first <code>len</code> byte
+elements out of it, and then releases the array. Depending upon the VM
+policies the <code>Get</code> call will either pin or copy the array contents.
+We copy the data (for perhaps a second time), then call Release; in this case
+we use <code>JNI_ABORT</code> so there's no chance of a third copy.</p>
+
+<p>We can accomplish the same thing with this:</p>
+<pre>
+ env->GetByteArrayRegion(array, 0, len, buffer);</pre>
+
+<p>This has several advantages:</p>
+<ul>
+ <li>Requires one JNI call instead of 2, reducing overhead.
+ <li>Doesn't require pinning or extra data copies.
+ <li>Reduces the risk of programmer error &mdash; no risk of forgetting
+ to call <code>Release</code> after something fails.
+</ul>
+
+<p>Similarly, you can use the <code>Set&lt;Type&gt;ArrayRegion</code> call
+to copy data into an array, and <code>GetStringRegion</code> or
+<code>GetStringUTFRegion</code> to copy characters out of a
+<code>String</code>.
+
+
+<a name="exceptions" id="exceptions"></a>
+<h2>Exception</h2>
+
+<p><strong>You may not call most JNI functions while an exception is pending.</strong>
+Your code is expected to notice the exception (via the function's return value,
+<code>ExceptionCheck()</code>, or <code>ExceptionOccurred()</code>) and return,
+or clear the exception and handle it.</p>
+
+<p>The only JNI functions that you are allowed to call while an exception is
+pending are:</p>
+<ul>
+ <li>DeleteGlobalRef
+ <li>DeleteLocalRef
+ <li>DeleteWeakGlobalRef
+ <li>ExceptionCheck
+ <li>ExceptionClear
+ <li>ExceptionDescribe
+ <li>ExceptionOccurred
+ <li>MonitorExit
+ <li>PopLocalFrame
+ <li>PushLocalFrame
+ <li>Release&lt;PrimitiveType&gt;ArrayElements
+ <li>ReleasePrimitiveArrayCritical
+ <li>ReleaseStringChars
+ <li>ReleaseStringCritical
+ <li>ReleaseStringUTFChars
+</ul>
+
+<p>Many JNI calls can throw an exception, but often provide a simpler way
+of checking for failure. For example, if <code>NewString</code> returns
+a non-NULL value, you don't need to check for an exception. However, if
+you call a method (using a function like <code>CallObjectMethod</code>),
+you must always check for an exception, because the return value is not
+going to be valid if an exception was thrown.</p>
+
+<p>Note that exceptions thrown by interpreted code do not "leap over" native code,
+and C++ exceptions thrown by native code are not handled by Dalvik.
+The JNI <code>Throw</code> and <code>ThrowNew</code> instructions just
+set an exception pointer in the current thread. Upon returning to the VM from
+native code, the exception will be noted and handled appropriately.</p>
+
+<p>Native code can "catch" an exception by calling <code>ExceptionCheck</code> or
+<code>ExceptionOccurred</code>, and clear it with
+<code>ExceptionClear</code>. As usual,
+discarding exceptions without handling them can lead to problems.</p>
+
+<p>There are no built-in functions for manipulating the Throwable object
+itself, so if you want to (say) get the exception string you will need to
+find the Throwable class, look up the method ID for
+<code>getMessage "()Ljava/lang/String;"</code>, invoke it, and if the result
+is non-NULL use <code>GetStringUTFChars</code> to get something you can
+hand to printf or a LOG macro.</p>
+
+
+<a name="extended_checking" id="extended_checking"></a>
+<h2>Extended Checking</h2>
+
+<p>JNI does very little error checking. Calling <code>SetIntField</code>
+on an Object field will succeed, even if the field is marked
+<code>private</code> and <code>final</code>. The
+goal is to minimize the overhead on the assumption that, if you've written it in native code,
+you probably did it for performance reasons.</p>
+
+<p>In Dalvik, you can enable additional checks by setting the
+"<code>-Xcheck:jni</code>" flag. If the flag is set, the VM directs
+the JavaVM and JNIEnv pointers to a different table of functions.
+These functions perform an extended series of checks before calling the
+standard implementation.</p>
+
+<p>The additional tests include:</p>
+
+<ul>
+<li> Check for null pointers where not allowed.</li>
+<li> Verify argument type correctness (jclass is a class object,
+jfieldID points to field data, jstring is a java.lang.String).</li>
+<li> Field type correctness, e.g. don't store a HashMap in a String field.</li>
+<li> Ensure jmethodID is appropriate when making a static or virtual
+method call.</li>
+<li> Check to see if an exception is pending on calls where pending exceptions are not legal.</li>
+<li> Check for calls to inappropriate functions between Critical get/release calls.</li>
+<li> Check that JNIEnv structs aren't being shared between threads.</li>
+<li> Make sure local references aren't used outside their allowed lifespan.</li>
+<li> UTF-8 strings contain only valid "modified UTF-8" data.</li>
+</ul>
+
+<p>Accessibility of methods and fields (i.e. public vs. private) is not
+checked.</p>
+
+<p>For a description of how to enable CheckJNI for Android apps, see
+<a href="embedded-vm-control.html">Controlling the Embedded VM</a>.
+It's currently enabled by default in the Android emulator and on
+"engineering" device builds.</p>
+
+<p>JNI checks can be modified with the <code>-Xjniopts</code> command-line
+flag. Currently supported values include:</p>
+
+<dl>
+<dt>forcecopy
+<dd>When set, any function that can return a copy of the original data
+(array of primitive values, UTF-16 chars) will always do so. The buffers
+are over-allocated and surrounded with a guard pattern to help identify
+code writing outside the buffer, and the contents are erased before the
+storage is freed to trip up code that uses the data after calling Release.
+This will have a noticeable performance impact on some applications.
+<dt>warnonly
+<dd>By default, JNI "warnings" cause the VM to abort. With this flag
+it continues on.
+</dl>
+
+
+<a name="native_libraries" id="native_libraries"></a>
+<h2>Native Libraries</h2>
+
+<p>You can load native code from shared libraries with the standard
+<code>System.loadLibrary()</code> call. The
+preferred way to get at your native code is:</p>
+
+<ul>
+<li> Call <code>System.loadLibrary()</code> from a static class
+initializer. (See the earlier example, where one is used to call
+<code>nativeClassInit()</code>.) The argument is the "undecorated"
+library name, e.g. to load "libfubar.so" you would pass in "fubar".</li>
+<li> Provide a native function: <code><strong>jint JNI_OnLoad(JavaVM* vm, void* reserved)</strong></code></li>
+<li>In <code>JNI_OnLoad</code>, register all of your native methods. You
+should declare
+the methods "static" so the names don't take up space in the symbol table
+on the device.</li>
+</ul>
+
+<p>The <code>JNI_OnLoad</code> function should look something like this if
+written in C:</p>
+<pre>jint JNI_OnLoad(JavaVM* vm, void* reserved)
+{
+ JNIEnv* env;
+ if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_6) != JNI_OK)
+ return -1;
+
+ /* get class with (*env)->FindClass */
+ /* register methods with (*env)->RegisterNatives */
+
+ return JNI_VERSION_1_6;
+}</pre>
+
+<p>You can also call <code>System.load()</code> with the full path name of the
+shared library. For Android apps, you may find it useful to get the full
+path to the application's private data storage area from the context object.</p>
+
+<p>This is the recommended approach, but not the only approach. The VM does
+not require explicit registration, nor that you provide a
+<code>JNI_OnLoad</code> function.
+You can instead use "discovery" of native methods that are named in a
+specific way (see <a href="http://java.sun.com/javase/6/docs/technotes/guides/jni/spec/design.html#wp615">
+ the JNI spec</a> for details), though this is less desirable.
+It requires more space in the shared object symbol table,
+loading is slower because it requires string searches through all of the
+loaded shared libraries, and if a method signature is wrong you won't know
+about it until the first time the method is actually used.</p>
+
+<p>One other note about <code>JNI_OnLoad</code>: any <code>FindClass</code>
+calls you make from there will happen in the context of the class loader
+that was used to load the shared library. Normally <code>FindClass</code>
+uses the loader associated with the method at the top of the interpreted
+stack, or if there isn't one (because the thread was just attached to
+the VM) it uses the "system" class loader. This makes
+<code>JNI_OnLoad</code> a convenient place to look up and cache class
+object references.</p>
+
+
+<a name="64_bit" id="64_bit"></a>
+<h2>64-bit Considerations</h2>
+
+<p>Android is currently expected to run on 32-bit platforms. In theory it
+could be built for a 64-bit system, but that is not a goal at this time.
+For the most part this isn't something that you will need to worry about
+when interacting with native code,
+but it becomes significant if you plan to store pointers to native
+structures in integer fields in an object. To support architectures
+that use 64-bit pointers, <strong>you need to stash your native pointers in a
+<code>long</code> field rather than an <code>int</code></strong>.
+
+
+<a name="unsupported" id="unsupported"></a>
+<h2>Unsupported Features</h2>
+
+<p>All JNI 1.6 features are supported, with the following exceptions:</p>
+<ul>
+ <li><code>DefineClass</code> is not implemented. Dalvik does not use
+ Java bytecodes or class files, so passing in binary class data
+ doesn't work. Translation facilities may be added in a future
+ version of the VM.</li>
+ <li>"Weak global" references are implemented, but may only be passed
+ to <code>NewLocalRef</code>, <code>NewGlobalRef</code>, and
+ <code>DeleteWeakGlobalRef</code>. (The spec strongly encourages
+ programmers to create hard references to weak globals before doing
+ anything with them, so this should not be at all limiting.)</li>
+ <li><code>GetObjectRefType</code> (new in JNI 1.6) is implemented but not fully
+ functional &mdash; it can't always tell the difference between "local" and
+ "global" references.</li>
+</ul>
+
+<p>For backward compatibility, you may need to be aware of:</p>
+<ul>
+ <li>Until Android 2.0 ("Eclair"), the '$' character was not properly
+ converted to "_00024" during searches for method names. Working
+ around this requires using explicit registration or moving the
+ native methods out of inner classes.
+ <li>Until Android 2.0 ("Eclair"), it was not possible to use a <code>pthread_key_create</code>
+ destructor function to avoid the VM's "thread must be detached before
+ exit" check. (The VM also uses a pthread key destructor function,
+ so it'd be a race to see which gets called first.)
+ <li>"Weak global" references were not implemented until Android 2.2 ("Froyo").
+ Older VMs will vigorously reject attempts to use them. You can use
+ the Android platform version constants to test for support.
+</ul>
+
+
+<a name="faq_ULE" id="faq_ULE"></a>
+<h2>FAQ: UnsatisfiedLinkError</h2>
+
+<p>When working on native code it's not uncommon to see a failure like this:</p>
+<pre>java.lang.UnsatisfiedLinkError: Library foo not found</pre>
+
+<p>In some cases it means what it says &mdash; the library wasn't found. In
+other cases the library exists but couldn't be opened by dlopen(), and
+the details of the failure can be found in the exception's detail message.</p>
+
+<p>Common reasons why you might encounter "library not found" exceptions:</p>
+<ul>
+ <li>The library doesn't exist or isn't accessible to the app. Use
+ <code>adb shell ls -l &lt;path&gt;</code> to check its presence
+ and permissions.
+ <li>The library wasn't built with the NDK. This can result in
+ dependencies on functions or libraries that don't exist on the device.
+</ul>
+
+<p>Another class of <code>UnsatisfiedLinkError</code> failures looks like:</p>
+<pre>java.lang.UnsatisfiedLinkError: myfunc
+ at Foo.myfunc(Native Method)
+ at Foo.main(Foo.java:10)</pre>
+
+<p>In logcat, you'll see:</p>
+<pre>W/dalvikvm( 880): No implementation found for native LFoo;.myfunc ()V</pre>
+
+<p>This means that the VM tried to find a matching method but was unsuccessful.
+Some common reasons for this are:</p>
+<ul>
+ <li>The library isn't getting loaded. Check the logcat output for
+ messages about library loading.
+ <li>The method isn't being found due to a name or signature mismatch. This
+ is commonly caused by:
+ <ul>
+ <li>For lazy method lookup, failing to declare C++ functions
+ with <code>extern C</code>. You can use <code>arm-eabi-nm</code>
+ to see the symbols as they appear in the library; if they look
+ mangled (e.g. <code>_Z15Java_Foo_myfuncP7_JNIEnvP7_jclass</code>
+ rather than <code>Java_Foo_myfunc</code>) then you need to
+ adjust the declaration.
+ <li>For explicit registration, minor errors when entering the
+ method signature. Make sure that what you're passing to the
+ registration call matches the signature in the log file.
+ Remember that 'B' is <code>byte</code> and 'Z' is <code>boolean</code>.
+ Class name components in signatures start with 'L', end with ';',
+ use '/' to separate package/class names, and use '$' to separate
+ inner-class names
+ (e.g. <code>Ljava/util/Map$Entry;</code>).
+ </ul>
+</ul>
+
+<p>Using <code>javah</code> to automatically generate JNI headers may help
+avoid some problems.
+
+
+<a name="faq_FindClass" id="faq_FindClass"></a>
+<h2>FAQ: FindClass didn't find my class</h2>
+
+<p>Make sure that the class name string has the correct format. JNI class
+names start with the package name and are separated with slashes,
+e.g. <code>java/lang/String</code>. If you're looking up an array class,
+you need to start with the appropriate number of square brackets and
+must also wrap the class with 'L' and ';', so a one-dimensional array of
+<code>String</code> would be <code>[Ljava/lang/String;</code>.</p>
+
+<p>If the class name looks right, you could be running into a class loader
+issue. <code>FindClass</code> wants to start the class search in the
+class loader associated with your code. It examines the VM call stack,
+which will look something like:
+<pre> Foo.myfunc(Native Method)
+ Foo.main(Foo.java:10)
+ dalvik.system.NativeStart.main(Native Method)</pre>
+
+<p>The topmost method is <code>Foo.myfunc</code>. <code>FindClass</code>
+finds the <code>ClassLoader</code> object associated with the <code>Foo</code>
+class and uses that.</p>
+
+<p>This usually does what you want. You can get into trouble if you
+create a thread outside the VM (perhaps by calling <code>pthread_create</code>
+and then attaching it to the VM with <code>AttachCurrentThread</code>).
+Now the stack trace looks like this:</p>
+<pre> dalvik.system.NativeStart.run(Native Method)</pre>
+
+<p>The topmost method is <code>NativeStart.run</code>, which isn't part of
+your application. If you call <code>FindClass</code> from this thread, the
+VM will start in the "system" class loader instead of the one associated
+with your application, so attempts to find app-specific classes will fail.</p>
+
+<p>There are a few ways to work around this:</p>
+<ul>
+ <li>Do your <code>FindClass</code> lookups once, in
+ <code>JNI_OnLoad</code>, and cache the class references for later
+ use. Any <code>FindClass</code> calls made as part of executing
+ <code>JNI_OnLoad</code> will use the class loader associated with
+ the function that called <code>System.loadLibrary</code> (this is a
+ special rule, provided to make library initialization more convenient).
+ If your app code is loading the library, <code>FindClass</code>
+ will use the correct class loader.
+ <li>Pass an instance of the class into the functions that need
+ it, e.g. declare your native method to take a Class argument and
+ then pass <code>Foo.class</code> in.
+ <li>Cache a reference to the <code>ClassLoader</code> object somewhere
+ handy, and issue <code>loadClass</code> calls directly. This requires
+ some effort.
+</ul>
+
+
+<a name="faq_sharing" id="faq_sharing"></a>
+<h2>FAQ: Sharing raw data with native code</h2>
+
+<p>You may find yourself in a situation where you need to access a large
+buffer of raw data from code written in Java and C/C++. Common examples
+include manipulation of bitmaps or sound samples. There are two
+basic approaches.</p>
+
+<p>You can store the data in a <code>byte[]</code>. This allows very fast
+access from code written in Java. On the native side, however, you're
+not guaranteed to be able to access the data without having to copy it. In
+some implementations, <code>GetByteArrayElements</code> and
+<code>GetPrimitiveArrayCritical</code> will return actual pointers to the
+raw data in the managed heap, but in others it will allocate a buffer
+on the native heap and copy the data over.</p>
+
+<p>The alternative is to store the data in a direct byte buffer. These
+can be created with <code>java.nio.ByteBuffer.allocateDirect</code>, or
+the JNI <code>NewDirectByteBuffer</code> function. Unlike regular
+byte buffers, the storage is not allocated on the managed heap, and can
+always be accessed directly from native code (get the address
+with <code>GetDirectBufferAddress</code>). Depending on how direct
+byte buffer access is implemented in the VM, accessing the data from code
+written in Java can be very slow.</p>
+
+<p>The choice of which to use depends on two factors:</p>
+<ol>
+ <li>Will most of the data accesses happen from code written in Java
+ or in C/C++?
+ <li>If the data is eventually being passed to a system API, what form
+ must it be in? (For example, if the data is eventually passed to a
+ function that takes a byte[], doing processing in a direct
+ <code>ByteBuffer</code> might be unwise.)
+</ol>
+
+<p>If there's no clear winner, use a direct byte buffer. Support for them
+is built directly into JNI, and access to them from code written in
+Java can be made faster with VM improvements.</p>
diff --git a/docs/html/guide/practices/design/performance.jd b/docs/html/guide/practices/design/performance.jd
index fe69d7d5e000..c41f971ab46c 100644
--- a/docs/html/guide/practices/design/performance.jd
+++ b/docs/html/guide/practices/design/performance.jd
@@ -375,6 +375,9 @@ code compiled for the ARM in the Nexus One won't run on the ARM in the G1.</p>
<p>Native code is primarily useful when you have an existing native codebase
that you want to port to Android, not for "speeding up" parts of a Java app.</p>
+<p>If you do need to use native code, you should read our
+<a href="{@docRoot}guide/practices/design/jni.html">JNI Tips</a>.</p>
+
<p>(See also <em>Effective Java</em> item 54.)</p>
<a name="closing_notes" id="closing_notes"></a>
diff --git a/docs/html/guide/publishing/licensing.jd b/docs/html/guide/publishing/licensing.jd
index 4184ecbae3c5..a9b182eff837 100644
--- a/docs/html/guide/publishing/licensing.jd
+++ b/docs/html/guide/publishing/licensing.jd
@@ -368,7 +368,7 @@ to set up your development environment for licensing. </p>
<ol>
<li><a href="#download-sdk">Downloading the latest SDK</a>, if you haven't already done so </li>
-<li><a href="#runtime-setup">Setting up the runtime environment</a> for development</a></li>
+<li><a href="#runtime-setup">Setting up the runtime environment</a> for development</li>
<li><a href="#download-lvl">Downloading the Market Licensing component</a> into your SDK </li>
<li><a href="#lvl-setup">Setting up the Licensing Verification Library</a></li>
<li><a href="#add-library">Including the LVL library project in your application</a></li>
@@ -582,9 +582,9 @@ Licensing package contains the LVL and the LVL sample application. </div>
<p>When the download is complete, the Android SDK and AVD Manager installs both
the LVL library project and the example application into these directories: </p>
-<p style="margin-left:2em"><code>&lt;<em>sdk</em>&gt;/market_licensing/library/</code>
+<p style="margin-left:2em"><code>&lt;<em>sdk</em>&gt;/extras/google/market_licensing/library/</code>
&nbsp;&nbsp;(the LVL library project)<br />
-<code>&lt;<em>sdk</em>&gt;/market_licensing/sample/</code>&nbsp;&nbsp;(the example
+<code>&lt;<em>sdk</em>&gt;/extras/google/market_licensing/sample/</code>&nbsp;&nbsp;(the example
application)</p>
<p>If you aren't familiar with how to download components into your SDK, see the
@@ -1530,7 +1530,7 @@ Make sure that you sign in to the account from which the application you are
licensing is published (or will be published). </li>
<li>In the account home page, locate the "Edit profile" link and click it. </li>
<li>In the Edit Profile page, locate the "Licensing" pane, shown below. Your
-public key for licensing is given in the "Public key" text box. </p>
+public key for licensing is given in the "Public key" text box. </li>
</ol>
<p>To add the public key to your application, simply copy/paste the key string
diff --git a/docs/html/guide/topics/fundamentals/tasks-and-back-stack.jd b/docs/html/guide/topics/fundamentals/tasks-and-back-stack.jd
index bd542bd292f3..f22e5b2bc31e 100644
--- a/docs/html/guide/topics/fundamentals/tasks-and-back-stack.jd
+++ b/docs/html/guide/topics/fundamentals/tasks-and-back-stack.jd
@@ -11,7 +11,7 @@ parent.link=activities.html
<li>A task contains a collection of activities in the order in which the user interacts with
them</li>
<li>Tasks can move to the background and retain the state of each activity in order for the user
-to perform other tasks without loosing their work</li>
+to perform other tasks without losing their work</li>
</ul>
<h2>In this document</h2>
@@ -181,7 +181,7 @@ system memory. When this happens, information about the activity state is lost.
system still
knows that the activity has a place in the back stack, but when the activity is brought to the
top of the stack the system must recreate it (rather than resume it). In order to
-avoid loosing the user's work, you should proactively retain it by implementing the {@link
+avoid losing the user's work, you should proactively retain it by implementing the {@link
android.app.Activity#onSaveInstanceState onSaveInstanceState()} callback
methods in your activity.</p>
@@ -201,7 +201,7 @@ the normal behavior. Perhaps you want an activity in your application to begin a
started (instead of being placed within the current task); or, when you start an activity, you want
to bring forward an existing instance of it (instead of creating a new
instance on top of the back stack); or, you want your back stack to be cleared of all
-activitiesstart an activity except for the root activity when the user leaves the task.</p>
+activities except for the root activity when the user leaves the task.</p>
<p>You can do these things and more, with attributes in the
<a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
@@ -566,4 +566,4 @@ activate other application components and publish the intents to which your comp
respond, continue with the <b><a
href="{@docRoot}guide/topics/intents/intents-filters.html">Intents and Intent
Filters</a></b> document.</p>
---> \ No newline at end of file
+-->
diff --git a/docs/html/guide/webapps/targeting.jd b/docs/html/guide/webapps/targeting.jd
index bdc2d5e81ff0..46f769c92905 100644
--- a/docs/html/guide/webapps/targeting.jd
+++ b/docs/html/guide/webapps/targeting.jd
@@ -368,14 +368,14 @@ that the hdpi device shows a different image that's applied in CSS.</p>
}
&#64;media screen and (-webkit-device-pixel-ratio: 1.5) {
- // CSS for high-density screens
+ /* CSS for high-density screens */
#header {
background:url(high-density-image.png);
}
}
&#64;media screen and (-webkit-device-pixel-ratio: 0.75) {
- // CSS for low-density screens
+ /* CSS for low-density screens */
#header {
background:url(low-density-image.png);
}
@@ -426,7 +426,7 @@ target to affect how your web page is scaled for different screen densities.</p>
<pre>
if (window.devicePixelRatio == 1.5) {
alert("This is a high-density screen");
-} else if (window.devicePixelRation == 0.75) {
+} else if (window.devicePixelRatio == 0.75) {
alert("This is a low-density screen");
}
</pre>
diff --git a/docs/html/sdk/download.jd b/docs/html/sdk/download.jd
index 81b4ff63cb1f..44fe5e4c0db1 100644
--- a/docs/html/sdk/download.jd
+++ b/docs/html/sdk/download.jd
@@ -1,4 +1,93 @@
-sdk.redirect=true
+page.title=Download an Archived Android SDK
+hide_license_footer=true
@jd:body
+<script type="text/javascript">
+ function verify() {
+ document.getElementById('download-button').disabled =
+!document.getElementById('checkbox').checked;
+ }
+ function submit() {
+ var location = window.location.href;
+ if (location.indexOf('?v=') != -1) {
+ var filename = location.substring(location.indexOf('=')+1,location.length);
+ if (document.getElementById('checkbox').checked) {
+ document.location = "http://dl.google.com/android/" + filename;
+ }
+ document.getElementById('click-download').setAttribute("href", "http://dl.google.com/android/"
++ filename);
+ $("#terms-form").hide(500);
+ $("#next-steps").show(500);
+ document.getElementById('checkbox').disabled=true;
+ document.getElementById('download-button').disabled=true;
+ } else {
+ alert("You have not selected an SDK version. Please return to the SDK Archives page");
+ }
+ }
+</script>
+
+<div id="terms-form">
+ <p>Please carefully review the Android SDK License Agreement before downloading the SDK.
+The License Agreement constitutes a contract between you and Google with respect to your use of the
+SDK.</p>
+ <p class="note"><strong>Note:</strong> You must agree to this license agreement in order to
+download one of the archived SDKs, because these SDK packages contain Google software (whereas, the
+<a href="http://developer.android.com/sdk/index.html">current SDK</a> packages do not require a
+license agreement, because they contain only the open sourced SDK tools).</p>
+
+ <iframe id="terms" style="border:1px solid #888;margin:0 0 1em;height:400px;width:95%;"
+src="terms_body.html">
+ </iframe>
+
+ <p>
+ <input type="checkbox" id="checkbox" onclick="verify()" />
+ <label for="checkbox">I agree to the terms of the Android SDK License Agreement.</label>
+ </p>
+ <p>
+ <input type="submit" value="Download" id="download-button" disabled="disabled"
+onclick="submit()" />
+ </p>
+ <p>
+ <script language="javascript">
+ var loc = window.location.href;
+ if (loc.indexOf('?v=') != -1) {
+ var filename = loc.substring(loc.indexOf('=')+1,loc.length);
+ document.write("File: " + filename);
+ }
+ </script>
+ </p>
+</div><!-- end terms-form -->
+
+<noscript>
+ <p><strong>Please enable Javascript in your browser in order to agree to the terms and download
+the SDK.</strong></p>
+</noscript>
+
+<div class="special" id="next-steps" style="display:none">
+ <p>Your download should be underway. If not, <a id="click-download">click here to start the
+download</a>.</p>
+ <p>Beware that you've just downloaded a very old version of the Android SDK, which is not
+recommended. We no longer maintain documentation about how to install these archived SDKs nor
+support the tools contained within.</p>
+ <p>We recommend that you instead download the latest <a
+href="http://developer.android.com/sdk/index.html">Android SDK starter package</a>, which includes
+the latest SDK tools and allows you to develop against any version of the Android platform, back to
+Android 1.1.</p>
+</div>
+
+<script type="text/javascript">
+ var loc = window.location.href;
+ var filename = loc.substring(loc.indexOf('=')+1,loc.length);
+ version = filename.substring(filename.indexOf('.')-1,filename.lastIndexOf('.'));
+ $(".addVersionPath").each(function(i) {
+ var oldHref = $(this).attr("href");
+ $(this).attr({href: "/sdk/" + version + "/" + oldHref});
+ });
+</script>
+
+
+
+
+
+
diff --git a/docs/html/sdk/older_releases.jd b/docs/html/sdk/older_releases.jd
index 77f7e43783b6..870ff04df37d 100644
--- a/docs/html/sdk/older_releases.jd
+++ b/docs/html/sdk/older_releases.jd
@@ -47,7 +47,7 @@ Notes</a></em></p>
<td>Windows</td>
<td>
<a
-href="http://dl.google.com/android/archives/android-sdk-windows-1.6_r1.zip">android-sdk-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-windows-1.6_r1.zip">android-sdk-
windows-1 .6_r1.zip</a>
</td>
<td>260529085 bytes</td>
@@ -57,7 +57,7 @@ windows-1 .6_r1.zip</a>
<td>Mac OS X (intel)</td>
<td>
<a
-href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.6_r1.zip">android-sdk-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-mac_x86-1.6_r1.zip">android-sdk-
mac_x86-1 .6_r1.zip</a>
</td>
<td>247412515 bytes</td>
@@ -67,7 +67,7 @@ mac_x86-1 .6_r1.zip</a>
<td>Linux (i386)</td>
<td>
<a
-href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.6_r1.tgz">android-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-linux_x86-1.6_r1.tgz">android-
sdk- linux_x86-1.6_r1.tgz</a>
</td>
<td>238224860 bytes</td>
@@ -92,7 +92,7 @@ Notes</a></em></p>
<td>Windows</td>
<td>
<a
-href="http://dl.google.com/android/archives/android-sdk-windows-1.5_r3.zip">android-sdk-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-windows-1.5_r3.zip">android-sdk-
windows-1 .5_r3.zip</a>
</td>
<td>191477853 bytes</td>
@@ -102,7 +102,7 @@ windows-1 .5_r3.zip</a>
<td>Mac OS X (intel)</td>
<td>
<a
-href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.5_r3.zip">android-sdk-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-mac_x86-1.5_r3.zip">android-sdk-
mac_x86-1 .5_r3.zip</a>
</td>
<td>183024673 bytes</td>
@@ -112,7 +112,7 @@ mac_x86-1 .5_r3.zip</a>
<td>Linux (i386)</td>
<td>
<a
-href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.5_r3.zip">android-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-linux_x86-1.5_r3.zip">android-
sdk- linux_x86-1.5_r3.zip</a>
</td>
<td>178117561 bytes</td>
@@ -137,7 +137,7 @@ Notes</a></em></p>
<td>Windows</td>
<td>
<a
-href="http://dl.google.com/android/archives/android-sdk-windows-1.1_r1.zip">android-sdk-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-windows-1.1_r1.zip">android-sdk-
windows-1
.1_r1.zip</a>
</td>
@@ -148,7 +148,7 @@ windows-1
<td>Mac OS X (intel)</td>
<td>
<a
-href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.1_r1.zip">android-sdk-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-mac_x86-1.1_r1.zip">android-sdk-
mac_x86-1
.1_r1.zip</a>
</td>
@@ -159,7 +159,7 @@ mac_x86-1
<td>Linux (i386)</td>
<td>
<a
-href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.1_r1.zip">android-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-linux_x86-1.1_r1.zip">android-
sdk-
linux_x86-1.1_r1.zip</a>
</td>
@@ -185,7 +185,7 @@ Notes</a></em></p>
<td>Windows</td>
<td>
<a
-href="http://dl.google.com/android/archives/android-sdk-windows-1.0_r2.zip">android-sdk-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-windows-1.0_r2.zip">android-sdk-
windows-1
.0_r2.zip</a>
</td>
@@ -196,7 +196,7 @@ windows-1
<td>Mac OS X (intel)</td>
<td>
<a
-href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.0_r2.zip">android-sdk-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-mac_x86-1.0_r2.zip">android-sdk-
mac_x86-1
.0_r2.zip</a>
</td>
@@ -207,7 +207,7 @@ mac_x86-1
<td>Linux (i386)</td>
<td>
<a
-href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.0_r2.zip">android-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-linux_x86-1.0_r2.zip">android-
sdk-
linux_x86-1.0_r2.zip</a>
</td>
@@ -241,7 +241,7 @@ Notes</a></em></p>
<td>Windows</td>
<td>
<a
-href="http://dl.google.com/android/archives/android-sdk-windows-1.5_r2.zip">android-sdk-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-windows-1.5_r2.zip">android-sdk-
windows-1 .5_r2.zip</a>
</td>
<td>178346828 bytes</td>
@@ -251,7 +251,7 @@ windows-1 .5_r2.zip</a>
<td>Mac OS X (intel)</td>
<td>
<a
-href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.5_r2.zip">android-sdk-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-mac_x86-1.5_r2.zip">android-sdk-
mac_x86-1 .5_r2.zip</a>
</td>
<td>169945128 bytes</td>
@@ -261,7 +261,7 @@ mac_x86-1 .5_r2.zip</a>
<td>Linux (i386)</td>
<td>
<a
-href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.5_r2.zip">android-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-linux_x86-1.5_r2.zip">android-
sdk- linux_x86-1.5_r2.zip</a>
</td>
<td>165035130 bytes</td>
@@ -286,7 +286,7 @@ Notes</a></em></p>
<td>Windows</td>
<td>
<a
-href="http://dl.google.com/android/archives/android-sdk-windows-1.5_r1.zip">android-sdk-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-windows-1.5_r1.zip">android-sdk-
windows-1 .5_r1.zip</a>
</td>
<td>176263368 bytes</td>
@@ -296,7 +296,7 @@ windows-1 .5_r1.zip</a>
<td>Mac OS X (intel)</td>
<td>
<a
-href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.5_r1.zip">android-sdk-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-mac_x86-1.5_r1.zip">android-sdk-
mac_x86-1 .5_r1.zip</a>
</td>
<td>167848675 bytes</td>
@@ -306,7 +306,7 @@ mac_x86-1 .5_r1.zip</a>
<td>Linux (i386)</td>
<td>
<a
-href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.5_r1.zip">android-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-linux_x86-1.5_r1.zip">android-
sdk- linux_x86-1.5_r1.zip</a>
</td>
<td>162938845 bytes</td>
@@ -331,7 +331,7 @@ Notes</a></em></p>
<td>Windows</td>
<td>
<a
-href="http://dl.google.com/android/archives/android-sdk-windows-1.0_r1.zip">android-sdk-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-windows-1.0_r1.zip">android-sdk-
windows-1 .0_r1.zip</a>
</td>
<td>89.7 MB bytes</td>
@@ -341,7 +341,7 @@ windows-1 .0_r1.zip</a>
<td>Mac OS X (intel)</td>
<td>
<a
-href="http://dl.google.com/android/archives/android-sdk-mac_x86-1.0_r1.zip">android-sdk-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-mac_x86-1.0_r1.zip">android-sdk-
mac_x86-1 .0_r1.zip</a>
</td>
<td>87.5 MB bytes</td>
@@ -351,7 +351,7 @@ mac_x86-1 .0_r1.zip</a>
<td>Linux (i386)</td>
<td>
<a
-href="http://dl.google.com/android/archives/android-sdk-linux_x86-1.0_r1.zip">android-
+href="{@docRoot}sdk/download.html?v=archives/android-sdk-linux_x86-1.0_r1.zip">android-
sdk- linux_x86-1.0_r1.zip</a>
</td>
<td>87.8 MB bytes</td>
diff --git a/docs/html/sdk/terms_body.html b/docs/html/sdk/terms_body.html
new file mode 100644
index 000000000000..8c55b37bc61d
--- /dev/null
+++ b/docs/html/sdk/terms_body.html
@@ -0,0 +1,336 @@
+
+
+<p>This is the Android Software Development Kit License Agreement.</p>
+
+<h2>
+ 1. Introduction
+</h2>
+<p>
+ 1.1 The Android Software Development Kit (referred to in this License Agreement as the "SDK"
+and specifically including the Android system files, packaged APIs, and Google APIs add-ons) is
+licensed to you subject to the terms of this License Agreement. This License Agreement forms a
+legally binding contract between you and Google in relation to your use of the SDK.
+
+</p>
+<p>
+ 1.2 "Google" means Google Inc., a Delaware corporation with principal place of business at
+1600 Amphitheatre Parkway, Mountain View, CA 94043, United States.
+</p>
+<h2>
+ 2. Accepting this License Agreement
+</h2>
+<p>
+ 2.1 In order to use the SDK, you must first agree to this License Agreement. You may not use
+the SDK if you do not accept this License Agreement.
+</p>
+<p>
+ 2.2 You can accept this License Agreement by:
+</p>
+<p>
+ (A) clicking to accept or agree to this License Agreement, where this option is made
+available to you; or
+</p>
+<p>
+ (B) by actually using the SDK. In this case, you agree that use of the SDK constitutes
+acceptance of the Licensing Agreement from that point onwards.
+</p>
+<p>
+ 2.3 You may not use the SDK and may not accept the Licensing Agreement if you are a person
+barred from receiving the SDK under the laws of the United States or other countries including the
+country in which you are resident or from which you use the SDK.
+</p>
+<p>
+ 2.4 If you are agreeing to be bound by this License Agreement on behalf of your employer or
+other entity, you represent and warrant that you have full legal authority to bind your employer or
+such entity to this License Agreement. If you do not have the requisite authority, you may not
+accept the Licensing Agreement or use the SDK on behalf of your employer or other entity.
+</p>
+<h2>
+ 3. SDK License from Google
+</h2>
+<p>
+ 3.1 Subject to the terms of this License Agreement, Google grants you a limited, worldwide,
+royalty-free, non- assignable and non-exclusive license to use the SDK solely to develop
+applications to run on the Android platform.
+</p>
+<p>
+ 3.2 You agree that Google or third parties own all legal right, title and interest in and to
+the SDK, including any Intellectual Property Rights that subsist in the SDK. "Intellectual Property
+Rights" means any and all rights under patent law, copyright law, trade secret law, trademark law,
+and any and all other proprietary rights. Google reserves all rights not expressly granted to you.
+
+</p>
+<p>
+ 3.3 Except to the extent required by applicable third party licenses, you may not copy
+(except for backup purposes), modify, adapt, redistribute, decompile, reverse engineer, disassemble,
+or create derivative works of the SDK or any part of the SDK. Except to the extent required by
+applicable third party licenses, you may not load any part of the SDK onto a mobile handset or any
+other hardware device except a personal computer, combine any part of the SDK with other software,
+or distribute any software or device incorporating a part of the SDK.
+</p>
+<p>
+ 3.4 Use, reproduction and distribution of components of the SDK licensed under an open
+source software license are governed solely by the terms of that open source software license and
+not this License Agreement.
+</p>
+<p>
+ 3.5 You agree that the form and nature of the SDK that Google provides may change without
+prior notice to you and that future versions of the SDK may be incompatible with applications
+developed on previous versions of the SDK. You agree that Google may stop (permanently or
+temporarily) providing the SDK (or any features within the SDK) to you or to users generally at
+Google's sole discretion, without prior notice to you.
+</p>
+<p>
+ 3.6 Nothing in this License Agreement gives you a right to use any of Google's trade names,
+trademarks, service marks, logos, domain names, or other distinctive brand features.
+</p>
+<p>
+ 3.7 You agree that you will not remove, obscure, or alter any proprietary rights notices
+(including copyright and trademark notices) that may be affixed to or contained within the SDK.
+</p>
+<h2>
+ 4. Use of the SDK by You
+</h2>
+<p>
+ 4.1 Google agrees that it obtains no right, title or interest from you (or your licensors)
+under this License Agreement in or to any software applications that you develop using the SDK,
+including any intellectual property rights that subsist in those applications.
+</p>
+<p>
+ 4.2 You agree to use the SDK and write applications only for purposes that are permitted by
+(a) this License Agreement and (b) any applicable law, regulation or generally accepted practices or
+guidelines in the relevant jurisdictions (including any laws regarding the export of data or
+software to and from the United States or other relevant countries).
+</p>
+<p>
+ 4.3 You agree that if you use the SDK to develop applications for general public users, you
+will protect the privacy and legal rights of those users. If the users provide you with user names,
+passwords, or other login information or personal information, your must make the users aware that
+the information will be available to your application, and you must provide legally adequate privacy
+notice and protection for those users. If your application stores personal or sensitive information
+provided by users, it must do so securely. If the user provides your application with Google Account
+information, your application may only use that information to access the user's Google Account
+when, and for the limited purposes for which, the user has given you permission to do so.
+</p>
+<p>
+ 4.4 You agree that you will not engage in any activity with the SDK, including the
+development or distribution of an application, that interferes with, disrupts, damages, or accesses
+in an unauthorized manner the servers, networks, or other properties or services of any third party
+including, but not limited to, Google or any mobile communications carrier.
+</p>
+<p>
+ 4.5 You agree that you are solely responsible for (and that Google has no responsibility to
+you or to any third party for) any data, content, or resources that you create, transmit or display
+through the Android platform and/or applications for the Android platform, and for the consequences
+of your actions (including any loss or damage which Google may suffer) by doing so.
+</p>
+<p>
+ 4.6 You agree that you are solely responsible for (and that Google has no responsibility to
+you or to any third party for) any breach of your obligations under this License Agreement, any
+applicable third party contract or Terms of Service, or any applicable law or regulation, and for
+the consequences (including any loss or damage which Google or any third party may suffer) of any
+such breach.
+</p>
+<h2>
+ 5. Your Developer Credentials
+</h2>
+<p>
+ 5.1 You agree that you are responsible for maintaining the confidentiality of any developer
+credentials that may be issued to you by Google or which you may choose yourself and that you will
+be solely responsible for all applications that are developed under your developer credentials.
+</p>
+<h2>
+ 6. Privacy and Information
+</h2>
+<p>
+ 6.1 In order to continually innovate and improve the SDK, Google may collect certain usage
+statistics from the software including but not limited to a unique identifier, associated IP
+address, version number of the software, and information on which tools and/or services in the SDK
+are being used and how they are being used. Before any of this information is collected, the SDK
+will notify you and seek your consent. If you withhold consent, the information will not be
+collected.
+</p>
+<p>
+ 6.2 The data collected is examined in the aggregate to improve the SDK and is maintained in
+accordance with Google's Privacy Policy.
+</p>
+<h2>
+ 7. Third Party Applications for the Android Platform
+</h2>
+<p>
+ 7.1 If you use the SDK to run applications developed by a third party or that access data,
+content or resources provided by a third party, you agree that Google is not responsible for those
+applications, data, content, or resources. You understand that all data, content or resources which
+you may access through such third party applications are the sole responsibility of the person from
+which they originated and that Google is not liable for any loss or damage that you may experience
+as a result of the use or access of any of those third party applications, data, content, or
+resources.
+</p>
+<p>
+ 7.2 You should be aware the data, content, and resources presented to you through such a
+third party application may be protected by intellectual property rights which are owned by the
+providers (or by other persons or companies on their behalf). You may not modify, rent, lease, loan,
+sell, distribute or create derivative works based on these data, content, or resources (either in
+whole or in part) unless you have been specifically given permission to do so by the relevant
+owners.
+</p>
+<p>
+ 7.3 You acknowledge that your use of such third party applications, data, content, or
+resources may be subject to separate terms between you and the relevant third party. In that case,
+this License Agreement does not affect your legal relationship with these third parties.
+</p>
+<h2>
+ 8. Using Android APIs
+</h2>
+<p>
+ 8.1 Google Data APIs
+</p>
+<p>
+ 8.1.1 If you use any API to retrieve data from Google, you acknowledge that the data may be
+protected by intellectual property rights which are owned by Google or those parties that provide
+the data (or by other persons or companies on their behalf). Your use of any such API may be subject
+to additional Terms of Service. You may not modify, rent, lease, loan, sell, distribute or create
+derivative works based on this data (either in whole or in part) unless allowed by the relevant
+Terms of Service.
+</p>
+<p>
+ 8.1.2 If you use any API to retrieve a user's data from Google, you acknowledge and agree
+that you shall retrieve data only with the user's explicit consent and only when, and for the
+limited purposes for which, the user has given you permission to do so.
+
+</p>
+<h2>
+ 9. Terminating this License Agreement
+</h2>
+<p>
+ 9.1 This License Agreement will continue to apply until terminated by either you or Google
+as set out below.
+</p>
+<p>
+ 9.2 If you want to terminate this License Agreement, you may do so by ceasing your use of
+the SDK and any relevant developer credentials.
+</p>
+<p>
+ 9.3 Google may at any time, terminate this License Agreement with you if:
+</p>
+<p>
+ (A) you have breached any provision of this License Agreement; or
+</p>
+<p>
+ (B) Google is required to do so by law; or
+</p>
+<p>
+ (C) the partner with whom Google offered certain parts of SDK (such as APIs) to you has
+terminated its relationship with Google or ceased to offer certain parts of the SDK to you; or
+</p>
+<p>
+ (D) Google decides to no longer providing the SDK or certain parts of the SDK to users in
+the country in which you are resident or from which you use the service, or the provision of the SDK
+or certain SDK services to you by Google is, in Google's sole discretion, no longer commercially
+viable.
+</p>
+<p>
+ 9.4 When this License Agreement comes to an end, all of the legal rights, obligations and
+liabilities that you and Google have benefited from, been subject to (or which have accrued over
+time whilst this License Agreement has been in force) or which are expressed to continue
+indefinitely, shall be unaffected by this cessation, and the provisions of paragraph 14.7 shall
+continue to apply to such rights, obligations and liabilities indefinitely.
+</p>
+<h2>
+ 10. DISCLAIMER OF WARRANTIES
+</h2>
+<p>
+ 10.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT YOUR USE OF THE SDK IS AT YOUR SOLE RISK AND
+THAT THE SDK IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT WARRANTY OF ANY KIND FROM GOOGLE.
+</p>
+<p>
+ 10.2 YOUR USE OF THE SDK AND ANY MATERIAL DOWNLOADED OR OTHERWISE OBTAINED THROUGH THE USE
+OF THE SDK IS AT YOUR OWN DISCRETION AND RISK AND YOU ARE SOLELY RESPONSIBLE FOR ANY DAMAGE TO YOUR
+COMPUTER SYSTEM OR OTHER DEVICE OR LOSS OF DATA THAT RESULTS FROM SUCH USE.
+</p>
+<p>
+ 10.3 GOOGLE FURTHER EXPRESSLY DISCLAIMS ALL WARRANTIES AND CONDITIONS OF ANY KIND, WHETHER
+EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO THE IMPLIED WARRANTIES AND CONDITIONS OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+</p>
+<h2>
+ 11. LIMITATION OF LIABILITY
+</h2>
+<p>
+ 11.1 YOU EXPRESSLY UNDERSTAND AND AGREE THAT GOOGLE, ITS SUBSIDIARIES AND AFFILIATES, AND
+ITS LICENSORS SHALL NOT BE LIABLE TO YOU UNDER ANY THEORY OF LIABILITY FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL CONSEQUENTIAL OR EXEMPLARY DAMAGES THAT MAY BE INCURRED BY YOU, INCLUDING ANY
+LOSS OF DATA, WHETHER OR NOT GOOGLE OR ITS REPRESENTATIVES HAVE BEEN ADVISED OF OR SHOULD HAVE BEEN
+AWARE OF THE POSSIBILITY OF ANY SUCH LOSSES ARISING.
+</p>
+<h2>
+ 12. Indemnification
+</h2>
+<p>
+ 12.1 To the maximum extent permitted by law, you agree to defend, indemnify and hold
+harmless Google, its affiliates and their respective directors, officers, employees and agents from
+and against any and all claims, actions, suits or proceedings, as well as any and all losses,
+liabilities, damages, costs and expenses (including reasonable attorneys fees) arising out of or
+accruing from (a) your use of the SDK, (b) any application you develop on the SDK that infringes any
+copyright, trademark, trade secret, trade dress, patent or other intellectual property right of any
+person or defames any person or violates their rights of publicity or privacy, and (c) any
+non-compliance by you with this License Agreement.
+</p>
+<h2>
+ 13. Changes to the License Agreement
+</h2>
+<p>
+ 13.1 Google may make changes to the License Agreement as it distributes new versions of the
+SDK. When these changes are made, Google will make a new version of the License Agreement available
+on the website where the SDK is made available.
+</p>
+<h2>
+ 14. General Legal Terms
+</h2>
+<p>
+ 14.1 This License Agreement constitute the whole legal agreement between you and Google and
+govern your use of the SDK (excluding any services which Google may provide to you under a separate
+written agreement), and completely replace any prior agreements between you and Google in relation
+to the SDK.
+</p>
+<p>
+ 14.2 You agree that if Google does not exercise or enforce any legal right or remedy which
+is contained in this License Agreement (or which Google has the benefit of under any applicable
+law), this will not be taken to be a formal waiver of Google's rights and that those rights or
+remedies will still be available to Google.
+</p>
+<p>
+ 14.3 If any court of law, having the jurisdiction to decide on this matter, rules that any
+provision of this License Agreement is invalid, then that provision will be removed from this
+License Agreement without affecting the rest of this License Agreement. The remaining provisions of
+this License Agreement will continue to be valid and enforceable.
+</p>
+<p>
+ 14.4 You acknowledge and agree that each member of the group of companies of which Google is
+the parent shall be third party beneficiaries to this License Agreement and that such other
+companies shall be entitled to directly enforce, and rely upon, any provision of this License
+Agreement that confers a benefit on (or rights in favor of) them. Other than this, no other person
+or company shall be third party beneficiaries to this License Agreement.
+</p>
+<p>
+ 14.5 EXPORT RESTRICTIONS. THE SDK IS SUBJECT TO UNITED STATES EXPORT LAWS AND REGULATIONS.
+YOU MUST COMPLY WITH ALL DOMESTIC AND INTERNATIONAL EXPORT LAWS AND REGULATIONS THAT APPLY TO THE
+SDK. THESE LAWS INCLUDE RESTRICTIONS ON DESTINATIONS, END USERS AND END USE.
+</p>
+<p>
+ 14.6 The rights granted in this License Agreement may not be assigned or transferred by
+either you or Google without the prior written approval of the other party. Neither you nor Google
+shall be permitted to delegate their responsibilities or obligations under this License Agreement
+without the prior written approval of the other party.
+</p>
+<p>
+ 14.7 This License Agreement, and your relationship with Google under this License Agreement,
+shall be governed by the laws of the State of California without regard to its conflict of laws
+provisions. You and Google agree to submit to the exclusive jurisdiction of the courts located
+within the county of Santa Clara, California to resolve any legal matter arising from this License
+Agreement. Notwithstanding this, you agree that Google shall still be allowed to apply for
+injunctive remedies (or an equivalent type of urgent legal relief) in any jurisdiction.
+</p>
+<p>
+ <em>April 10, 2009</em>
+</p> \ No newline at end of file
diff --git a/include/android_runtime/AndroidRuntime.h b/include/android_runtime/AndroidRuntime.h
index 22c9b72b6276..b02a057efab1 100644
--- a/include/android_runtime/AndroidRuntime.h
+++ b/include/android_runtime/AndroidRuntime.h
@@ -46,17 +46,13 @@ public:
const char* className, const JNINativeMethod* gMethods, int numMethods);
/**
- * Call a static Java function that takes no arguments and returns void.
- */
- status_t callStatic(const char* className, const char* methodName);
-
- /**
* Call a class's static main method with the given arguments,
*/
- status_t callMain(const char* className, int argc, const char* const argv[]);
+ status_t callMain(const char* className, jclass clazz, int argc,
+ const char* const argv[]);
/**
- * Find a class, with the input either of the form
+ * Find a class, with the input either of the form
* "package/class" or "package.class".
*/
static jclass findClass(JNIEnv* env, const char* className);
@@ -67,7 +63,14 @@ public:
void start(); // start in android.util.RuntimeInit
static AndroidRuntime* getRuntime();
-
+
+ /**
+ * This gets called after the VM has been created, but before we
+ * run any code. Override it to make any FindClass calls that need
+ * to use CLASSPATH.
+ */
+ virtual void onVmCreated(JNIEnv* env);
+
/**
* This gets called after the JavaVM has initialized. Override it
* with the system's native entry point.
@@ -98,6 +101,9 @@ public:
/** return a pointer to the JNIEnv pointer for this thread */
static JNIEnv* getJNIEnv();
+ /** return a new string corresponding to 'className' with all '.'s replaced by '/'s. */
+ static char* toSlashClassName(const char* className);
+
private:
static int startReg(JNIEnv* env);
void parseExtraOpts(char* extraOptsBuf);
@@ -112,7 +118,7 @@ private:
* Thread creation helpers.
*/
static int javaCreateThreadEtc(
- android_thread_func_t entryFunction,
+ android_thread_func_t entryFunction,
void* userData,
const char* threadName,
int32_t threadPriority,
@@ -121,9 +127,6 @@ private:
static int javaThreadShell(void* args);
};
-// Returns the Unix file descriptor for a ParcelFileDescriptor object
-extern int getParcelFileDescriptorFD(JNIEnv* env, jobject object);
-
extern CursorWindow * get_window_from_object(JNIEnv * env, jobject javaWindow);
}
diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h
index 32c9a1d5a9b6..bfe13f01bc7f 100644
--- a/include/binder/Parcel.h
+++ b/include/binder/Parcel.h
@@ -53,7 +53,8 @@ public:
status_t setData(const uint8_t* buffer, size_t len);
- status_t appendFrom(Parcel *parcel, size_t start, size_t len);
+ status_t appendFrom(const Parcel *parcel,
+ size_t start, size_t len);
bool hasFileDescriptors() const;
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index 7930f47a68c3..e272839151c8 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -308,6 +308,44 @@ public:
// 0.3333, EV is -2.
// Example value: "0.333333333" or "0.5". Read only.
static const char KEY_EXPOSURE_COMPENSATION_STEP[];
+ // The maximum number of metering areas supported. This is the maximum
+ // length of KEY_METERING_AREAS.
+ // Example value: "0" or "2". Read only.
+ static const char KEY_MAX_NUM_METERING_AREAS[];
+ // Current metering areas. Camera driver uses these areas to decide
+ // exposure.
+ //
+ // Before accessing this parameter, apps should check
+ // KEY_MAX_NUM_METERING_AREAS first to know the maximum number of metering
+ // areas first. If the value is 0, metering area is not supported.
+ //
+ // Each metering area is a rectangle with specified weight. The direction is
+ // relative to the sensor orientation, that is, what the sensor sees. The
+ // direction is not affected by the rotation or mirroring of
+ // CAMERA_CMD_SET_DISPLAY_ORIENTATION. Coordinates of the rectangle range
+ // from -1000 to 1000. (-1000, -1000) is the upper left point. (1000, 1000)
+ // is the lower right point. The length and width of metering areas cannot
+ // be 0 or negative.
+ //
+ // The weight ranges from 1 to 1000. The sum of the weights of all metering
+ // areas must be 1000. Metering areas can partially overlap and the driver
+ // will add the weights in the overlap region. But apps should not set two
+ // metering areas that have identical coordinates.
+ //
+ // A special case of all-zero single metering area means driver to decide
+ // the metering area. For example, the driver may use more signals to decide
+ // metering areas and change them dynamically. Apps can set all-zero if they
+ // want the driver to decide metering areas.
+ //
+ // Metering areas are relative to the current field of view (KEY_ZOOM).
+ // No matter what the zoom level is, (-1000,-1000) represents the top of the
+ // currently visible camera frame. The metering area cannot be set to be
+ // outside the current field of view, even when using zoom.
+ //
+ // No matter what metering areas are, the final exposure are compensated
+ // by KEY_EXPOSURE_COMPENSATION.
+ // Example value: "(-10,-10,0,0,300),(0,0,10,10,700)". Read/write.
+ static const char KEY_METERING_AREAS[];
// Current zoom value.
// Example value: "0" or "6". Read/write.
static const char KEY_ZOOM[];
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 585d288ed26a..96828c640c27 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -127,11 +127,28 @@ public:
// be called from the client.
status_t setDefaultBufferSize(uint32_t w, uint32_t h);
-private:
+ // getCurrentBuffer returns the buffer associated with the current image.
+ sp<GraphicBuffer> getCurrentBuffer() const;
+
+ // getCurrentTextureTarget returns the texture target of the current
+ // texture as returned by updateTexImage().
+ GLenum getCurrentTextureTarget() const;
+
+ // getCurrentCrop returns the cropping rectangle of the current buffer
+ Rect getCurrentCrop() const;
+
+ // getCurrentTransform returns the transform of the current buffer
+ uint32_t getCurrentTransform() const;
+
+protected:
// freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for
// all slots.
void freeAllBuffers();
+ static bool isExternalFormat(uint32_t format);
+ static GLenum getTextureTarget(uint32_t format);
+
+private:
// createImage creates a new EGLImage from a GraphicBuffer.
EGLImageKHR createImage(EGLDisplay dpy,
@@ -194,6 +211,10 @@ private:
// reset mCurrentTexture to INVALID_BUFFER_SLOT.
int mCurrentTexture;
+ // mCurrentTextureTarget is the GLES texture target to be used with the
+ // current texture.
+ GLenum mCurrentTextureTarget;
+
// mCurrentTextureBuf is the graphic buffer of the current texture. It's
// possible that this buffer is not associated with any buffer slot, so we
// must track it separately in order to properly use
@@ -248,12 +269,6 @@ private:
// allocate new GraphicBuffer objects.
sp<IGraphicBufferAlloc> mGraphicBufferAlloc;
- // mAllocdBuffers is mirror of the list of buffers that SurfaceFlinger is
- // referencing. This is kept so that gralloc implementations do not need to
- // properly handle the case where SurfaceFlinger no longer holds a reference
- // to a buffer, but other processes do.
- Vector<sp<GraphicBuffer> > mAllocdBuffers;
-
// mFrameAvailableListener is the listener object that will be called when a
// new frame becomes available. If it is not NULL it will be called from
// queueBuffer.
@@ -262,7 +277,7 @@ private:
// mMutex is the mutex used to prevent concurrent access to the member
// variables of SurfaceTexture objects. It must be locked whenever the
// member variables are accessed.
- Mutex mMutex;
+ mutable Mutex mMutex;
};
// ----------------------------------------------------------------------------
diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h
index df82bf217f72..fe9b04917ed8 100644
--- a/include/gui/SurfaceTextureClient.h
+++ b/include/gui/SurfaceTextureClient.h
@@ -27,6 +27,8 @@
namespace android {
+class Surface;
+
class SurfaceTextureClient
: public EGLNativeBase<ANativeWindow, SurfaceTextureClient, RefBase>
{
@@ -36,6 +38,7 @@ public:
sp<ISurfaceTexture> getISurfaceTexture() const;
private:
+ friend class Surface;
// can't be copied
SurfaceTextureClient& operator = (const SurfaceTextureClient& rhs);
@@ -78,6 +81,8 @@ private:
void freeAllBuffers();
+ int getConnectedApi() const;
+
enum { MIN_UNDEQUEUED_BUFFERS = SurfaceTexture::MIN_UNDEQUEUED_BUFFERS };
enum { MIN_BUFFER_SLOTS = SurfaceTexture::MIN_BUFFER_SLOTS };
enum { NUM_BUFFER_SLOTS = SurfaceTexture::NUM_BUFFER_SLOTS };
@@ -121,10 +126,25 @@ private:
// a timestamp is auto-generated when queueBuffer is called.
int64_t mTimestamp;
+ // mConnectedApi holds the currently connected API to this surface
+ int mConnectedApi;
+
+ // mQueryWidth is the width returned by query(). It is set to width
+ // of the last dequeued buffer or to mReqWidth if no buffer was dequeued.
+ uint32_t mQueryWidth;
+
+ // mQueryHeight is the height returned by query(). It is set to height
+ // of the last dequeued buffer or to mReqHeight if no buffer was dequeued.
+ uint32_t mQueryHeight;
+
+ // mQueryFormat is the format returned by query(). It is set to the last
+ // dequeued format or to mReqFormat if no buffer was dequeued.
+ uint32_t mQueryFormat;
+
// mMutex is the mutex used to prevent concurrent access to the member
// variables of SurfaceTexture objects. It must be locked whenever the
// member variables are accessed.
- Mutex mMutex;
+ mutable Mutex mMutex;
};
}; // namespace android
diff --git a/include/media/IMediaPlayerClient.h b/include/media/IMediaPlayerClient.h
index eee6c9762f08..daec1c707693 100644
--- a/include/media/IMediaPlayerClient.h
+++ b/include/media/IMediaPlayerClient.h
@@ -28,7 +28,7 @@ class IMediaPlayerClient: public IInterface
public:
DECLARE_META_INTERFACE(MediaPlayerClient);
- virtual void notify(int msg, int ext1, int ext2) = 0;
+ virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 447942bd5ed5..e1b6dd6e4330 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -55,7 +55,8 @@ enum player_type {
// callback mechanism for passing messages to MediaPlayer object
-typedef void (*notify_callback_f)(void* cookie, int msg, int ext1, int ext2);
+typedef void (*notify_callback_f)(void* cookie,
+ int msg, int ext1, int ext2, const Parcel *obj);
// abstract base class - use MediaPlayerInterface
class MediaPlayerBase : public RefBase
@@ -159,9 +160,10 @@ public:
mCookie = cookie; mNotify = notifyFunc;
}
- void sendEvent(int msg, int ext1=0, int ext2=0) {
+ void sendEvent(int msg, int ext1=0, int ext2=0,
+ const Parcel *obj=NULL) {
Mutex::Autolock autoLock(mNotifyLock);
- if (mNotify) mNotify(mCookie, msg, ext1, ext2);
+ if (mNotify) mNotify(mCookie, msg, ext1, ext2, obj);
}
private:
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 528eeb91c257..748e48931b73 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -37,6 +37,7 @@ enum media_event_type {
MEDIA_BUFFERING_UPDATE = 3,
MEDIA_SEEK_COMPLETE = 4,
MEDIA_SET_VIDEO_SIZE = 5,
+ MEDIA_TIMED_TEXT = 99,
MEDIA_ERROR = 100,
MEDIA_INFO = 200,
};
@@ -129,7 +130,7 @@ enum media_player_states {
class MediaPlayerListener: virtual public RefBase
{
public:
- virtual void notify(int msg, int ext1, int ext2) = 0;
+ virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) = 0;
};
class MediaPlayer : public BnMediaPlayerClient,
@@ -166,7 +167,7 @@ public:
status_t setLooping(int loop);
bool isLooping();
status_t setVolume(float leftVolume, float rightVolume);
- void notify(int msg, int ext1, int ext2);
+ void notify(int msg, int ext1, int ext2, const Parcel *obj = NULL);
static sp<IMemory> decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
static sp<IMemory> decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat);
status_t invoke(const Parcel& request, Parcel *reply);
diff --git a/include/surfaceflinger/IGraphicBufferAlloc.h b/include/surfaceflinger/IGraphicBufferAlloc.h
index d996af75a478..01e4bd9ff052 100644
--- a/include/surfaceflinger/IGraphicBufferAlloc.h
+++ b/include/surfaceflinger/IGraphicBufferAlloc.h
@@ -32,18 +32,10 @@ class IGraphicBufferAlloc : public IInterface
public:
DECLARE_META_INTERFACE(GraphicBufferAlloc);
- /* Create a new GraphicBuffer for the client to use. The server will
- * maintain a reference to the newly created GraphicBuffer until
- * freeAllGraphicBuffers is called.
+ /* Create a new GraphicBuffer for the client to use.
*/
virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
PixelFormat format, uint32_t usage) = 0;
-
- /* Free all but one of the GraphicBuffer objects that the server is
- * currently referencing. If bufIndex is not a valid index of the buffers
- * the server is referencing, then all buffers are freed.
- */
- virtual void freeAllGraphicBuffersExcept(int bufIndex) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/tts/TtsEngine.h b/include/tts/TtsEngine.h
deleted file mode 100644
index 998e35322c45..000000000000
--- a/include/tts/TtsEngine.h
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Copyright (C) 2009 Google Inc.
- *
- * 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 <media/AudioSystem.h>
-
-// This header defines the interface used by the Android platform
-// to access Text-To-Speech functionality in shared libraries that implement
-// speech synthesis and the management of resources associated with the
-// synthesis.
-// An example of the implementation of this interface can be found in
-// FIXME: add path+name to implementation of default TTS engine
-// Libraries implementing this interface are used in:
-// frameworks/base/tts/jni/android_tts_SpeechSynthesis.cpp
-
-namespace android {
-
-#define ANDROID_TTS_ENGINE_PROPERTY_CONFIG "engineConfig"
-#define ANDROID_TTS_ENGINE_PROPERTY_PITCH "pitch"
-#define ANDROID_TTS_ENGINE_PROPERTY_RATE "rate"
-#define ANDROID_TTS_ENGINE_PROPERTY_VOLUME "volume"
-
-
-enum tts_synth_status {
- TTS_SYNTH_DONE = 0,
- TTS_SYNTH_PENDING = 1
-};
-
-enum tts_callback_status {
- TTS_CALLBACK_HALT = 0,
- TTS_CALLBACK_CONTINUE = 1
-};
-
-// The callback is used by the implementation of this interface to notify its
-// client, the Android TTS service, that the last requested synthesis has been
-// completed. // TODO reword
-// The callback for synthesis completed takes:
-// @param [inout] void *& - The userdata pointer set in the original
-// synth call
-// @param [in] uint32_t - Track sampling rate in Hz
-// @param [in] uint32_t - The audio format
-// @param [in] int - The number of channels
-// @param [inout] int8_t *& - A buffer of audio data only valid during the
-// execution of the callback
-// @param [inout] size_t & - The size of the buffer
-// @param [in] tts_synth_status - indicate whether the synthesis is done, or
-// if more data is to be synthesized.
-// @return TTS_CALLBACK_HALT to indicate the synthesis must stop,
-// TTS_CALLBACK_CONTINUE to indicate the synthesis must continue if
-// there is more data to produce.
-typedef tts_callback_status (synthDoneCB_t)(void *&, uint32_t,
- uint32_t, int, int8_t *&, size_t&, tts_synth_status);
-
-class TtsEngine;
-extern "C" TtsEngine* getTtsEngine();
-
-enum tts_result {
- TTS_SUCCESS = 0,
- TTS_FAILURE = -1,
- TTS_FEATURE_UNSUPPORTED = -2,
- TTS_VALUE_INVALID = -3,
- TTS_PROPERTY_UNSUPPORTED = -4,
- TTS_PROPERTY_SIZE_TOO_SMALL = -5,
- TTS_MISSING_RESOURCES = -6
-};
-
-enum tts_support_result {
- TTS_LANG_COUNTRY_VAR_AVAILABLE = 2,
- TTS_LANG_COUNTRY_AVAILABLE = 1,
- TTS_LANG_AVAILABLE = 0,
- TTS_LANG_MISSING_DATA = -1,
- TTS_LANG_NOT_SUPPORTED = -2
-};
-
-class TtsEngine
-{
-public:
- virtual ~TtsEngine() {}
-
- // Initialize the TTS engine and returns whether initialization succeeded.
- // @param synthDoneCBPtr synthesis callback function pointer
- // @return TTS_SUCCESS, or TTS_FAILURE
- virtual tts_result init(synthDoneCB_t synthDoneCBPtr, const char *engineConfig);
-
- // Shut down the TTS engine and releases all associated resources.
- // @return TTS_SUCCESS, or TTS_FAILURE
- virtual tts_result shutdown();
-
- // Interrupt synthesis and flushes any synthesized data that hasn't been
- // output yet. This will block until callbacks underway are completed.
- // @return TTS_SUCCESS, or TTS_FAILURE
- virtual tts_result stop();
-
- // Returns the level of support for the language, country and variant.
- // @return TTS_LANG_COUNTRY_VAR_AVAILABLE if the language, country and variant are supported,
- // and the corresponding resources are correctly installed
- // TTS_LANG_COUNTRY_AVAILABLE if the language and country are supported and the
- // corresponding resources are correctly installed, but there is no match for
- // the specified variant
- // TTS_LANG_AVAILABLE if the language is supported and the
- // corresponding resources are correctly installed, but there is no match for
- // the specified country and variant
- // TTS_LANG_MISSING_DATA if the required resources to provide any level of support
- // for the language are not correctly installed
- // TTS_LANG_NOT_SUPPORTED if the language is not supported by the TTS engine.
- virtual tts_support_result isLanguageAvailable(const char *lang, const char *country,
- const char *variant);
-
- // Load the resources associated with the specified language. The loaded
- // language will only be used once a call to setLanguage() with the same
- // language value is issued. Language and country values are coded according to the ISO three
- // letter codes for languages and countries, as can be retrieved from a java.util.Locale
- // instance. The variant value is encoded as the variant string retrieved from a
- // java.util.Locale instance built with that variant data.
- // @param lang pointer to the ISO three letter code for the language
- // @param country pointer to the ISO three letter code for the country
- // @param variant pointer to the variant code
- // @return TTS_SUCCESS, or TTS_FAILURE
- virtual tts_result loadLanguage(const char *lang, const char *country, const char *variant);
-
- // Load the resources associated with the specified language, country and Locale variant.
- // The loaded language will only be used once a call to setLanguageFromLocale() with the same
- // language value is issued. Language and country values are coded according to the ISO three
- // letter codes for languages and countries, as can be retrieved from a java.util.Locale
- // instance. The variant value is encoded as the variant string retrieved from a
- // java.util.Locale instance built with that variant data.
- // @param lang pointer to the ISO three letter code for the language
- // @param country pointer to the ISO three letter code for the country
- // @param variant pointer to the variant code
- // @return TTS_SUCCESS, or TTS_FAILURE
- virtual tts_result setLanguage(const char *lang, const char *country, const char *variant);
-
- // Retrieve the currently set language, country and variant, or empty strings if none of
- // parameters have been set. Language and country are represented by their 3-letter ISO code
- // @param[out] pointer to the retrieved 3-letter code language value
- // @param[out] pointer to the retrieved 3-letter code country value
- // @param[out] pointer to the retrieved variant value
- // @return TTS_SUCCESS, or TTS_FAILURE
- virtual tts_result getLanguage(char *language, char *country, char *variant);
-
- // Notifies the engine what audio parameters should be used for the synthesis.
- // This is meant to be used as a hint, the engine implementation will set the output values
- // to those of the synthesis format, based on a given hint.
- // @param[inout] encoding in: the desired audio sample format
- // out: the format used by the TTS engine
- // @param[inout] rate in: the desired audio sample rate
- // out: the sample rate used by the TTS engine
- // @param[inout] channels in: the desired number of audio channels
- // out: the number of channels used by the TTS engine
- // @return TTS_SUCCESS, or TTS_FAILURE
- virtual tts_result setAudioFormat(AudioSystem::audio_format& encoding, uint32_t& rate,
- int& channels);
-
- // Set a property for the the TTS engine
- // "size" is the maximum size of "value" for properties "property"
- // @param property pointer to the property name
- // @param value pointer to the property value
- // @param size maximum size required to store this type of property
- // @return TTS_PROPERTY_UNSUPPORTED, or TTS_SUCCESS, or TTS_FAILURE,
- // or TTS_VALUE_INVALID
- virtual tts_result setProperty(const char *property, const char *value,
- const size_t size);
-
- // Retrieve a property from the TTS engine
- // @param property pointer to the property name
- // @param[out] value pointer to the retrieved language value
- // @param[inout] iosize in: stores the size available to store the
- // property value.
- // out: stores the size required to hold the language
- // value if getLanguage() returned
- // TTS_PROPERTY_SIZE_TOO_SMALL, unchanged otherwise
- // @return TTS_PROPERTY_UNSUPPORTED, or TTS_SUCCESS,
- // or TTS_PROPERTY_SIZE_TOO_SMALL
- virtual tts_result getProperty(const char *property, char *value,
- size_t *iosize);
-
- // Synthesize the text.
- // As the synthesis is performed, the engine invokes the callback to notify
- // the TTS framework that it has filled the given buffer, and indicates how
- // many bytes it wrote. The callback is called repeatedly until the engine
- // has generated all the audio data corresponding to the text.
- // Note about the format of the input: the text parameter may use the
- // following elements
- // and their respective attributes as defined in the SSML 1.0 specification:
- // * lang
- // * say-as:
- // o interpret-as
- // * phoneme
- // * voice:
- // o gender,
- // o age,
- // o variant,
- // o name
- // * emphasis
- // * break:
- // o strength,
- // o time
- // * prosody:
- // o pitch,
- // o contour,
- // o range,
- // o rate,
- // o duration,
- // o volume
- // * mark
- // Differences between this text format and SSML are:
- // * full SSML documents are not supported
- // * namespaces are not supported
- // Text is coded in UTF-8.
- // @param text the UTF-8 text to synthesize
- // @param userdata pointer to be returned when the call is invoked
- // @param buffer the location where the synthesized data must be written
- // @param bufferSize the number of bytes that can be written in buffer
- // @return TTS_SUCCESS or TTS_FAILURE
- virtual tts_result synthesizeText(const char *text, int8_t *buffer,
- size_t bufferSize, void *userdata);
-
-};
-
-} // namespace android
-
diff --git a/include/utils/AssetManager.h b/include/utils/AssetManager.h
index 9e2bf37e8fa4..a8c7ddbd78a6 100644
--- a/include/utils/AssetManager.h
+++ b/include/utils/AssetManager.h
@@ -222,6 +222,7 @@ private:
{
String8 path;
FileType type;
+ String8 idmap;
};
Asset* openInPathLocked(const char* fileName, AccessMode mode,
@@ -262,6 +263,16 @@ private:
void setLocaleLocked(const char* locale);
void updateResourceParamsLocked() const;
+ bool createIdmapFileLocked(const String8& originalPath, const String8& overlayPath,
+ const String8& idmapPath);
+
+ bool isIdmapStaleLocked(const String8& originalPath, const String8& overlayPath,
+ const String8& idmapPath);
+
+ Asset* openIdmapLocked(const struct asset_path& ap) const;
+
+ bool getZipEntryCrcLocked(const String8& zipPath, const char* entryFilename, uint32_t* pCrc);
+
class SharedZip : public RefBase {
public:
static sp<SharedZip> get(const String8& path);
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index 35792dc0c7bd..173412e4155a 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -1798,9 +1798,9 @@ public:
~ResTable();
status_t add(const void* data, size_t size, void* cookie,
- bool copyData=false);
+ bool copyData=false, const void* idmap = NULL);
status_t add(Asset* asset, void* cookie,
- bool copyData=false);
+ bool copyData=false, const void* idmap = NULL);
status_t add(ResTable* src);
status_t getError() const;
@@ -2046,6 +2046,24 @@ public:
void getLocales(Vector<String8>* locales) const;
+ // Generate an idmap.
+ //
+ // Return value: on success: NO_ERROR; caller is responsible for free-ing
+ // outData (using free(3)). On failure, any status_t value other than
+ // NO_ERROR; the caller should not free outData.
+ status_t createIdmap(const ResTable& overlay, uint32_t originalCrc, uint32_t overlayCrc,
+ void** outData, size_t* outSize) const;
+
+ enum {
+ IDMAP_HEADER_SIZE_BYTES = 3 * sizeof(uint32_t),
+ };
+ // Retrieve idmap meta-data.
+ //
+ // This function only requires the idmap header (the first
+ // IDMAP_HEADER_SIZE_BYTES) bytes of an idmap file.
+ static bool getIdmapInfo(const void* idmap, size_t size,
+ uint32_t* pOriginalCrc, uint32_t* pOverlayCrc);
+
#ifndef HAVE_ANDROID_OS
void print(bool inclValues) const;
static String8 normalizeForOutput(const char* input);
@@ -2059,7 +2077,7 @@ private:
struct bag_set;
status_t add(const void* data, size_t size, void* cookie,
- Asset* asset, bool copyData);
+ Asset* asset, bool copyData, const Asset* idmap);
ssize_t getResourcePackageIndex(uint32_t resID) const;
ssize_t getEntry(
@@ -2068,7 +2086,7 @@ private:
const ResTable_type** outType, const ResTable_entry** outEntry,
const Type** outTypeClass) const;
status_t parsePackage(
- const ResTable_package* const pkg, const Header* const header);
+ const ResTable_package* const pkg, const Header* const header, uint32_t idmap_id);
void print_value(const Package* pkg, const Res_value& value) const;
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index d57f2c9fdcec..a0fc4d05bc8f 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -338,7 +338,7 @@ void Parcel::setDataPosition(size_t pos) const
status_t Parcel::setDataCapacity(size_t size)
{
- if (size > mDataSize) return continueWrite(size);
+ if (size > mDataCapacity) return continueWrite(size);
return NO_ERROR;
}
@@ -353,12 +353,12 @@ status_t Parcel::setData(const uint8_t* buffer, size_t len)
return err;
}
-status_t Parcel::appendFrom(Parcel *parcel, size_t offset, size_t len)
+status_t Parcel::appendFrom(const Parcel *parcel, size_t offset, size_t len)
{
const sp<ProcessState> proc(ProcessState::self());
status_t err;
- uint8_t *data = parcel->mData;
- size_t *objects = parcel->mObjects;
+ const uint8_t *data = parcel->mData;
+ const size_t *objects = parcel->mObjects;
size_t size = parcel->mObjectsSize;
int startPos = mDataPos;
int firstIndex = -1, lastIndex = -2;
@@ -386,10 +386,12 @@ status_t Parcel::appendFrom(Parcel *parcel, size_t offset, size_t len)
}
int numObjects = lastIndex - firstIndex + 1;
- // grow data
- err = growData(len);
- if (err != NO_ERROR) {
- return err;
+ if ((mDataSize+len) > mDataCapacity) {
+ // grow data
+ err = growData(len);
+ if (err != NO_ERROR) {
+ return err;
+ }
}
// append data
@@ -1384,8 +1386,10 @@ status_t Parcel::continueWrite(size_t desired)
return NO_MEMORY;
}
} else {
- mDataSize = desired;
- LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
+ if (mDataSize > desired) {
+ mDataSize = desired;
+ LOGV("continueWrite Setting data size of %p to %d\n", this, mDataSize);
+ }
if (mDataPos > desired) {
mDataPos = desired;
LOGV("continueWrite Setting data pos of %p to %d\n", this, mDataPos);
diff --git a/libs/camera/CameraParameters.cpp b/libs/camera/CameraParameters.cpp
index 1e7abaebbfc1..214cd4df8280 100644
--- a/libs/camera/CameraParameters.cpp
+++ b/libs/camera/CameraParameters.cpp
@@ -68,6 +68,8 @@ const char CameraParameters::KEY_EXPOSURE_COMPENSATION[] = "exposure-compensatio
const char CameraParameters::KEY_MAX_EXPOSURE_COMPENSATION[] = "max-exposure-compensation";
const char CameraParameters::KEY_MIN_EXPOSURE_COMPENSATION[] = "min-exposure-compensation";
const char CameraParameters::KEY_EXPOSURE_COMPENSATION_STEP[] = "exposure-compensation-step";
+const char CameraParameters::KEY_MAX_NUM_METERING_AREAS[] = "max-num-metering-areas";
+const char CameraParameters::KEY_METERING_AREAS[] = "metering-areas";
const char CameraParameters::KEY_ZOOM[] = "zoom";
const char CameraParameters::KEY_MAX_ZOOM[] = "max-zoom";
const char CameraParameters::KEY_ZOOM_RATIOS[] = "zoom-ratios";
diff --git a/libs/gui/IGraphicBufferAlloc.cpp b/libs/gui/IGraphicBufferAlloc.cpp
index e05da725c47f..0cd51da539ed 100644
--- a/libs/gui/IGraphicBufferAlloc.cpp
+++ b/libs/gui/IGraphicBufferAlloc.cpp
@@ -32,7 +32,6 @@ namespace android {
enum {
CREATE_GRAPHIC_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
- FREE_ALL_GRAPHIC_BUFFERS_EXCEPT,
};
class BpGraphicBufferAlloc : public BpInterface<IGraphicBufferAlloc>
@@ -46,8 +45,7 @@ public:
virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
PixelFormat format, uint32_t usage) {
Parcel data, reply;
- data.writeInterfaceToken(
- IGraphicBufferAlloc::getInterfaceDescriptor());
+ data.writeInterfaceToken(IGraphicBufferAlloc::getInterfaceDescriptor());
data.writeInt32(w);
data.writeInt32(h);
data.writeInt32(format);
@@ -58,17 +56,12 @@ public:
if (nonNull) {
graphicBuffer = new GraphicBuffer();
reply.read(*graphicBuffer);
+ // reply.readStrongBinder();
+ // here we don't even have to read the BufferReference from
+ // the parcel, it'll die with the parcel.
}
return graphicBuffer;
}
-
- virtual void freeAllGraphicBuffersExcept(int bufIdx) {
- Parcel data, reply;
- data.writeInterfaceToken(
- IGraphicBufferAlloc::getInterfaceDescriptor());
- data.writeInt32(bufIdx);
- remote()->transact(FREE_ALL_GRAPHIC_BUFFERS_EXCEPT, data, &reply);
- }
};
IMPLEMENT_META_INTERFACE(GraphicBufferAlloc, "android.ui.IGraphicBufferAlloc");
@@ -80,6 +73,17 @@ status_t BnGraphicBufferAlloc::onTransact(
{
// codes that don't require permission check
+ /* BufferReference just keeps a strong reference to a
+ * GraphicBuffer until it is destroyed (that is, until
+ * no local or remote process have a reference to it).
+ */
+ class BufferReference : public BBinder {
+ sp<GraphicBuffer> buffer;
+ public:
+ BufferReference(const sp<GraphicBuffer>& buffer) : buffer(buffer) { }
+ };
+
+
switch(code) {
case CREATE_GRAPHIC_BUFFER: {
CHECK_INTERFACE(IGraphicBufferAlloc, data, reply);
@@ -91,15 +95,16 @@ status_t BnGraphicBufferAlloc::onTransact(
reply->writeInt32(result != 0);
if (result != 0) {
reply->write(*result);
+ // We add a BufferReference to this parcel to make sure the
+ // buffer stays alive until the GraphicBuffer object on
+ // the other side has been created.
+ // This is needed so that the buffer handle can be
+ // registered before the buffer is destroyed on implementations
+ // that do not use file-descriptors to track their buffers.
+ reply->writeStrongBinder( new BufferReference(result) );
}
return NO_ERROR;
} break;
- case FREE_ALL_GRAPHIC_BUFFERS_EXCEPT: {
- CHECK_INTERFACE(IGraphicBufferAlloc, data, reply);
- int bufIdx = data.readInt32();
- freeAllGraphicBuffersExcept(bufIdx);
- return NO_ERROR;
- } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index f4e2a676160f..39418f03adae 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -27,6 +27,8 @@
#include <gui/SurfaceTexture.h>
+#include <hardware/hardware.h>
+
#include <surfaceflinger/ISurfaceComposer.h>
#include <surfaceflinger/SurfaceComposerClient.h>
#include <surfaceflinger/IGraphicBufferAlloc.h>
@@ -82,6 +84,7 @@ SurfaceTexture::SurfaceTexture(GLuint tex) :
mUseDefaultSize(true),
mBufferCount(MIN_BUFFER_SLOTS),
mCurrentTexture(INVALID_BUFFER_SLOT),
+ mCurrentTextureTarget(GL_TEXTURE_EXTERNAL_OES),
mCurrentTransform(0),
mCurrentTimestamp(0),
mLastQueued(INVALID_BUFFER_SLOT),
@@ -172,7 +175,6 @@ sp<GraphicBuffer> SurfaceTexture::requestBuffer(int buf,
mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
}
- mAllocdBuffers.add(graphicBuffer);
}
return graphicBuffer;
}
@@ -198,6 +200,7 @@ status_t SurfaceTexture::dequeueBuffer(int *buf) {
if (buffer == NULL) {
return ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
}
+
if ((mUseDefaultSize) &&
((uint32_t(buffer->width) != mDefaultWidth) ||
(uint32_t(buffer->height) != mDefaultHeight))) {
@@ -264,9 +267,6 @@ status_t SurfaceTexture::updateTexImage() {
LOGV("SurfaceTexture::updateTexImage");
Mutex::Autolock lock(mMutex);
- // We always bind the texture even if we don't update its contents.
- glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTexName);
-
// Initially both mCurrentTexture and mLastQueued are INVALID_BUFFER_SLOT,
// so this check will fail until a buffer gets queued.
if (mCurrentTexture != mLastQueued) {
@@ -284,7 +284,15 @@ status_t SurfaceTexture::updateTexImage() {
while ((error = glGetError()) != GL_NO_ERROR) {
LOGE("GL error cleared before updating SurfaceTexture: %#04x", error);
}
- glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, (GLeglImageOES)image);
+
+ GLenum target = getTextureTarget(
+ mSlots[mLastQueued].mGraphicBuffer->format);
+ if (target != mCurrentTextureTarget) {
+ glDeleteTextures(1, &mTexName);
+ }
+ glBindTexture(target, mTexName);
+ glEGLImageTargetTexture2DOES(target, (GLeglImageOES)image);
+
bool failed = false;
while ((error = glGetError()) != GL_NO_ERROR) {
LOGE("error binding external texture image %p (slot %d): %#04x",
@@ -297,14 +305,53 @@ status_t SurfaceTexture::updateTexImage() {
// Update the SurfaceTexture state.
mCurrentTexture = mLastQueued;
+ mCurrentTextureTarget = target;
mCurrentTextureBuf = mSlots[mCurrentTexture].mGraphicBuffer;
mCurrentCrop = mLastQueuedCrop;
mCurrentTransform = mLastQueuedTransform;
mCurrentTimestamp = mLastQueuedTimestamp;
+ } else {
+ // We always bind the texture even if we don't update its contents.
+ glBindTexture(mCurrentTextureTarget, mTexName);
}
return OK;
}
+bool SurfaceTexture::isExternalFormat(uint32_t format)
+{
+ switch (format) {
+ // supported YUV formats
+ case HAL_PIXEL_FORMAT_YV12:
+ // Legacy/deprecated YUV formats
+ case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+ case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+ case HAL_PIXEL_FORMAT_YCbCr_422_I:
+ return true;
+ }
+
+ // Any OEM format needs to be considered
+ if (format>=0x100 && format<=0x1FF)
+ return true;
+
+ return false;
+}
+
+GLenum SurfaceTexture::getTextureTarget(uint32_t format)
+{
+ GLenum target = GL_TEXTURE_2D;
+#if defined(GL_OES_EGL_image_external)
+ if (isExternalFormat(format)) {
+ target = GL_TEXTURE_EXTERNAL_OES;
+ }
+#endif
+ return target;
+}
+
+GLenum SurfaceTexture::getCurrentTextureTarget() const {
+ Mutex::Autolock lock(mMutex);
+ return mCurrentTextureTarget;
+}
+
void SurfaceTexture::getTransformMatrix(float mtx[16]) {
LOGV("SurfaceTexture::getTransformMatrix");
Mutex::Autolock lock(mMutex);
@@ -425,19 +472,6 @@ void SurfaceTexture::freeAllBuffers() {
mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
}
}
-
- int exceptBuf = -1;
- for (size_t i = 0; i < mAllocdBuffers.size(); i++) {
- if (mAllocdBuffers[i] == mCurrentTextureBuf) {
- exceptBuf = i;
- break;
- }
- }
- mAllocdBuffers.clear();
- if (exceptBuf >= 0) {
- mAllocdBuffers.add(mCurrentTextureBuf);
- }
- mGraphicBufferAlloc->freeAllGraphicBuffersExcept(exceptBuf);
}
EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy,
@@ -459,6 +493,22 @@ EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy,
return image;
}
+sp<GraphicBuffer> SurfaceTexture::getCurrentBuffer() const {
+ Mutex::Autolock lock(mMutex);
+ return mCurrentTextureBuf;
+}
+
+Rect SurfaceTexture::getCurrentCrop() const {
+ Mutex::Autolock lock(mMutex);
+ return mCurrentCrop;
+}
+
+uint32_t SurfaceTexture::getCurrentTransform() const {
+ Mutex::Autolock lock(mMutex);
+ return mCurrentTransform;
+}
+
+
static void mtxMul(float out[16], const float a[16], const float b[16]) {
out[0] = a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3];
out[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3];
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index 29fc4d3edc1e..f4b24162f0bf 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -26,8 +26,10 @@ namespace android {
SurfaceTextureClient::SurfaceTextureClient(
const sp<ISurfaceTexture>& surfaceTexture):
mSurfaceTexture(surfaceTexture), mAllocator(0), mReqWidth(0),
- mReqHeight(0), mReqFormat(DEFAULT_FORMAT), mReqUsage(0),
- mTimestamp(NATIVE_WINDOW_TIMESTAMP_AUTO), mMutex() {
+ mReqHeight(0), mReqFormat(0), mReqUsage(0),
+ mTimestamp(NATIVE_WINDOW_TIMESTAMP_AUTO), mConnectedApi(0),
+ mQueryWidth(0), mQueryHeight(0), mQueryFormat(0),
+ mMutex() {
// Initialize the ANativeWindow function pointers.
ANativeWindow::setSwapInterval = setSwapInterval;
ANativeWindow::dequeueBuffer = dequeueBuffer;
@@ -101,9 +103,10 @@ int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer) {
}
sp<GraphicBuffer>& gbuf(mSlots[buf]);
if (err == ISurfaceTexture::BUFFER_NEEDS_REALLOCATION ||
- gbuf == 0 || gbuf->getWidth() != mReqWidth ||
- gbuf->getHeight() != mReqHeight ||
- uint32_t(gbuf->getPixelFormat()) != mReqFormat ||
+ gbuf == 0 ||
+ (mReqWidth && gbuf->getWidth() != mReqWidth) ||
+ (mReqHeight && gbuf->getHeight() != mReqHeight) ||
+ (mReqFormat && uint32_t(gbuf->getPixelFormat()) != mReqFormat) ||
(gbuf->getUsage() & mReqUsage) != mReqUsage) {
gbuf = mSurfaceTexture->requestBuffer(buf, mReqWidth, mReqHeight,
mReqFormat, mReqUsage);
@@ -111,6 +114,9 @@ int SurfaceTextureClient::dequeueBuffer(android_native_buffer_t** buffer) {
LOGE("dequeueBuffer: ISurfaceTexture::requestBuffer failed");
return NO_MEMORY;
}
+ mQueryWidth = gbuf->width;
+ mQueryHeight = gbuf->height;
+ mQueryFormat = gbuf->format;
}
*buffer = gbuf.get();
return OK;
@@ -159,13 +165,13 @@ int SurfaceTextureClient::query(int what, int* value) {
Mutex::Autolock lock(mMutex);
switch (what) {
case NATIVE_WINDOW_WIDTH:
+ *value = mQueryWidth ? mQueryWidth : mReqWidth;
+ return NO_ERROR;
case NATIVE_WINDOW_HEIGHT:
- // XXX: How should SurfaceTexture behave if setBuffersGeometry didn't
- // override the size?
- *value = 0;
+ *value = mQueryHeight ? mQueryHeight : mReqHeight;
return NO_ERROR;
case NATIVE_WINDOW_FORMAT:
- *value = DEFAULT_FORMAT;
+ *value = mQueryFormat ? mQueryFormat : mReqFormat;
return NO_ERROR;
case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS:
*value = MIN_UNDEQUEUED_BUFFERS;
@@ -260,16 +266,49 @@ int SurfaceTextureClient::dispatchSetBuffersTimestamp(va_list args) {
int SurfaceTextureClient::connect(int api) {
LOGV("SurfaceTextureClient::connect");
- // XXX: Implement this!
- return INVALID_OPERATION;
+ Mutex::Autolock lock(mMutex);
+ int err = NO_ERROR;
+ switch (api) {
+ case NATIVE_WINDOW_API_EGL:
+ if (mConnectedApi) {
+ err = -EINVAL;
+ } else {
+ mConnectedApi = api;
+ }
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+ return err;
}
int SurfaceTextureClient::disconnect(int api) {
LOGV("SurfaceTextureClient::disconnect");
- // XXX: Implement this!
- return INVALID_OPERATION;
+ Mutex::Autolock lock(mMutex);
+ int err = NO_ERROR;
+ switch (api) {
+ case NATIVE_WINDOW_API_EGL:
+ if (mConnectedApi == api) {
+ mConnectedApi = 0;
+ } else {
+ err = -EINVAL;
+ }
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+ return err;
}
+int SurfaceTextureClient::getConnectedApi() const
+{
+ Mutex::Autolock lock(mMutex);
+ return mConnectedApi;
+}
+
+
int SurfaceTextureClient::setUsage(uint32_t reqUsage)
{
LOGV("SurfaceTextureClient::setUsage");
diff --git a/libs/rs/driver/rsdBcc.cpp b/libs/rs/driver/rsdBcc.cpp
index 6c5a55be85ed..20aef4939dae 100644
--- a/libs/rs/driver/rsdBcc.cpp
+++ b/libs/rs/driver/rsdBcc.cpp
@@ -381,7 +381,7 @@ void rsdScriptInvokeForEach(const Context *rsc,
mtls.zEnd = rsMax((uint32_t)1, mtls.zEnd);
mtls.arrayEnd = rsMax((uint32_t)1, mtls.arrayEnd);
- rsAssert(ain->getType()->getDimZ() == 0);
+ rsAssert(!ain || (ain->getType()->getDimZ() == 0));
Context *mrsc = (Context *)rsc;
Script * oldTLS = setTLS(s);
diff --git a/libs/usb/src/com/android/future/usb/UsbManager.java b/libs/usb/src/com/android/future/usb/UsbManager.java
index d424b63ba182..91d8e8a86f36 100644
--- a/libs/usb/src/com/android/future/usb/UsbManager.java
+++ b/libs/usb/src/com/android/future/usb/UsbManager.java
@@ -28,7 +28,7 @@ import android.os.ServiceManager;
import android.util.Log;
/**
- * This class allows you to access the state of USB, both in host and device mode.
+ * This is a wrapper class for the USB Manager to support USB accessories.
*
* <p>You can obtain an instance of this class by calling {@link #getInstance}
*
@@ -141,7 +141,7 @@ public class UsbManager {
/**
* Returns true if the caller has permission to access the accessory.
* Permission might have been granted temporarily via
- * {@link #requestPermission(android.hardware.usb.UsbAccessory} or
+ * {@link #requestPermission} or
* by the user choosing the caller as the default application for the accessory.
*
* @param accessory to check permissions for
diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp
index 6e57d93d8b47..e41dd3968299 100644
--- a/libs/utils/AssetManager.cpp
+++ b/libs/utils/AssetManager.cpp
@@ -37,6 +37,19 @@
#include <errno.h>
#include <assert.h>
#include <strings.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#ifndef TEMP_FAILURE_RETRY
+/* Used to retry syscalls that can return EINTR. */
+#define TEMP_FAILURE_RETRY(exp) ({ \
+ typeof (exp) _rc; \
+ do { \
+ _rc = (exp); \
+ } while (_rc == -1 && errno == EINTR); \
+ _rc; })
+#endif
using namespace android;
@@ -49,6 +62,7 @@ static const char* kDefaultVendor = "default";
static const char* kAssetsRoot = "assets";
static const char* kAppZipName = NULL; //"classes.jar";
static const char* kSystemAssets = "framework/framework-res.apk";
+static const char* kIdmapCacheDir = "resource-cache";
static const char* kExcludeExtension = ".EXCLUDE";
@@ -56,6 +70,35 @@ static Asset* const kExcludedAsset = (Asset*) 0xd000000d;
static volatile int32_t gCount = 0;
+namespace {
+ // Transform string /a/b/c.apk to /data/resource-cache/a@b@c.apk@idmap
+ String8 idmapPathForPackagePath(const String8& pkgPath)
+ {
+ const char* root = getenv("ANDROID_DATA");
+ LOG_ALWAYS_FATAL_IF(root == NULL, "ANDROID_DATA not set");
+ String8 path(root);
+ path.appendPath(kIdmapCacheDir);
+
+ char buf[256]; // 256 chars should be enough for anyone...
+ strncpy(buf, pkgPath.string(), 255);
+ buf[255] = '\0';
+ char* filename = buf;
+ while (*filename && *filename == '/') {
+ ++filename;
+ }
+ char* p = filename;
+ while (*p) {
+ if (*p == '/') {
+ *p = '@';
+ }
+ ++p;
+ }
+ path.appendPath(filename);
+ path.append("@idmap");
+
+ return path;
+ }
+}
/*
* ===========================================================================
@@ -123,7 +166,7 @@ bool AssetManager::addAssetPath(const String8& path, void** cookie)
return true;
}
}
-
+
LOGV("In %p Asset %s path: %s", this,
ap.type == kFileTypeDirectory ? "dir" : "zip", ap.path.string());
@@ -134,9 +177,181 @@ bool AssetManager::addAssetPath(const String8& path, void** cookie)
*cookie = (void*)mAssetPaths.size();
}
+ // add overlay packages for /system/framework; apps are handled by the
+ // (Java) package manager
+ if (strncmp(path.string(), "/system/framework/", 18) == 0) {
+ // When there is an environment variable for /vendor, this
+ // should be changed to something similar to how ANDROID_ROOT
+ // and ANDROID_DATA are used in this file.
+ String8 overlayPath("/vendor/overlay/framework/");
+ overlayPath.append(path.getPathLeaf());
+ if (TEMP_FAILURE_RETRY(access(overlayPath.string(), R_OK)) == 0) {
+ asset_path oap;
+ oap.path = overlayPath;
+ oap.type = ::getFileType(overlayPath.string());
+ bool addOverlay = (oap.type == kFileTypeRegular); // only .apks supported as overlay
+ if (addOverlay) {
+ oap.idmap = idmapPathForPackagePath(overlayPath);
+
+ if (isIdmapStaleLocked(ap.path, oap.path, oap.idmap)) {
+ addOverlay = createIdmapFileLocked(ap.path, oap.path, oap.idmap);
+ }
+ }
+ if (addOverlay) {
+ mAssetPaths.add(oap);
+ } else {
+ LOGW("failed to add overlay package %s\n", overlayPath.string());
+ }
+ }
+ }
+
+ return true;
+}
+
+bool AssetManager::isIdmapStaleLocked(const String8& originalPath, const String8& overlayPath,
+ const String8& idmapPath)
+{
+ struct stat st;
+ if (TEMP_FAILURE_RETRY(stat(idmapPath.string(), &st)) == -1) {
+ if (errno == ENOENT) {
+ return true; // non-existing idmap is always stale
+ } else {
+ LOGW("failed to stat file %s: %s\n", idmapPath.string(), strerror(errno));
+ return false;
+ }
+ }
+ if (st.st_size < ResTable::IDMAP_HEADER_SIZE_BYTES) {
+ LOGW("file %s has unexpectedly small size=%zd\n", idmapPath.string(), (size_t)st.st_size);
+ return false;
+ }
+ int fd = TEMP_FAILURE_RETRY(::open(idmapPath.string(), O_RDONLY));
+ if (fd == -1) {
+ LOGW("failed to open file %s: %s\n", idmapPath.string(), strerror(errno));
+ return false;
+ }
+ char buf[ResTable::IDMAP_HEADER_SIZE_BYTES];
+ ssize_t bytesLeft = ResTable::IDMAP_HEADER_SIZE_BYTES;
+ for (;;) {
+ ssize_t r = TEMP_FAILURE_RETRY(read(fd, buf + ResTable::IDMAP_HEADER_SIZE_BYTES - bytesLeft,
+ bytesLeft));
+ if (r < 0) {
+ TEMP_FAILURE_RETRY(close(fd));
+ return false;
+ }
+ bytesLeft -= r;
+ if (bytesLeft == 0) {
+ break;
+ }
+ }
+ TEMP_FAILURE_RETRY(close(fd));
+
+ uint32_t cachedOriginalCrc, cachedOverlayCrc;
+ if (!ResTable::getIdmapInfo(buf, ResTable::IDMAP_HEADER_SIZE_BYTES,
+ &cachedOriginalCrc, &cachedOverlayCrc)) {
+ return false;
+ }
+
+ uint32_t actualOriginalCrc, actualOverlayCrc;
+ if (!getZipEntryCrcLocked(originalPath, "resources.arsc", &actualOriginalCrc)) {
+ return false;
+ }
+ if (!getZipEntryCrcLocked(overlayPath, "resources.arsc", &actualOverlayCrc)) {
+ return false;
+ }
+ return cachedOriginalCrc != actualOriginalCrc || cachedOverlayCrc != actualOverlayCrc;
+}
+
+bool AssetManager::getZipEntryCrcLocked(const String8& zipPath, const char* entryFilename,
+ uint32_t* pCrc)
+{
+ asset_path ap;
+ ap.path = zipPath;
+ const ZipFileRO* zip = getZipFileLocked(ap);
+ if (zip == NULL) {
+ return false;
+ }
+ const ZipEntryRO entry = zip->findEntryByName(entryFilename);
+ if (entry == NULL) {
+ return false;
+ }
+ if (!zip->getEntryInfo(entry, NULL, NULL, NULL, NULL, NULL, (long*)pCrc)) {
+ return false;
+ }
return true;
}
+bool AssetManager::createIdmapFileLocked(const String8& originalPath, const String8& overlayPath,
+ const String8& idmapPath)
+{
+ LOGD("%s: originalPath=%s overlayPath=%s idmapPath=%s\n",
+ __FUNCTION__, originalPath.string(), overlayPath.string(), idmapPath.string());
+ ResTable tables[2];
+ const String8* paths[2] = { &originalPath, &overlayPath };
+ uint32_t originalCrc, overlayCrc;
+ bool retval = false;
+ ssize_t offset = 0;
+ int fd = 0;
+ uint32_t* data = NULL;
+ size_t size;
+
+ for (int i = 0; i < 2; ++i) {
+ asset_path ap;
+ ap.type = kFileTypeRegular;
+ ap.path = *paths[i];
+ Asset* ass = openNonAssetInPathLocked("resources.arsc", Asset::ACCESS_BUFFER, ap);
+ if (ass == NULL) {
+ LOGW("failed to find resources.arsc in %s\n", ap.path.string());
+ goto error;
+ }
+ tables[i].add(ass, (void*)1, false);
+ }
+
+ if (!getZipEntryCrcLocked(originalPath, "resources.arsc", &originalCrc)) {
+ LOGW("failed to retrieve crc for resources.arsc in %s\n", originalPath.string());
+ goto error;
+ }
+ if (!getZipEntryCrcLocked(overlayPath, "resources.arsc", &overlayCrc)) {
+ LOGW("failed to retrieve crc for resources.arsc in %s\n", overlayPath.string());
+ goto error;
+ }
+
+ if (tables[0].createIdmap(tables[1], originalCrc, overlayCrc,
+ (void**)&data, &size) != NO_ERROR) {
+ LOGW("failed to generate idmap data for file %s\n", idmapPath.string());
+ goto error;
+ }
+
+ // This should be abstracted (eg replaced by a stand-alone
+ // application like dexopt, triggered by something equivalent to
+ // installd).
+ fd = TEMP_FAILURE_RETRY(::open(idmapPath.string(), O_WRONLY | O_CREAT | O_TRUNC, 0644));
+ if (fd == -1) {
+ LOGW("failed to write idmap file %s (open: %s)\n", idmapPath.string(), strerror(errno));
+ goto error_free;
+ }
+ for (;;) {
+ ssize_t written = TEMP_FAILURE_RETRY(write(fd, data + offset, size));
+ if (written < 0) {
+ LOGW("failed to write idmap file %s (write: %s)\n", idmapPath.string(),
+ strerror(errno));
+ goto error_close;
+ }
+ size -= (size_t)written;
+ offset += written;
+ if (size == 0) {
+ break;
+ }
+ }
+
+ retval = true;
+error_close:
+ TEMP_FAILURE_RETRY(close(fd));
+error_free:
+ free(data);
+error:
+ return retval;
+}
+
bool AssetManager::addDefaultAssets()
{
const char* root = getenv("ANDROID_ROOT");
@@ -405,6 +620,7 @@ const ResTable* AssetManager::getResTable(bool required) const
ResTable* sharedRes = NULL;
bool shared = true;
const asset_path& ap = mAssetPaths.itemAt(i);
+ Asset* idmap = openIdmapLocked(ap);
LOGV("Looking for resource asset in '%s'\n", ap.path.string());
if (ap.type != kFileTypeDirectory) {
if (i == 0) {
@@ -434,7 +650,7 @@ const ResTable* AssetManager::getResTable(bool required) const
// can quickly copy it out for others.
LOGV("Creating shared resources for %s", ap.path.string());
sharedRes = new ResTable();
- sharedRes->add(ass, (void*)(i+1), false);
+ sharedRes->add(ass, (void*)(i+1), false, idmap);
sharedRes = const_cast<AssetManager*>(this)->
mZipSet.setZipResourceTable(ap.path, sharedRes);
}
@@ -458,7 +674,7 @@ const ResTable* AssetManager::getResTable(bool required) const
rt->add(sharedRes);
} else {
LOGV("Parsing resources for %s", ap.path.string());
- rt->add(ass, (void*)(i+1), !shared);
+ rt->add(ass, (void*)(i+1), !shared, idmap);
}
if (!shared) {
@@ -499,6 +715,21 @@ void AssetManager::updateResourceParamsLocked() const
res->setParameters(mConfig);
}
+Asset* AssetManager::openIdmapLocked(const struct asset_path& ap) const
+{
+ Asset* ass = NULL;
+ if (ap.idmap.size() != 0) {
+ ass = const_cast<AssetManager*>(this)->
+ openAssetFromFileLocked(ap.idmap, Asset::ACCESS_BUFFER);
+ if (ass) {
+ LOGV("loading idmap %s\n", ap.idmap.string());
+ } else {
+ LOGW("failed to load idmap %s\n", ap.idmap.string());
+ }
+ }
+ return ass;
+}
+
const ResTable& AssetManager::getResources(bool required) const
{
const ResTable* rt = getResTable(required);
diff --git a/libs/utils/README b/libs/utils/README
index 36a706d5c0db..01741e0930c7 100644
--- a/libs/utils/README
+++ b/libs/utils/README
@@ -1,4 +1,6 @@
Android Utility Function Library
+================================
+
If you need a feature that is native to Linux but not present on other
platforms, construct a platform-dependent implementation that shares
@@ -12,3 +14,276 @@ The ultimate goal is *not* to create a super-duper platform abstraction
layer. The goal is to provide an optimized solution for Linux with
reasonable implementations for other platforms.
+
+
+Resource overlay
+================
+
+
+Introduction
+------------
+
+Overlay packages are special .apk files which provide no code but
+additional resource values (and possibly new configurations) for
+resources in other packages. When an application requests resources,
+the system will return values from either the application's original
+package or any associated overlay package. Any redirection is completely
+transparent to the calling application.
+
+Resource values have the following precedence table, listed in
+descending precedence.
+
+ * overlay package, matching config (eg res/values-en-land)
+
+ * original package, matching config
+
+ * overlay package, no config (eg res/values)
+
+ * original package, no config
+
+During compilation, overlay packages are differentiated from regular
+packages by passing the -o flag to aapt.
+
+
+Background
+----------
+
+This section provides generic background material on resources in
+Android.
+
+
+How resources are bundled in .apk files
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Android .apk files are .zip files, usually housing .dex code,
+certificates and resources, though packages containing resources but
+no code are possible. Resources can be divided into the following
+categories; a `configuration' indicates a set of phone language, display
+density, network operator, etc.
+
+ * assets: uncompressed, raw files packaged as part of an .apk and
+ explicitly referenced by filename. These files are
+ independent of configuration.
+
+ * res/drawable: bitmap or xml graphics. Each file may have different
+ values depending on configuration.
+
+ * res/values: integers, strings, etc. Each resource may have different
+ values depending on configuration.
+
+Resource meta information and information proper is stored in a binary
+format in a named file resources.arsc, bundled as part of the .apk.
+
+Resource IDs and lookup
+~~~~~~~~~~~~~~~~~~~~~~~
+During compilation, the aapt tool gathers application resources and
+generates a resources.arsc file. Each resource name is assigned an
+integer ID 0xppttiii (translated to a symbolic name via R.java), where
+
+ * pp: corresponds to the package namespace (details below).
+
+ * tt: corresponds to the resource type (string, int, etc). Every
+ resource of the same type within the same package has the same
+ tt value, but depending on available types, the actual numerical
+ value may be different between packages.
+
+ * iiii: sequential number, assigned in the order resources are found.
+
+Resource values are specified paired with a set of configuration
+constraints (the default being the empty set), eg res/values-sv-port
+which imposes restrictions on language (Swedish) and display orientation
+(portrait). During lookup, every constraint set is matched against the
+current configuration, and the value corresponding to the best matching
+constraint set is returned (ResourceTypes.{h,cpp}).
+
+Parsing of resources.arsc is handled by ResourceTypes.cpp; this utility
+is governed by AssetManager.cpp, which tracks loaded resources per
+process.
+
+Assets are looked up by path and filename in AssetManager.cpp. The path
+to resources in res/drawable are located by ResourceTypes.cpp and then
+handled like assets by AssetManager.cpp. Other resources are handled
+solely by ResourceTypes.cpp.
+
+Package ID as namespace
+~~~~~~~~~~~~~~~~~~~~~~~
+The pp part of a resource ID defines a namespace. Android currently
+defines two namespaces:
+
+ * 0x01: system resources (pre-installed in framework-res.apk)
+
+ * 0x7f: application resources (bundled in the application .apk)
+
+ResourceTypes.cpp supports package IDs between 0x01 and 0x7f
+(inclusive); values outside this range are invalid.
+
+Each running (Dalvik) process is assigned a unique instance of
+AssetManager, which in turn keeps a forest structure of loaded
+resource.arsc files. Normally, this forest is structured as follows,
+where mPackageMap is the internal vector employed in ResourceTypes.cpp.
+
+mPackageMap[0x00] -> system package
+mPackageMap[0x01] -> NULL
+mPackageMap[0x02] -> NULL
+...
+mPackageMap[0x7f - 2] -> NULL
+mPackageMap[0x7f - 1] -> application package
+
+
+
+The resource overlay extension
+------------------------------
+
+The resource overlay mechanism aims to (partly) shadow and extend
+existing resources with new values for defined and new configurations.
+Technically, this is achieved by adding resource-only packages (called
+overlay packages) to existing resource namespaces, like so:
+
+mPackageMap[0x00] -> system package -> system overlay package
+mPackageMap[0x01] -> NULL
+mPackageMap[0x02] -> NULL
+...
+mPackageMap[0x7f - 2] -> NULL
+mPackageMap[0x7f - 1] -> application package -> overlay 1 -> overlay 2
+
+The use of overlay resources is completely transparent to
+applications; no additional resource identifiers are introduced, only
+configuration/value pairs. Any number of overlay packages may be loaded
+at a time; overlay packages are agnostic to what they target -- both
+system and application resources are fair game.
+
+The package targeted by an overlay package is called the target or
+original package.
+
+Resource overlay operates on symbolic resources names. Hence, to
+override the string/str1 resources in a package, the overlay package
+would include a resource also named string/str1. The end user does not
+have to worry about the numeric resources IDs assigned by aapt, as this
+is resolved automatically by the system.
+
+As of this writing, the use of resource overlay has not been fully
+explored. Until it has, only OEMs are trusted to use resource overlay.
+For this reason, overlay packages must reside in /system/overlay.
+
+
+Resource ID mapping
+~~~~~~~~~~~~~~~~~~~
+Resource identifiers must be coherent within the same namespace (ie
+PackageGroup in ResourceTypes.cpp). Calling applications will refer to
+resources using the IDs defined in the original package, but there is no
+guarantee aapt has assigned the same ID to the corresponding resource in
+an overlay package. To translate between the two, a resource ID mapping
+{original ID -> overlay ID} is created during package installation
+(PackageManagerService.java) and used during resource lookup. The
+mapping is stored in /data/resource-cache, with a @idmap file name
+suffix.
+
+The idmap file format is documented in a separate section, below.
+
+
+Package management
+~~~~~~~~~~~~~~~~~~
+Packages are managed by the PackageManagerService. Addition and removal
+of packages are monitored via the inotify framework, exposed via
+android.os.FileObserver.
+
+During initialization of a Dalvik process, ActivityThread.java requests
+the process' AssetManager (by proxy, via AssetManager.java and JNI)
+to load a list of packages. This list includes overlay packages, if
+present.
+
+When a target package or a corresponding overlay package is installed,
+the target package's process is stopped and a new idmap is generated.
+This is similar to how applications are stopped when their packages are
+upgraded.
+
+
+Creating overlay packages
+-------------------------
+
+Overlay packages should contain no code, define (some) resources with
+the same type and name as in the original package, and be compiled with
+the -o flag passed to aapt.
+
+The aapt -o flag instructs aapt to create an overlay package.
+Technically, this means the package will be assigned package id 0x00.
+
+There are no restrictions on overlay packages names, though the naming
+convention <original.package.name>.overlay.<name> is recommended.
+
+
+Example overlay package
+~~~~~~~~~~~~~~~~~~~~~~~
+
+To overlay the resource bool/b in package com.foo.bar, to be applied
+when the display is in landscape mode, create a new package with
+no source code and a single .xml file under res/values-land, with
+an entry for bool/b. Compile with aapt -o and place the results in
+/system/overlay by adding the following to Android.mk:
+
+LOCAL_AAPT_FLAGS := -o com.foo.bar
+LOCAL_MODULE_PATH := $(TARGET_OUT)/overlay
+
+
+The ID map (idmap) file format
+------------------------------
+
+The idmap format is designed for lookup performance. However, leading
+and trailing undefined overlay values are discarded to reduce the memory
+footprint.
+
+
+idmap grammar
+~~~~~~~~~~~~~
+All atoms (names in square brackets) are uint32_t integers. The
+idmap-magic constant spells "idmp" in ASCII. Offsets are given relative
+to the data_header, not to the beginning of the file.
+
+map := header data
+header := idmap-magic <crc32-original-pkg> <crc32-overlay-pkg>
+idmap-magic := <0x706d6469>
+data := data_header type_block+
+data_header := <m> header_block{m}
+header_block := <0> | <type_block_offset>
+type_block := <n> <id_offset> entry{n}
+entry := <resource_id_in_target_package>
+
+
+idmap example
+~~~~~~~~~~~~~
+Given a pair of target and overlay packages with CRC sums 0x216a8fe2
+and 0x6b9beaec, each defining the following resources
+
+Name Target package Overlay package
+string/str0 0x7f010000 -
+string/str1 0x7f010001 0x7f010000
+string/str2 0x7f010002 -
+string/str3 0x7f010003 0x7f010001
+string/str4 0x7f010004 -
+bool/bool0 0x7f020000 -
+integer/int0 0x7f030000 0x7f020000
+integer/int1 0x7f030001 -
+
+the corresponding resource map is
+
+0x706d6469 0x216a8fe2 0x6b9beaec 0x00000003 \
+0x00000004 0x00000000 0x00000009 0x00000003 \
+0x00000001 0x7f010000 0x00000000 0x7f010001 \
+0x00000001 0x00000000 0x7f020000
+
+or, formatted differently
+
+0x706d6469 # magic: all idmap files begin with this constant
+0x216a8fe2 # CRC32 of the resources.arsc file in the original package
+0x6b9beaec # CRC32 of the resources.arsc file in the overlay package
+0x00000003 # header; three types (string, bool, integer) in the target package
+0x00000004 # header_block for type 0 (string) is located at offset 4
+0x00000000 # no bool type exists in overlay package -> no header_block
+0x00000009 # header_block for type 2 (integer) is located at offset 9
+0x00000003 # header_block for string; overlay IDs span 3 elements
+0x00000001 # the first string in target package is entry 1 == offset
+0x7f010000 # target 0x7f01001 -> overlay 0x7f010000
+0x00000000 # str2 not defined in overlay package
+0x7f010001 # target 0x7f010003 -> overlay 0x7f010001
+0x00000001 # header_block for integer; overlay IDs span 1 element
+0x00000000 # offset == 0
+0x7f020000 # target 0x7f030000 -> overlay 0x7f020000
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index ac9cdf9f9f21..784c9d284d4d 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -63,6 +63,10 @@ namespace android {
#endif
#endif
+#define IDMAP_MAGIC 0x706d6469
+// size measured in sizeof(uint32_t)
+#define IDMAP_HEADER_SIZE (ResTable::IDMAP_HEADER_SIZE_BYTES / sizeof(uint32_t))
+
static void printToLogFunc(void* cookie, const char* txt)
{
LOGV("%s", txt);
@@ -214,6 +218,81 @@ static void deserializeInternal(const void* inData, Res_png_9patch* outData) {
outData->colors = (uint32_t*) data;
}
+static bool assertIdmapHeader(const uint32_t* map, size_t sizeBytes)
+{
+ if (sizeBytes < ResTable::IDMAP_HEADER_SIZE_BYTES) {
+ LOGW("idmap assertion failed: size=%d bytes\n", sizeBytes);
+ return false;
+ }
+ if (*map != htodl(IDMAP_MAGIC)) { // htodl: map data expected to be in correct endianess
+ LOGW("idmap assertion failed: invalid magic found (is 0x%08x, expected 0x%08x)\n",
+ *map, htodl(IDMAP_MAGIC));
+ return false;
+ }
+ return true;
+}
+
+static status_t idmapLookup(const uint32_t* map, size_t sizeBytes, uint32_t key, uint32_t* outValue)
+{
+ // see README for details on the format of map
+ if (!assertIdmapHeader(map, sizeBytes)) {
+ return UNKNOWN_ERROR;
+ }
+ map = map + IDMAP_HEADER_SIZE; // skip ahead to data segment
+ // size of data block, in uint32_t
+ const size_t size = (sizeBytes - ResTable::IDMAP_HEADER_SIZE_BYTES) / sizeof(uint32_t);
+ const uint32_t type = Res_GETTYPE(key) + 1; // add one, idmap stores "public" type id
+ const uint32_t entry = Res_GETENTRY(key);
+ const uint32_t typeCount = *map;
+
+ if (type > typeCount) {
+ LOGW("Resource ID map: type=%d exceeds number of types=%d\n", type, typeCount);
+ return UNKNOWN_ERROR;
+ }
+ if (typeCount > size) {
+ LOGW("Resource ID map: number of types=%d exceeds size of map=%d\n", typeCount, size);
+ return UNKNOWN_ERROR;
+ }
+ const uint32_t typeOffset = map[type];
+ if (typeOffset == 0) {
+ *outValue = 0;
+ return NO_ERROR;
+ }
+ if (typeOffset + 1 > size) {
+ LOGW("Resource ID map: type offset=%d exceeds reasonable value, size of map=%d\n",
+ typeOffset, size);
+ return UNKNOWN_ERROR;
+ }
+ const uint32_t entryCount = map[typeOffset];
+ const uint32_t entryOffset = map[typeOffset + 1];
+ if (entryCount == 0 || entry < entryOffset || entry - entryOffset > entryCount - 1) {
+ *outValue = 0;
+ return NO_ERROR;
+ }
+ const uint32_t index = typeOffset + 2 + entry - entryOffset;
+ if (index > size) {
+ LOGW("Resource ID map: entry index=%d exceeds size of map=%d\n", index, size);
+ *outValue = 0;
+ return NO_ERROR;
+ }
+ *outValue = map[index];
+
+ return NO_ERROR;
+}
+
+static status_t getIdmapPackageId(const uint32_t* map, size_t mapSize, uint32_t *outId)
+{
+ if (!assertIdmapHeader(map, mapSize)) {
+ return UNKNOWN_ERROR;
+ }
+ const uint32_t* p = map + IDMAP_HEADER_SIZE + 1;
+ while (*p == 0) {
+ ++p;
+ }
+ *outId = (map[*p + IDMAP_HEADER_SIZE + 2] >> 24) & 0x000000ff;
+ return NO_ERROR;
+}
+
Res_png_9patch* Res_png_9patch::deserialize(const void* inData)
{
if (sizeof(void*) != sizeof(int32_t)) {
@@ -1290,7 +1369,13 @@ status_t ResXMLTree::validateNode(const ResXMLTree_node* node) const
struct ResTable::Header
{
- Header(ResTable* _owner) : owner(_owner), ownedData(NULL), header(NULL) { }
+ Header(ResTable* _owner) : owner(_owner), ownedData(NULL), header(NULL),
+ resourceIDMap(NULL), resourceIDMapSize(0) { }
+
+ ~Header()
+ {
+ free(resourceIDMap);
+ }
ResTable* const owner;
void* ownedData;
@@ -1301,6 +1386,8 @@ struct ResTable::Header
void* cookie;
ResStringPool values;
+ uint32_t* resourceIDMap;
+ size_t resourceIDMapSize;
};
struct ResTable::Type
@@ -1716,12 +1803,13 @@ inline ssize_t ResTable::getResourcePackageIndex(uint32_t resID) const
return ((ssize_t)mPackageMap[Res_GETPACKAGE(resID)+1])-1;
}
-status_t ResTable::add(const void* data, size_t size, void* cookie, bool copyData)
+status_t ResTable::add(const void* data, size_t size, void* cookie, bool copyData,
+ const void* idmap)
{
- return add(data, size, cookie, NULL, copyData);
+ return add(data, size, cookie, NULL, copyData, reinterpret_cast<const Asset*>(idmap));
}
-status_t ResTable::add(Asset* asset, void* cookie, bool copyData)
+status_t ResTable::add(Asset* asset, void* cookie, bool copyData, const void* idmap)
{
const void* data = asset->getBuffer(true);
if (data == NULL) {
@@ -1729,7 +1817,7 @@ status_t ResTable::add(Asset* asset, void* cookie, bool copyData)
return UNKNOWN_ERROR;
}
size_t size = (size_t)asset->getLength();
- return add(data, size, cookie, asset, copyData);
+ return add(data, size, cookie, asset, copyData, reinterpret_cast<const Asset*>(idmap));
}
status_t ResTable::add(ResTable* src)
@@ -1757,19 +1845,30 @@ status_t ResTable::add(ResTable* src)
}
status_t ResTable::add(const void* data, size_t size, void* cookie,
- Asset* asset, bool copyData)
+ Asset* asset, bool copyData, const Asset* idmap)
{
if (!data) return NO_ERROR;
Header* header = new Header(this);
header->index = mHeaders.size();
header->cookie = cookie;
+ if (idmap != NULL) {
+ const size_t idmap_size = idmap->getLength();
+ const void* idmap_data = const_cast<Asset*>(idmap)->getBuffer(true);
+ header->resourceIDMap = (uint32_t*)malloc(idmap_size);
+ if (header->resourceIDMap == NULL) {
+ delete header;
+ return (mError = NO_MEMORY);
+ }
+ memcpy((void*)header->resourceIDMap, idmap_data, idmap_size);
+ header->resourceIDMapSize = idmap_size;
+ }
mHeaders.add(header);
const bool notDeviceEndian = htods(0xf0) != 0xf0;
LOAD_TABLE_NOISY(
- LOGV("Adding resources to ResTable: data=%p, size=0x%x, cookie=%p, asset=%p, copy=%d\n",
- data, size, cookie, asset, copyData));
+ LOGV("Adding resources to ResTable: data=%p, size=0x%x, cookie=%p, asset=%p, copy=%d "
+ "idmap=%p\n", data, size, cookie, asset, copyData, idmap));
if (copyData || notDeviceEndian) {
header->ownedData = malloc(size);
@@ -1836,7 +1935,16 @@ status_t ResTable::add(const void* data, size_t size, void* cookie,
dtohl(header->header->packageCount));
return (mError=BAD_TYPE);
}
- if (parsePackage((ResTable_package*)chunk, header) != NO_ERROR) {
+ uint32_t idmap_id = 0;
+ if (idmap != NULL) {
+ uint32_t tmp;
+ if (getIdmapPackageId(header->resourceIDMap,
+ header->resourceIDMapSize,
+ &tmp) == NO_ERROR) {
+ idmap_id = tmp;
+ }
+ }
+ if (parsePackage((ResTable_package*)chunk, header, idmap_id) != NO_ERROR) {
return mError;
}
curPackage++;
@@ -1858,6 +1966,7 @@ status_t ResTable::add(const void* data, size_t size, void* cookie,
if (mError != NO_ERROR) {
LOGW("No string values found in resource table!");
}
+
TABLE_NOISY(LOGV("Returning from add with mError=%d\n", mError));
return mError;
}
@@ -2002,17 +2111,38 @@ ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag
size_t ip = grp->packages.size();
while (ip > 0) {
ip--;
+ int T = t;
+ int E = e;
const Package* const package = grp->packages[ip];
+ if (package->header->resourceIDMap) {
+ uint32_t overlayResID = 0x0;
+ status_t retval = idmapLookup(package->header->resourceIDMap,
+ package->header->resourceIDMapSize,
+ resID, &overlayResID);
+ if (retval == NO_ERROR && overlayResID != 0x0) {
+ // for this loop iteration, this is the type and entry we really want
+ LOGV("resource map 0x%08x -> 0x%08x\n", resID, overlayResID);
+ T = Res_GETTYPE(overlayResID);
+ E = Res_GETENTRY(overlayResID);
+ } else {
+ // resource not present in overlay package, continue with the next package
+ continue;
+ }
+ }
const ResTable_type* type;
const ResTable_entry* entry;
const Type* typeClass;
- ssize_t offset = getEntry(package, t, e, desiredConfig, &type, &entry, &typeClass);
+ ssize_t offset = getEntry(package, T, E, desiredConfig, &type, &entry, &typeClass);
if (offset <= 0) {
- if (offset < 0) {
+ // No {entry, appropriate config} pair found in package. If this
+ // package is an overlay package (ip != 0), this simply means the
+ // overlay package did not specify a default.
+ // Non-overlay packages are still required to provide a default.
+ if (offset < 0 && ip == 0) {
LOGW("Failure getting entry for 0x%08x (t=%d e=%d) in package %zd (error %d)\n",
- resID, t, e, ip, (int)offset);
+ resID, T, E, ip, (int)offset);
rc = offset;
goto out;
}
@@ -2044,13 +2174,16 @@ ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag
if (outSpecFlags != NULL) {
if (typeClass->typeSpecFlags != NULL) {
- *outSpecFlags |= dtohl(typeClass->typeSpecFlags[e]);
+ *outSpecFlags |= dtohl(typeClass->typeSpecFlags[E]);
} else {
*outSpecFlags = -1;
}
}
-
- if (bestPackage != NULL && bestItem.isMoreSpecificThan(thisConfig)) {
+
+ if (bestPackage != NULL &&
+ (bestItem.isMoreSpecificThan(thisConfig) || bestItem.diff(thisConfig) == 0)) {
+ // Discard thisConfig not only if bestItem is more specific, but also if the two configs
+ // are identical (diff == 0), or overlay packages will not take effect.
continue;
}
@@ -2250,21 +2383,45 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
TABLE_NOISY(LOGI("Building bag: %p\n", (void*)resID));
+ ResTable_config bestConfig;
+ memset(&bestConfig, 0, sizeof(bestConfig));
+
// Now collect all bag attributes from all packages.
size_t ip = grp->packages.size();
while (ip > 0) {
ip--;
+ int T = t;
+ int E = e;
const Package* const package = grp->packages[ip];
+ if (package->header->resourceIDMap) {
+ uint32_t overlayResID = 0x0;
+ status_t retval = idmapLookup(package->header->resourceIDMap,
+ package->header->resourceIDMapSize,
+ resID, &overlayResID);
+ if (retval == NO_ERROR && overlayResID != 0x0) {
+ // for this loop iteration, this is the type and entry we really want
+ LOGV("resource map 0x%08x -> 0x%08x\n", resID, overlayResID);
+ T = Res_GETTYPE(overlayResID);
+ E = Res_GETENTRY(overlayResID);
+ } else {
+ // resource not present in overlay package, continue with the next package
+ continue;
+ }
+ }
const ResTable_type* type;
const ResTable_entry* entry;
const Type* typeClass;
- LOGV("Getting entry pkg=%p, t=%d, e=%d\n", package, t, e);
- ssize_t offset = getEntry(package, t, e, &mParams, &type, &entry, &typeClass);
+ LOGV("Getting entry pkg=%p, t=%d, e=%d\n", package, T, E);
+ ssize_t offset = getEntry(package, T, E, &mParams, &type, &entry, &typeClass);
LOGV("Resulting offset=%d\n", offset);
if (offset <= 0) {
- if (offset < 0) {
+ // No {entry, appropriate config} pair found in package. If this
+ // package is an overlay package (ip != 0), this simply means the
+ // overlay package did not specify a default.
+ // Non-overlay packages are still required to provide a default.
+ if (offset < 0 && ip == 0) {
if (set) free(set);
return offset;
}
@@ -2277,6 +2434,15 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
continue;
}
+ if (set != NULL && !type->config.isBetterThan(bestConfig, NULL)) {
+ continue;
+ }
+ bestConfig = type->config;
+ if (set) {
+ free(set);
+ set = NULL;
+ }
+
const uint16_t entrySize = dtohs(entry->size);
const uint32_t parent = entrySize >= sizeof(ResTable_map_entry)
? dtohl(((const ResTable_map_entry*)entry)->parent.ident) : 0;
@@ -2288,43 +2454,41 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
TABLE_NOISY(LOGI("Found map: size=%p parent=%p count=%d\n",
entrySize, parent, count));
- if (set == NULL) {
- // If this map inherits from another, we need to start
- // with its parent's values. Otherwise start out empty.
- TABLE_NOISY(printf("Creating new bag, entrySize=0x%08x, parent=0x%08x\n",
- entrySize, parent));
- if (parent) {
- const bag_entry* parentBag;
- uint32_t parentTypeSpecFlags = 0;
- const ssize_t NP = getBagLocked(parent, &parentBag, &parentTypeSpecFlags);
- const size_t NT = ((NP >= 0) ? NP : 0) + N;
- set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*NT);
- if (set == NULL) {
- return NO_MEMORY;
- }
- if (NP > 0) {
- memcpy(set+1, parentBag, NP*sizeof(bag_entry));
- set->numAttrs = NP;
- TABLE_NOISY(LOGI("Initialized new bag with %d inherited attributes.\n", NP));
- } else {
- TABLE_NOISY(LOGI("Initialized new bag with no inherited attributes.\n"));
- set->numAttrs = 0;
- }
- set->availAttrs = NT;
- set->typeSpecFlags = parentTypeSpecFlags;
+ // If this map inherits from another, we need to start
+ // with its parent's values. Otherwise start out empty.
+ TABLE_NOISY(printf("Creating new bag, entrySize=0x%08x, parent=0x%08x\n",
+ entrySize, parent));
+ if (parent) {
+ const bag_entry* parentBag;
+ uint32_t parentTypeSpecFlags = 0;
+ const ssize_t NP = getBagLocked(parent, &parentBag, &parentTypeSpecFlags);
+ const size_t NT = ((NP >= 0) ? NP : 0) + N;
+ set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*NT);
+ if (set == NULL) {
+ return NO_MEMORY;
+ }
+ if (NP > 0) {
+ memcpy(set+1, parentBag, NP*sizeof(bag_entry));
+ set->numAttrs = NP;
+ TABLE_NOISY(LOGI("Initialized new bag with %d inherited attributes.\n", NP));
} else {
- set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*N);
- if (set == NULL) {
- return NO_MEMORY;
- }
+ TABLE_NOISY(LOGI("Initialized new bag with no inherited attributes.\n"));
set->numAttrs = 0;
- set->availAttrs = N;
- set->typeSpecFlags = 0;
}
+ set->availAttrs = NT;
+ set->typeSpecFlags = parentTypeSpecFlags;
+ } else {
+ set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*N);
+ if (set == NULL) {
+ return NO_MEMORY;
+ }
+ set->numAttrs = 0;
+ set->availAttrs = N;
+ set->typeSpecFlags = 0;
}
if (typeClass->typeSpecFlags != NULL) {
- set->typeSpecFlags |= dtohl(typeClass->typeSpecFlags[e]);
+ set->typeSpecFlags |= dtohl(typeClass->typeSpecFlags[E]);
} else {
set->typeSpecFlags = -1;
}
@@ -3870,7 +4034,7 @@ ssize_t ResTable::getEntry(
}
status_t ResTable::parsePackage(const ResTable_package* const pkg,
- const Header* const header)
+ const Header* const header, uint32_t idmap_id)
{
const uint8_t* base = (const uint8_t*)pkg;
status_t err = validate_chunk(&pkg->header, sizeof(*pkg),
@@ -3904,8 +4068,12 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
Package* package = NULL;
PackageGroup* group = NULL;
- uint32_t id = dtohl(pkg->id);
- if (id != 0 && id < 256) {
+ uint32_t id = idmap_id != 0 ? idmap_id : dtohl(pkg->id);
+ // If at this point id == 0, pkg is an overlay package without a
+ // corresponding idmap. During regular usage, overlay packages are
+ // always loaded alongside their idmaps, but during idmap creation
+ // the package is temporarily loaded by itself.
+ if (id < 256) {
package = new Package(this, header, pkg);
if (package == NULL) {
@@ -3958,7 +4126,7 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
return (mError=err);
}
} else {
- LOG_ALWAYS_FATAL("Skins not supported!");
+ LOG_ALWAYS_FATAL("Package id out of range");
return NO_ERROR;
}
@@ -4112,6 +4280,136 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
return NO_ERROR;
}
+status_t ResTable::createIdmap(const ResTable& overlay, uint32_t originalCrc, uint32_t overlayCrc,
+ void** outData, size_t* outSize) const
+{
+ // see README for details on the format of map
+ if (mPackageGroups.size() == 0) {
+ return UNKNOWN_ERROR;
+ }
+ if (mPackageGroups[0]->packages.size() == 0) {
+ return UNKNOWN_ERROR;
+ }
+
+ Vector<Vector<uint32_t> > map;
+ const PackageGroup* pg = mPackageGroups[0];
+ const Package* pkg = pg->packages[0];
+ size_t typeCount = pkg->types.size();
+ // starting size is header + first item (number of types in map)
+ *outSize = (IDMAP_HEADER_SIZE + 1) * sizeof(uint32_t);
+ const String16 overlayPackage(overlay.mPackageGroups[0]->packages[0]->package->name);
+ const uint32_t pkg_id = pkg->package->id << 24;
+
+ for (size_t typeIndex = 0; typeIndex < typeCount; ++typeIndex) {
+ ssize_t offset = -1;
+ const Type* typeConfigs = pkg->getType(typeIndex);
+ ssize_t mapIndex = map.add();
+ if (mapIndex < 0) {
+ return NO_MEMORY;
+ }
+ Vector<uint32_t>& vector = map.editItemAt(mapIndex);
+ for (size_t entryIndex = 0; entryIndex < typeConfigs->entryCount; ++entryIndex) {
+ uint32_t resID = (0xff000000 & ((pkg->package->id)<<24))
+ | (0x00ff0000 & ((typeIndex+1)<<16))
+ | (0x0000ffff & (entryIndex));
+ resource_name resName;
+ if (!this->getResourceName(resID, &resName)) {
+ return UNKNOWN_ERROR;
+ }
+
+ const String16 overlayType(resName.type, resName.typeLen);
+ const String16 overlayName(resName.name, resName.nameLen);
+ uint32_t overlayResID = overlay.identifierForName(overlayName.string(),
+ overlayName.size(),
+ overlayType.string(),
+ overlayType.size(),
+ overlayPackage.string(),
+ overlayPackage.size());
+ if (overlayResID != 0) {
+ // overlay package has package ID == 0, use original package's ID instead
+ overlayResID |= pkg_id;
+ }
+ vector.push(overlayResID);
+ if (overlayResID != 0 && offset == -1) {
+ offset = Res_GETENTRY(resID);
+ }
+#if 0
+ if (overlayResID != 0) {
+ LOGD("%s/%s 0x%08x -> 0x%08x\n",
+ String8(String16(resName.type)).string(),
+ String8(String16(resName.name)).string(),
+ resID, overlayResID);
+ }
+#endif
+ }
+
+ if (offset != -1) {
+ // shave off leading and trailing entries which lack overlay values
+ vector.removeItemsAt(0, offset);
+ vector.insertAt((uint32_t)offset, 0, 1);
+ while (vector.top() == 0) {
+ vector.pop();
+ }
+ // reserve space for number and offset of entries, and the actual entries
+ *outSize += (2 + vector.size()) * sizeof(uint32_t);
+ } else {
+ // no entries of current type defined in overlay package
+ vector.clear();
+ // reserve space for type offset
+ *outSize += 1 * sizeof(uint32_t);
+ }
+ }
+
+ if ((*outData = malloc(*outSize)) == NULL) {
+ return NO_MEMORY;
+ }
+ uint32_t* data = (uint32_t*)*outData;
+ *data++ = htodl(IDMAP_MAGIC);
+ *data++ = htodl(originalCrc);
+ *data++ = htodl(overlayCrc);
+ const size_t mapSize = map.size();
+ *data++ = htodl(mapSize);
+ size_t offset = mapSize;
+ for (size_t i = 0; i < mapSize; ++i) {
+ const Vector<uint32_t>& vector = map.itemAt(i);
+ const size_t N = vector.size();
+ if (N == 0) {
+ *data++ = htodl(0);
+ } else {
+ offset++;
+ *data++ = htodl(offset);
+ offset += N;
+ }
+ }
+ for (size_t i = 0; i < mapSize; ++i) {
+ const Vector<uint32_t>& vector = map.itemAt(i);
+ const size_t N = vector.size();
+ if (N == 0) {
+ continue;
+ }
+ *data++ = htodl(N - 1); // do not count the offset (which is vector's first element)
+ for (size_t j = 0; j < N; ++j) {
+ const uint32_t& overlayResID = vector.itemAt(j);
+ *data++ = htodl(overlayResID);
+ }
+ }
+
+ return NO_ERROR;
+}
+
+bool ResTable::getIdmapInfo(const void* idmap, size_t sizeBytes,
+ uint32_t* pOriginalCrc, uint32_t* pOverlayCrc)
+{
+ const uint32_t* map = (const uint32_t*)idmap;
+ if (!assertIdmapHeader(map, sizeBytes)) {
+ return false;
+ }
+ *pOriginalCrc = map[1];
+ *pOverlayCrc = map[2];
+ return true;
+}
+
+
#ifndef HAVE_ANDROID_OS
#define CHAR16_TO_CSTR(c16, len) (String8(String16(c16,len)).string())
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 9d0cba373911..504cfde2111c 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -111,6 +111,7 @@ public class AudioService extends IAudioService.Stub {
private static final int MSG_BTA2DP_DOCK_TIMEOUT = 8;
private static final int MSG_LOAD_SOUND_EFFECTS = 9;
private static final int MSG_SET_FORCE_USE = 10;
+ private static final int MSG_PERSIST_MEDIABUTTONRECEIVER = 11;
private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
@@ -355,6 +356,12 @@ public class AudioService extends IAudioService.Stub {
intentFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
context.registerReceiver(mReceiver, intentFilter);
+ // Register for package removal intent broadcasts for media button receiver persistence
+ IntentFilter pkgFilter = new IntentFilter();
+ pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ pkgFilter.addDataScheme("package");
+ context.registerReceiver(mReceiver, pkgFilter);
+
// Register for media button intent broadcasts.
intentFilter = new IntentFilter(Intent.ACTION_MEDIA_BUTTON);
intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
@@ -444,6 +451,9 @@ public class AudioService extends IAudioService.Stub {
// Broadcast vibrate settings
broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
+
+ // Restore the default media button receiver from the system settings
+ restoreMediaButtonReceiver();
}
private void setStreamVolumeIndex(int stream, int index) {
@@ -1912,6 +1922,11 @@ public class AudioService extends IAudioService.Stub {
}
}
+ private void persistMediaButtonReceiver(ComponentName receiver) {
+ Settings.System.putString(mContentResolver, Settings.System.MEDIA_BUTTON_RECEIVER,
+ receiver == null ? "" : receiver.flattenToString());
+ }
+
private void cleanupPlayer(MediaPlayer mp) {
if (mp != null) {
try {
@@ -2022,6 +2037,10 @@ public class AudioService extends IAudioService.Stub {
case MSG_SET_FORCE_USE:
setForceUse(msg.arg1, msg.arg2);
break;
+
+ case MSG_PERSIST_MEDIABUTTONRECEIVER:
+ persistMediaButtonReceiver( (ComponentName) msg.obj );
+ break;
}
}
}
@@ -2354,6 +2373,14 @@ public class AudioService extends IAudioService.Stub {
newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
mContext.sendStickyBroadcast(newIntent);
+ } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
+ if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+ // a package is being removed, not replaced
+ String packageName = intent.getData().getSchemeSpecificPart();
+ if (packageName != null) {
+ removeMediaButtonReceiverForPackage(packageName);
+ }
+ }
}
}
}
@@ -2469,7 +2496,7 @@ public class AudioService extends IAudioService.Stub {
if(fse.mClientId.equals(clientToRemove)) {
Log.i(TAG, " AudioFocus abandonAudioFocus(): removing entry for "
+ fse.mClientId);
- mFocusStack.remove(fse);
+ stackIterator.remove();
}
}
}
@@ -2489,7 +2516,7 @@ public class AudioService extends IAudioService.Stub {
if(fse.mSourceRef.equals(cb)) {
Log.i(TAG, " AudioFocus abandonAudioFocus(): removing entry for "
+ fse.mClientId);
- mFocusStack.remove(fse);
+ stackIterator.remove();
}
}
if (isTopOfStackForClientToRemove) {
@@ -2701,6 +2728,56 @@ public class AudioService extends IAudioService.Stub {
/**
* Helper function:
+ * Remove any entry in the remote control stack that has the same package name as packageName
+ * Pre-condition: packageName != null
+ */
+ private void removeMediaButtonReceiverForPackage(String packageName) {
+ synchronized(mRCStack) {
+ if (mRCStack.empty()) {
+ return;
+ } else {
+ RemoteControlStackEntry oldTop = mRCStack.peek();
+ Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
+ // iterate over the stack entries
+ while(stackIterator.hasNext()) {
+ RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next();
+ if (packageName.equalsIgnoreCase(rcse.mReceiverComponent.getPackageName())) {
+ // a stack entry is from the package being removed, remove it from the stack
+ stackIterator.remove();
+ }
+ }
+ if (mRCStack.empty()) {
+ // no saved media button receiver
+ mAudioHandler.sendMessage(
+ mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0,
+ null));
+ return;
+ } else if (oldTop != mRCStack.peek()) {
+ // the top of the stack has changed, save it in the system settings
+ // by posting a message to persist it
+ mAudioHandler.sendMessage(
+ mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0,
+ mRCStack.peek().mReceiverComponent));
+ }
+ }
+ }
+ }
+
+ /**
+ * Helper function:
+ * Restore remote control receiver from the system settings
+ */
+ private void restoreMediaButtonReceiver() {
+ String receiverName = Settings.System.getString(mContentResolver,
+ Settings.System.MEDIA_BUTTON_RECEIVER);
+ if ((null != receiverName) && !receiverName.isEmpty()) {
+ ComponentName receiverComponentName = ComponentName.unflattenFromString(receiverName);
+ registerMediaButtonEventReceiver(receiverComponentName);
+ }
+ }
+
+ /**
+ * Helper function:
* Set the new remote control receiver at the top of the RC focus stack
*/
private void pushMediaButtonReceiver(ComponentName newReceiver) {
@@ -2712,11 +2789,15 @@ public class AudioService extends IAudioService.Stub {
while(stackIterator.hasNext()) {
RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next();
if(rcse.mReceiverComponent.equals(newReceiver)) {
- mRCStack.remove(rcse);
+ stackIterator.remove();
break;
}
}
mRCStack.push(new RemoteControlStackEntry(newReceiver));
+
+ // post message to persist the default media button receiver
+ mAudioHandler.sendMessage( mAudioHandler.obtainMessage(
+ MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, newReceiver/*obj*/) );
}
/**
@@ -2728,7 +2809,7 @@ public class AudioService extends IAudioService.Stub {
while(stackIterator.hasNext()) {
RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next();
if(rcse.mReceiverComponent.equals(newReceiver)) {
- mRCStack.remove(rcse);
+ stackIterator.remove();
break;
}
}
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 0b0d145a6a20..1e4b58520240 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1120,6 +1120,7 @@ public class MediaPlayer
mOnErrorListener = null;
mOnInfoListener = null;
mOnVideoSizeChangedListener = null;
+ mOnTimedTextListener = null;
_release();
}
@@ -1301,6 +1302,7 @@ public class MediaPlayer
private static final int MEDIA_BUFFERING_UPDATE = 3;
private static final int MEDIA_SEEK_COMPLETE = 4;
private static final int MEDIA_SET_VIDEO_SIZE = 5;
+ private static final int MEDIA_TIMED_TEXT = 99;
private static final int MEDIA_ERROR = 100;
private static final int MEDIA_INFO = 200;
@@ -1369,6 +1371,11 @@ public class MediaPlayer
}
// No real default action so far.
return;
+ case MEDIA_TIMED_TEXT:
+ if (mOnTimedTextListener != null) {
+ mOnTimedTextListener.onTimedText(mMediaPlayer, (String)msg.obj);
+ }
+ return;
case MEDIA_NOP: // interface test message - ignore
break;
@@ -1545,6 +1552,39 @@ public class MediaPlayer
private OnVideoSizeChangedListener mOnVideoSizeChangedListener;
+ /**
+ * Interface definition of a callback to be invoked when a
+ * timed text is available for display.
+ * {@hide}
+ */
+ public interface OnTimedTextListener
+ {
+ /**
+ * Called to indicate the video size
+ *
+ * @param mp the MediaPlayer associated with this callback
+ * @param text the timed text sample which contains the
+ * text needed to be displayed.
+ * {@hide}
+ */
+ public void onTimedText(MediaPlayer mp, String text);
+ }
+
+ /**
+ * Register a callback to be invoked when a timed text is available
+ * for display.
+ *
+ * @param listener the callback that will be run
+ * {@hide}
+ */
+ public void setOnTimedTextListener(OnTimedTextListener listener)
+ {
+ mOnTimedTextListener = listener;
+ }
+
+ private OnTimedTextListener mOnTimedTextListener;
+
+
/* Do not change these values without updating their counterparts
* in include/media/mediaplayer.h!
*/
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index a2196234aeb3..2ba9b3f53309 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -241,7 +241,7 @@ static void android_media_MediaMetadataRetriever_setDataSourceFD(JNIEnv *env, jo
jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
return;
}
- int fd = getParcelFileDescriptorFD(env, fileDescriptor);
+ int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
if (offset < 0 || length < 0 || fd < 0) {
if (offset < 0) {
LOGE("negative offset (%lld)", offset);
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index ecbd288db3cf..23a77d400a76 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -69,7 +69,7 @@ class JNIMediaPlayerListener: public MediaPlayerListener
public:
JNIMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz);
~JNIMediaPlayerListener();
- void notify(int msg, int ext1, int ext2);
+ virtual void notify(int msg, int ext1, int ext2, const Parcel *obj = NULL);
private:
JNIMediaPlayerListener();
jclass mClass; // Reference to MediaPlayer class
@@ -102,10 +102,23 @@ JNIMediaPlayerListener::~JNIMediaPlayerListener()
env->DeleteGlobalRef(mClass);
}
-void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2)
+void JNIMediaPlayerListener::notify(int msg, int ext1, int ext2, const Parcel *obj)
{
JNIEnv *env = AndroidRuntime::getJNIEnv();
- env->CallStaticVoidMethod(mClass, fields.post_event, mObject, msg, ext1, ext2, 0);
+ if (obj && obj->dataSize() > 0) {
+ jbyteArray jArray = env->NewByteArray(obj->dataSize());
+ if (jArray != NULL) {
+ jbyte *nArray = env->GetByteArrayElements(jArray, NULL);
+ memcpy(nArray, obj->data(), obj->dataSize());
+ env->ReleaseByteArrayElements(jArray, nArray, 0);
+ env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
+ msg, ext1, ext2, jArray);
+ env->DeleteLocalRef(jArray);
+ }
+ } else {
+ env->CallStaticVoidMethod(mClass, fields.post_event, mObject,
+ msg, ext1, ext2, NULL);
+ }
}
// ----------------------------------------------------------------------------
@@ -325,7 +338,7 @@ android_media_MediaPlayer_setDataSourceFD(JNIEnv *env, jobject thiz, jobject fil
jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
return;
}
- int fd = getParcelFileDescriptorFD(env, fileDescriptor);
+ int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
LOGV("setDataSourceFD: fd %d", fd);
process_media_player_call( env, thiz, mp->setDataSource(fd, offset, length), "java/io/IOException", "setDataSourceFD failed." );
}
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index a8a46c107acd..2c246958e955 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -253,7 +253,7 @@ android_media_MediaRecorder_setOutputFileFD(JNIEnv *env, jobject thiz, jobject f
jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
return;
}
- int fd = getParcelFileDescriptorFD(env, fileDescriptor);
+ int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
status_t opStatus = mr->setOutputFile(fd, offset, length);
process_media_recorder_call(env, opStatus, "java/io/IOException", "setOutputFile failed.");
@@ -267,7 +267,7 @@ android_media_MediaRecorder_setOutputFileAuxFD(JNIEnv *env, jobject thiz, jobjec
jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
return;
}
- int fd = getParcelFileDescriptorFD(env, fileDescriptor);
+ int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
status_t opStatus = mr->setOutputFileAuxiliary(fd);
process_media_recorder_call(env, opStatus, "java/io/IOException", "setOutputFile failed.");
@@ -404,38 +404,32 @@ android_media_MediaRecorder_native_init(JNIEnv *env)
clazz = env->FindClass("android/media/MediaRecorder");
if (clazz == NULL) {
- jniThrowException(env, "java/lang/RuntimeException", "Can't find android/media/MediaRecorder");
return;
}
fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
if (fields.context == NULL) {
- jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaRecorder.mNativeContext");
return;
}
fields.surface = env->GetFieldID(clazz, "mSurface", "Landroid/view/Surface;");
if (fields.surface == NULL) {
- jniThrowException(env, "java/lang/RuntimeException", "Can't find MediaRecorder.mSurface");
return;
}
jclass surface = env->FindClass("android/view/Surface");
if (surface == NULL) {
- jniThrowException(env, "java/lang/RuntimeException", "Can't find android/view/Surface");
return;
}
fields.surface_native = env->GetFieldID(surface, ANDROID_VIEW_SURFACE_JNI_ID, "I");
if (fields.surface_native == NULL) {
- jniThrowException(env, "java/lang/RuntimeException", "Can't find Surface.mSurface");
return;
}
fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
"(Ljava/lang/Object;IIILjava/lang/Object;)V");
if (fields.post_event == NULL) {
- jniThrowException(env, "java/lang/RuntimeException", "MediaRecorder.postEventFromNative");
return;
}
}
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index 06058dc44c8d..a3dd1367a53c 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -303,7 +303,7 @@ android_media_MediaScanner_extractAlbumArt(
return NULL;
}
- int fd = getParcelFileDescriptorFD(env, fileDescriptor);
+ int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
char* data = mp->extractAlbumArt(fd);
if (!data) {
return NULL;
@@ -335,15 +335,11 @@ android_media_MediaScanner_native_init(JNIEnv *env)
LOGV("native_init");
jclass clazz = env->FindClass(kClassMediaScanner);
if (clazz == NULL) {
- const char* err = "Can't find android/media/MediaScanner";
- jniThrowException(env, kRunTimeException, err);
return;
}
fields.context = env->GetFieldID(clazz, "mNativeContext", "I");
if (fields.context == NULL) {
- const char* err = "Can't find MediaScanner.mNativeContext";
- jniThrowException(env, kRunTimeException, err);
return;
}
}
@@ -426,5 +422,3 @@ int register_android_media_MediaScanner(JNIEnv *env)
return AndroidRuntime::registerNativeMethods(env,
kClassMediaScanner, gMethods, NELEM(gMethods));
}
-
-
diff --git a/media/jni/soundpool/android_media_SoundPool.cpp b/media/jni/soundpool/android_media_SoundPool.cpp
index 447f9319504f..03d33884ee5c 100644
--- a/media/jni/soundpool/android_media_SoundPool.cpp
+++ b/media/jni/soundpool/android_media_SoundPool.cpp
@@ -60,7 +60,7 @@ android_media_SoundPool_load_FD(JNIEnv *env, jobject thiz, jobject fileDescripto
LOGV("android_media_SoundPool_load_FD");
SoundPool *ap = MusterSoundPool(env, thiz);
if (ap == NULL) return 0;
- return ap->load(getParcelFileDescriptorFD(env, fileDescriptor),
+ return ap->load(jniGetFDFromFileDescriptor(env, fileDescriptor),
int64_t(offset), int64_t(length), int(priority));
}
diff --git a/media/libmedia/IMediaPlayerClient.cpp b/media/libmedia/IMediaPlayerClient.cpp
index bf51829baff4..1f135c4942eb 100644
--- a/media/libmedia/IMediaPlayerClient.cpp
+++ b/media/libmedia/IMediaPlayerClient.cpp
@@ -35,13 +35,16 @@ public:
{
}
- virtual void notify(int msg, int ext1, int ext2)
+ virtual void notify(int msg, int ext1, int ext2, const Parcel *obj)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerClient::getInterfaceDescriptor());
data.writeInt32(msg);
data.writeInt32(ext1);
data.writeInt32(ext2);
+ if (obj && obj->dataSize() > 0) {
+ data.appendFrom(const_cast<Parcel *>(obj), 0, obj->dataSize());
+ }
remote()->transact(NOTIFY, data, &reply, IBinder::FLAG_ONEWAY);
}
};
@@ -59,7 +62,12 @@ status_t BnMediaPlayerClient::onTransact(
int msg = data.readInt32();
int ext1 = data.readInt32();
int ext2 = data.readInt32();
- notify(msg, ext1, ext2);
+ Parcel obj;
+ if (data.dataAvail() > 0) {
+ obj.appendFrom(const_cast<Parcel *>(&data), data.dataPosition(), data.dataAvail());
+ }
+
+ notify(msg, ext1, ext2, &obj);
return NO_ERROR;
} break;
default:
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 0ee0249a6773..e80e74266b21 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -551,7 +551,7 @@ status_t MediaPlayer::attachAuxEffect(int effectId)
return mPlayer->attachAuxEffect(effectId);
}
-void MediaPlayer::notify(int msg, int ext1, int ext2)
+void MediaPlayer::notify(int msg, int ext1, int ext2, const Parcel *obj)
{
LOGV("message received msg=%d, ext1=%d, ext2=%d", msg, ext1, ext2);
bool send = true;
@@ -641,6 +641,9 @@ void MediaPlayer::notify(int msg, int ext1, int ext2)
mVideoWidth = ext1;
mVideoHeight = ext2;
break;
+ case MEDIA_TIMED_TEXT:
+ LOGV("Received timed text message");
+ break;
default:
LOGV("unrecognized message: (%d, %d, %d)", msg, ext1, ext2);
break;
@@ -653,7 +656,7 @@ void MediaPlayer::notify(int msg, int ext1, int ext2)
if ((listener != 0) && send) {
Mutex::Autolock _l(mNotifyLock);
LOGV("callback application");
- listener->notify(msg, ext1, ext2);
+ listener->notify(msg, ext1, ext2, obj);
LOGV("back from callback");
}
}
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 9c9ac9715459..6b977085d83e 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1022,7 +1022,8 @@ status_t MediaPlayerService::Client::attachAuxEffect(int effectId)
return NO_ERROR;
}
-void MediaPlayerService::Client::notify(void* cookie, int msg, int ext1, int ext2)
+void MediaPlayerService::Client::notify(
+ void* cookie, int msg, int ext1, int ext2, const Parcel *obj)
{
Client* client = static_cast<Client*>(cookie);
@@ -1039,7 +1040,7 @@ void MediaPlayerService::Client::notify(void* cookie, int msg, int ext1, int ext
client->addNewMetadataUpdate(metadata_type);
}
LOGV("[%d] notify (%p, %d, %d, %d)", client->mConnId, cookie, msg, ext1, ext2);
- client->mClient->notify(msg, ext1, ext2);
+ client->mClient->notify(msg, ext1, ext2, obj);
}
@@ -1623,7 +1624,8 @@ status_t MediaPlayerService::AudioCache::wait()
return mError;
}
-void MediaPlayerService::AudioCache::notify(void* cookie, int msg, int ext1, int ext2)
+void MediaPlayerService::AudioCache::notify(
+ void* cookie, int msg, int ext1, int ext2, const Parcel *obj)
{
LOGV("notify(%p, %d, %d, %d)", cookie, msg, ext1, ext2);
AudioCache* p = static_cast<AudioCache*>(cookie);
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index ff6ccf542a9c..5539a37affea 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -156,7 +156,8 @@ class MediaPlayerService : public BnMediaPlayerService
sp<IMemoryHeap> getHeap() const { return mHeap; }
- static void notify(void* cookie, int msg, int ext1, int ext2);
+ static void notify(void* cookie, int msg,
+ int ext1, int ext2, const Parcel *obj);
virtual status_t dump(int fd, const Vector<String16>& args) const;
private:
@@ -287,7 +288,8 @@ private:
status_t setDataSource(const sp<IStreamSource> &source);
- static void notify(void* cookie, int msg, int ext1, int ext2);
+ static void notify(void* cookie, int msg,
+ int ext1, int ext2, const Parcel *obj);
pid_t pid() const { return mPid; }
virtual status_t dump(int fd, const Vector<String16>& args) const;
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 93d423632d07..1bfdd8eaa880 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define DEBUG_HDCP
+#undef DEBUG_HDCP
//#define LOG_NDEBUG 0
#define LOG_TAG "AwesomePlayer"
@@ -184,7 +184,8 @@ AwesomePlayer::AwesomePlayer()
mFlags(0),
mExtractorFlags(0),
mVideoBuffer(NULL),
- mDecryptHandle(NULL) {
+ mDecryptHandle(NULL),
+ mLastVideoTimeUs(-1) {
CHECK_EQ(mClient.connect(), (status_t)OK);
DataSource::RegisterDefaultSniffers();
@@ -470,28 +471,13 @@ void AwesomePlayer::reset_l() {
mVideoRenderer.clear();
- if (mVideoBuffer) {
- mVideoBuffer->release();
- mVideoBuffer = NULL;
- }
-
if (mRTSPController != NULL) {
mRTSPController->disconnect();
mRTSPController.clear();
}
if (mVideoSource != NULL) {
- mVideoSource->stop();
-
- // The following hack is necessary to ensure that the OMX
- // component is completely released by the time we may try
- // to instantiate it again.
- wp<MediaSource> tmp = mVideoSource;
- mVideoSource.clear();
- while (tmp.promote() != NULL) {
- usleep(1000);
- }
- IPCThreadState::self()->flushCommands();
+ shutdownVideoDecoder_l();
}
mDurationUs = -1;
@@ -510,6 +496,7 @@ void AwesomePlayer::reset_l() {
mFileSource.clear();
mBitrate = -1;
+ mLastVideoTimeUs = -1;
}
void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
@@ -1012,7 +999,7 @@ void AwesomePlayer::setSurface(const sp<Surface> &surface) {
Mutex::Autolock autoLock(mLock);
mSurface = surface;
- mNativeWindow = surface;
+ setNativeWindow_l(surface);
}
void AwesomePlayer::setSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture) {
@@ -1020,9 +1007,57 @@ void AwesomePlayer::setSurfaceTexture(const sp<ISurfaceTexture> &surfaceTexture)
mSurface.clear();
if (surfaceTexture != NULL) {
- mNativeWindow = new SurfaceTextureClient(surfaceTexture);
+ setNativeWindow_l(new SurfaceTextureClient(surfaceTexture));
}
+}
+void AwesomePlayer::shutdownVideoDecoder_l() {
+ if (mVideoBuffer) {
+ mVideoBuffer->release();
+ mVideoBuffer = NULL;
+ }
+
+ mVideoSource->stop();
+
+ // The following hack is necessary to ensure that the OMX
+ // component is completely released by the time we may try
+ // to instantiate it again.
+ wp<MediaSource> tmp = mVideoSource;
+ mVideoSource.clear();
+ while (tmp.promote() != NULL) {
+ usleep(1000);
+ }
+ IPCThreadState::self()->flushCommands();
+}
+
+void AwesomePlayer::setNativeWindow_l(const sp<ANativeWindow> &native) {
+ mNativeWindow = native;
+
+ if (mVideoSource == NULL) {
+ return;
+ }
+
+ LOGI("attempting to reconfigure to use new surface");
+
+ bool wasPlaying = (mFlags & PLAYING) != 0;
+
+ pause_l();
+ mVideoRenderer.clear();
+
+ shutdownVideoDecoder_l();
+
+ CHECK_EQ(initVideoDecoder(), (status_t)OK);
+
+ if (mLastVideoTimeUs >= 0) {
+ mSeeking = SEEK;
+ mSeekNotificationSent = true;
+ mSeekTimeUs = mLastVideoTimeUs;
+ mFlags &= ~(AT_EOS | AUDIO_AT_EOS | VIDEO_AT_EOS);
+ }
+
+ if (wasPlaying) {
+ play_l();
+ }
}
void AwesomePlayer::setAudioSink(
@@ -1412,6 +1447,8 @@ void AwesomePlayer::onVideoEvent() {
int64_t timeUs;
CHECK(mVideoBuffer->meta_data()->findInt64(kKeyTime, &timeUs));
+ mLastVideoTimeUs = timeUs;
+
if (mSeeking == SEEK_VIDEO_ONLY) {
if (mSeekTimeUs > timeUs) {
LOGI("XXX mSeekTimeUs = %lld us, timeUs = %lld us",
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 1ca2d6d73355..f9db1a1bdec6 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -377,7 +377,7 @@ status_t MPEG4Extractor::readMetaData() {
mFileMetaData->setCString(kKeyMIMEType, "audio/mp4");
}
- mInitCheck = verifyIfStreamable();
+ mInitCheck = OK;
} else {
mInitCheck = err;
}
@@ -1904,7 +1904,7 @@ status_t MPEG4Source::read(
off64_t offset;
size_t size;
- uint32_t dts;
+ uint32_t cts;
bool isSyncSample;
bool newBuffer = false;
if (mBuffer == NULL) {
@@ -1912,7 +1912,7 @@ status_t MPEG4Source::read(
status_t err =
mSampleTable->getMetaDataForSample(
- mCurrentSampleIndex, &offset, &size, &dts, &isSyncSample);
+ mCurrentSampleIndex, &offset, &size, &cts, &isSyncSample);
if (err != OK) {
return err;
@@ -1942,7 +1942,7 @@ status_t MPEG4Source::read(
mBuffer->set_range(0, size);
mBuffer->meta_data()->clear();
mBuffer->meta_data()->setInt64(
- kKeyTime, ((int64_t)dts * 1000000) / mTimescale);
+ kKeyTime, ((int64_t)cts * 1000000) / mTimescale);
if (targetSampleTimeUs >= 0) {
mBuffer->meta_data()->setInt64(
@@ -2060,7 +2060,7 @@ status_t MPEG4Source::read(
mBuffer->meta_data()->clear();
mBuffer->meta_data()->setInt64(
- kKeyTime, ((int64_t)dts * 1000000) / mTimescale);
+ kKeyTime, ((int64_t)cts * 1000000) / mTimescale);
if (targetSampleTimeUs >= 0) {
mBuffer->meta_data()->setInt64(
@@ -2094,87 +2094,6 @@ MPEG4Extractor::Track *MPEG4Extractor::findTrackByMimePrefix(
return NULL;
}
-status_t MPEG4Extractor::verifyIfStreamable() {
- if (!(mDataSource->flags() & DataSource::kIsCachingDataSource)) {
- return OK;
- }
-
- Track *audio = findTrackByMimePrefix("audio/");
- Track *video = findTrackByMimePrefix("video/");
-
- if (audio == NULL || video == NULL) {
- return OK;
- }
-
- sp<SampleTable> audioSamples = audio->sampleTable;
- sp<SampleTable> videoSamples = video->sampleTable;
-
- off64_t maxOffsetDiff = 0;
- int64_t maxOffsetTimeUs = -1;
-
- for (uint32_t i = 0; i < videoSamples->countSamples(); ++i) {
- off64_t videoOffset;
- uint32_t videoTime;
- bool isSync;
- CHECK_EQ((status_t)OK, videoSamples->getMetaDataForSample(
- i, &videoOffset, NULL, &videoTime, &isSync));
-
- int64_t videoTimeUs = (int64_t)(videoTime * 1E6 / video->timescale);
-
- uint32_t reqAudioTime = (videoTimeUs * audio->timescale) / 1000000;
- uint32_t j;
- if (audioSamples->findSampleAtTime(
- reqAudioTime, &j, SampleTable::kFlagClosest) != OK) {
- continue;
- }
-
- off64_t audioOffset;
- uint32_t audioTime;
- CHECK_EQ((status_t)OK, audioSamples->getMetaDataForSample(
- j, &audioOffset, NULL, &audioTime));
-
- int64_t audioTimeUs = (int64_t)(audioTime * 1E6 / audio->timescale);
-
- off64_t offsetDiff = videoOffset - audioOffset;
- if (offsetDiff < 0) {
- offsetDiff = -offsetDiff;
- }
-
-#if 0
- printf("%s%d/%d videoTime %.2f secs audioTime %.2f secs "
- "videoOffset %lld audioOffset %lld offsetDiff %lld\n",
- isSync ? "*" : " ",
- i,
- j,
- videoTimeUs / 1E6,
- audioTimeUs / 1E6,
- videoOffset,
- audioOffset,
- offsetDiff);
-#endif
-
- if (offsetDiff > maxOffsetDiff) {
- maxOffsetDiff = offsetDiff;
- maxOffsetTimeUs = videoTimeUs;
- }
- }
-
-#if 0
- printf("max offset diff: %lld at video time: %.2f secs\n",
- maxOffsetDiff, maxOffsetTimeUs / 1E6);
-#endif
-
- if (maxOffsetDiff < 1024 * 1024) {
- return OK;
- }
-
- LOGE("This content is not streamable, "
- "max offset diff: %lld at video time: %.2f secs",
- maxOffsetDiff, maxOffsetTimeUs / 1E6);
-
- return ERROR_UNSUPPORTED;
-}
-
static bool LegacySniffMPEG4(
const sp<DataSource> &source, String8 *mimeType, float *confidence) {
uint8_t header[8];
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index 423df705a592..08db9021314e 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -53,6 +53,7 @@ SampleTable::SampleTable(const sp<DataSource> &source)
mNumSampleSizes(0),
mTimeToSampleCount(0),
mTimeToSample(NULL),
+ mSampleTimeEntries(NULL),
mCompositionTimeDeltaEntries(NULL),
mNumCompositionTimeDeltaEntries(0),
mSyncSampleOffset(-1),
@@ -73,6 +74,9 @@ SampleTable::~SampleTable() {
delete[] mCompositionTimeDeltaEntries;
mCompositionTimeDeltaEntries = NULL;
+ delete[] mSampleTimeEntries;
+ mSampleTimeEntries = NULL;
+
delete[] mTimeToSample;
mTimeToSample = NULL;
@@ -381,67 +385,128 @@ uint32_t abs_difference(uint32_t time1, uint32_t time2) {
return time1 > time2 ? time1 - time2 : time2 - time1;
}
-status_t SampleTable::findSampleAtTime(
- uint32_t req_time, uint32_t *sample_index, uint32_t flags) {
- // XXX this currently uses decoding time, instead of composition time.
+// static
+int SampleTable::CompareIncreasingTime(const void *_a, const void *_b) {
+ const SampleTimeEntry *a = (const SampleTimeEntry *)_a;
+ const SampleTimeEntry *b = (const SampleTimeEntry *)_b;
- *sample_index = 0;
+ if (a->mCompositionTime < b->mCompositionTime) {
+ return -1;
+ } else if (a->mCompositionTime > b->mCompositionTime) {
+ return 1;
+ }
+
+ return 0;
+}
+void SampleTable::buildSampleEntriesTable() {
Mutex::Autolock autoLock(mLock);
- uint32_t cur_sample = 0;
- uint32_t time = 0;
+ if (mSampleTimeEntries != NULL) {
+ return;
+ }
+
+ mSampleTimeEntries = new SampleTimeEntry[mNumSampleSizes];
+
+ uint32_t sampleIndex = 0;
+ uint32_t sampleTime = 0;
+
for (uint32_t i = 0; i < mTimeToSampleCount; ++i) {
uint32_t n = mTimeToSample[2 * i];
uint32_t delta = mTimeToSample[2 * i + 1];
- if (req_time < time + n * delta) {
- int j = (req_time - time) / delta;
-
- uint32_t time1 = time + j * delta;
- uint32_t time2 = time1 + delta;
-
- uint32_t sampleTime;
- if (i+1 == mTimeToSampleCount
- || (abs_difference(req_time, time1)
- < abs_difference(req_time, time2))) {
- *sample_index = cur_sample + j;
- sampleTime = time1;
- } else {
- *sample_index = cur_sample + j + 1;
- sampleTime = time2;
- }
+ for (uint32_t j = 0; j < n; ++j) {
+ CHECK(sampleIndex < mNumSampleSizes);
- switch (flags) {
- case kFlagBefore:
- {
- if (sampleTime > req_time && *sample_index > 0) {
- --*sample_index;
- }
- break;
- }
+ mSampleTimeEntries[sampleIndex].mSampleIndex = sampleIndex;
- case kFlagAfter:
- {
- if (sampleTime < req_time
- && *sample_index + 1 < mNumSampleSizes) {
- ++*sample_index;
- }
- break;
- }
+ mSampleTimeEntries[sampleIndex].mCompositionTime =
+ sampleTime + getCompositionTimeOffset(sampleIndex);
+
+ ++sampleIndex;
+ sampleTime += delta;
+ }
+ }
+
+ qsort(mSampleTimeEntries, mNumSampleSizes, sizeof(SampleTimeEntry),
+ CompareIncreasingTime);
+}
- default:
- break;
+status_t SampleTable::findSampleAtTime(
+ uint32_t req_time, uint32_t *sample_index, uint32_t flags) {
+ buildSampleEntriesTable();
+
+ uint32_t left = 0;
+ uint32_t right = mNumSampleSizes;
+ while (left < right) {
+ uint32_t center = (left + right) / 2;
+ uint32_t centerTime = mSampleTimeEntries[center].mCompositionTime;
+
+ if (req_time < centerTime) {
+ right = center;
+ } else if (req_time > centerTime) {
+ left = center + 1;
+ } else {
+ left = center;
+ break;
+ }
+ }
+
+ if (left == mNumSampleSizes) {
+ --left;
+ }
+
+ uint32_t closestIndex = left;
+
+ switch (flags) {
+ case kFlagBefore:
+ {
+ while (closestIndex > 0
+ && mSampleTimeEntries[closestIndex].mCompositionTime
+ > req_time) {
+ --closestIndex;
}
+ break;
+ }
- return OK;
+ case kFlagAfter:
+ {
+ while (closestIndex + 1 < mNumSampleSizes
+ && mSampleTimeEntries[closestIndex].mCompositionTime
+ < req_time) {
+ ++closestIndex;
+ }
+ break;
}
- time += delta * n;
- cur_sample += n;
+ default:
+ {
+ CHECK(flags == kFlagClosest);
+
+ if (closestIndex > 0) {
+ // Check left neighbour and pick closest.
+ uint32_t absdiff1 =
+ abs_difference(
+ mSampleTimeEntries[closestIndex].mCompositionTime,
+ req_time);
+
+ uint32_t absdiff2 =
+ abs_difference(
+ mSampleTimeEntries[closestIndex - 1].mCompositionTime,
+ req_time);
+
+ if (absdiff1 > absdiff2) {
+ closestIndex = closestIndex - 1;
+ }
+ }
+
+ break;
+ }
}
- return ERROR_OUT_OF_RANGE;
+ *sample_index = mSampleTimeEntries[closestIndex].mSampleIndex;
+
+ return OK;
}
status_t SampleTable::findSyncSampleNear(
@@ -613,7 +678,7 @@ status_t SampleTable::getMetaDataForSample(
uint32_t sampleIndex,
off64_t *offset,
size_t *size,
- uint32_t *decodingTime,
+ uint32_t *compositionTime,
bool *isSyncSample) {
Mutex::Autolock autoLock(mLock);
@@ -630,8 +695,8 @@ status_t SampleTable::getMetaDataForSample(
*size = mSampleIterator->getSampleSize();
}
- if (decodingTime) {
- *decodingTime = mSampleIterator->getSampleTime();
+ if (compositionTime) {
+ *compositionTime = mSampleIterator->getSampleTime();
}
if (isSyncSample) {
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index 4095fbf0f58f..7621f2ce8a42 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -146,7 +146,8 @@ static VideoFrame *extractVideoFrameWithCodecFlags(
int64_t thumbNailTime;
if (frameTimeUs < 0) {
- if (!trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)) {
+ if (!trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)
+ || thumbNailTime < 0) {
thumbNailTime = 0;
}
options.setSeekTo(thumbNailTime, mode);
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 7fd77245d6c7..8c61064c6898 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -218,6 +218,8 @@ private:
DrmManagerClient *mDrmManagerClient;
sp<DecryptHandle> mDecryptHandle;
+ int64_t mLastVideoTimeUs;
+
status_t setDataSource_l(
const char *uri,
const KeyedVector<String8, String8> *headers = NULL);
@@ -267,6 +269,9 @@ private:
status_t startAudioPlayer_l();
+ void shutdownVideoDecoder_l();
+ void setNativeWindow_l(const sp<ANativeWindow> &native);
+
AwesomePlayer(const AwesomePlayer &);
AwesomePlayer &operator=(const AwesomePlayer &);
};
diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h
index d9ef208bda1c..3bd4c7eb5807 100644
--- a/media/libstagefright/include/MPEG4Extractor.h
+++ b/media/libstagefright/include/MPEG4Extractor.h
@@ -92,8 +92,6 @@ private:
Track *findTrackByMimePrefix(const char *mimePrefix);
- status_t verifyIfStreamable();
-
MPEG4Extractor(const MPEG4Extractor &);
MPEG4Extractor &operator=(const MPEG4Extractor &);
};
diff --git a/media/libstagefright/include/SampleTable.h b/media/libstagefright/include/SampleTable.h
index 2f95de9ce5ed..f44e0a2495f7 100644
--- a/media/libstagefright/include/SampleTable.h
+++ b/media/libstagefright/include/SampleTable.h
@@ -63,7 +63,7 @@ public:
uint32_t sampleIndex,
off64_t *offset,
size_t *size,
- uint32_t *decodingTime,
+ uint32_t *compositionTime,
bool *isSyncSample = NULL);
enum {
@@ -107,6 +107,12 @@ private:
uint32_t mTimeToSampleCount;
uint32_t *mTimeToSample;
+ struct SampleTimeEntry {
+ uint32_t mSampleIndex;
+ uint32_t mCompositionTime;
+ };
+ SampleTimeEntry *mSampleTimeEntries;
+
uint32_t *mCompositionTimeDeltaEntries;
size_t mNumCompositionTimeDeltaEntries;
@@ -130,6 +136,10 @@ private:
uint32_t getCompositionTimeOffset(uint32_t sampleIndex) const;
+ static int CompareIncreasingTime(const void *, const void *);
+
+ void buildSampleEntriesTable();
+
SampleTable(const SampleTable &);
SampleTable &operator=(const SampleTable &);
};
diff --git a/native/include/android/tts.h b/native/include/android/tts.h
deleted file mode 100644
index fb15108e00fe..000000000000
--- a/native/include/android/tts.h
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * Copyright (C) 2009 Google Inc.
- *
- * 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_TTS_H
-#define ANDROID_TTS_H
-
-// This header defines the interface used by the Android platform
-// to access Text-To-Speech functionality in shared libraries that implement
-// speech synthesis and the management of resources associated with the
-// synthesis.
-
-// The shared library must contain a function named "android_getTtsEngine"
-// that returns an 'android_tts_engine_t' instance.
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define ANDROID_TTS_ENGINE_PROPERTY_CONFIG "engineConfig"
-#define ANDROID_TTS_ENGINE_PROPERTY_PITCH "pitch"
-#define ANDROID_TTS_ENGINE_PROPERTY_RATE "rate"
-#define ANDROID_TTS_ENGINE_PROPERTY_VOLUME "volume"
-
-typedef enum {
- ANDROID_TTS_SUCCESS = 0,
- ANDROID_TTS_FAILURE = -1,
- ANDROID_TTS_FEATURE_UNSUPPORTED = -2,
- ANDROID_TTS_VALUE_INVALID = -3,
- ANDROID_TTS_PROPERTY_UNSUPPORTED = -4,
- ANDROID_TTS_PROPERTY_SIZE_TOO_SMALL = -5,
- ANDROID_TTS_MISSING_RESOURCES = -6
-} android_tts_result_t;
-
-typedef enum {
- ANDROID_TTS_LANG_COUNTRY_VAR_AVAILABLE = 2,
- ANDROID_TTS_LANG_COUNTRY_AVAILABLE = 1,
- ANDROID_TTS_LANG_AVAILABLE = 0,
- ANDROID_TTS_LANG_MISSING_DATA = -1,
- ANDROID_TTS_LANG_NOT_SUPPORTED = -2
-} android_tts_support_result_t;
-
-typedef enum {
- ANDROID_TTS_SYNTH_DONE = 0,
- ANDROID_TTS_SYNTH_PENDING = 1
-} android_tts_synth_status_t;
-
-typedef enum {
- ANDROID_TTS_CALLBACK_HALT = 0,
- ANDROID_TTS_CALLBACK_CONTINUE = 1
-} android_tts_callback_status_t;
-
-// Supported audio formats
-typedef enum {
- ANDROID_TTS_AUDIO_FORMAT_INVALID = -1,
- ANDROID_TTS_AUDIO_FORMAT_DEFAULT = 0,
- ANDROID_TTS_AUDIO_FORMAT_PCM_16_BIT = 1,
- ANDROID_TTS_AUDIO_FORMAT_PCM_8_BIT = 2,
-} android_tts_audio_format_t;
-
-
-/* An android_tts_engine_t object can be anything, but must have,
- * as its first field, a pointer to a table of functions.
- *
- * See the full definition of struct android_tts_engine_t_funcs_t
- * below for details.
- */
-typedef struct android_tts_engine_funcs_t android_tts_engine_funcs_t;
-
-typedef struct {
- android_tts_engine_funcs_t *funcs;
-} android_tts_engine_t;
-
-/* This function must be located in the TTS Engine shared library
- * and must return the address of an android_tts_engine_t library.
- */
-extern android_tts_engine_t *android_getTtsEngine();
-
-/* Including the old version for legacy support (Froyo compatibility).
- * This should return the same thing as android_getTtsEngine.
- */
-extern "C" android_tts_engine_t *getTtsEngine();
-
-// A callback type used to notify the framework of new synthetized
-// audio samples, status will be SYNTH_DONE for the last sample of
-// the last request, of SYNTH_PENDING otherwise.
-//
-// This is passed by the framework to the engine through the
-// 'engine_init' function (see below).
-//
-// The callback for synthesis completed takes:
-// @param [inout] void *& - The userdata pointer set in the original
-// synth call
-// @param [in] uint32_t - Track sampling rate in Hz
-// @param [in] uint32_t - The audio format
-// @param [in] int - The number of channels
-// @param [inout] int8_t *& - A buffer of audio data only valid during the
-// execution of the callback
-// @param [inout] size_t & - The size of the buffer
-// @param [in] tts_synth_status - indicate whether the synthesis is done, or
-// if more data is to be synthesized.
-// @return TTS_CALLBACK_HALT to indicate the synthesis must stop,
-// TTS_CALLBACK_CONTINUE to indicate the synthesis must continue if
-// there is more data to produce.
-typedef android_tts_callback_status_t (*android_tts_synth_cb_t)
- (void **pUserData,
- uint32_t trackSamplingHz,
- android_tts_audio_format_t audioFormat,
- int channelCount,
- int8_t **pAudioBuffer,
- size_t *pBufferSize,
- android_tts_synth_status_t status);
-
-
-// The table of function pointers that the android_tts_engine_t must point to.
-// Note that each of these functions will take a handle to the engine itself
-// as their first parameter.
-//
-
-struct android_tts_engine_funcs_t {
- // reserved fields, ignored by the framework
- // they must be placed here to ensure binary compatibility
- // of legacy binary plugins.
- void *reserved[2];
-
- // Initialize the TTS engine and returns whether initialization succeeded.
- // @param synthDoneCBPtr synthesis callback function pointer
- // @return TTS_SUCCESS, or TTS_FAILURE
- android_tts_result_t (*init)
- (void *engine,
- android_tts_synth_cb_t synthDonePtr,
- const char *engineConfig);
-
- // Shut down the TTS engine and releases all associated resources.
- // @return TTS_SUCCESS, or TTS_FAILURE
- android_tts_result_t (*shutdown)
- (void *engine);
-
- // Interrupt synthesis and flushes any synthesized data that hasn't been
- // output yet. This will block until callbacks underway are completed.
- // @return TTS_SUCCESS, or TTS_FAILURE
- android_tts_result_t (*stop)
- (void *engine);
-
- // Returns the level of support for the language, country and variant.
- // @return TTS_LANG_COUNTRY_VAR_AVAILABLE if the language, country and variant are supported,
- // and the corresponding resources are correctly installed
- // TTS_LANG_COUNTRY_AVAILABLE if the language and country are supported and the
- // corresponding resources are correctly installed, but there is no match for
- // the specified variant
- // TTS_LANG_AVAILABLE if the language is supported and the
- // corresponding resources are correctly installed, but there is no match for
- // the specified country and variant
- // TTS_LANG_MISSING_DATA if the required resources to provide any level of support
- // for the language are not correctly installed
- // TTS_LANG_NOT_SUPPORTED if the language is not supported by the TTS engine.
- android_tts_support_result_t (*isLanguageAvailable)
- (void *engine,
- const char *lang,
- const char *country,
- const char *variant);
-
- // Load the resources associated with the specified language. The loaded
- // language will only be used once a call to setLanguage() with the same
- // language value is issued. Language and country values are coded according to the ISO three
- // letter codes for languages and countries, as can be retrieved from a java.util.Locale
- // instance. The variant value is encoded as the variant string retrieved from a
- // java.util.Locale instance built with that variant data.
- // @param lang pointer to the ISO three letter code for the language
- // @param country pointer to the ISO three letter code for the country
- // @param variant pointer to the variant code
- // @return TTS_SUCCESS, or TTS_FAILURE
- android_tts_result_t (*loadLanguage)
- (void *engine,
- const char *lang,
- const char *country,
- const char *variant);
-
- // Load the resources associated with the specified language, country and Locale variant.
- // The loaded language will only be used once a call to setLanguageFromLocale() with the same
- // language value is issued. Language and country values are coded according to the ISO three
- // letter codes for languages and countries, as can be retrieved from a java.util.Locale
- // instance. The variant value is encoded as the variant string retrieved from a
- // java.util.Locale instance built with that variant data.
- // @param lang pointer to the ISO three letter code for the language
- // @param country pointer to the ISO three letter code for the country
- // @param variant pointer to the variant code
- // @return TTS_SUCCESS, or TTS_FAILURE
- android_tts_result_t (*setLanguage)
- (void *engine,
- const char *lang,
- const char *country,
- const char *variant);
-
- // Retrieve the currently set language, country and variant, or empty strings if none of
- // parameters have been set. Language and country are represented by their 3-letter ISO code
- // @param[out] pointer to the retrieved 3-letter code language value
- // @param[out] pointer to the retrieved 3-letter code country value
- // @param[out] pointer to the retrieved variant value
- // @return TTS_SUCCESS, or TTS_FAILURE
- android_tts_result_t (*getLanguage)
- (void *engine,
- char *language,
- char *country,
- char *variant);
-
- // Notifies the engine what audio parameters should be used for the synthesis.
- // This is meant to be used as a hint, the engine implementation will set the output values
- // to those of the synthesis format, based on a given hint.
- // @param[inout] encoding in: the desired audio sample format
- // out: the format used by the TTS engine
- // @param[inout] rate in: the desired audio sample rate
- // out: the sample rate used by the TTS engine
- // @param[inout] channels in: the desired number of audio channels
- // out: the number of channels used by the TTS engine
- // @return TTS_SUCCESS, or TTS_FAILURE
- android_tts_result_t (*setAudioFormat)
- (void *engine,
- android_tts_audio_format_t* pEncoding,
- uint32_t* pRate,
- int* pChannels);
-
- // Set a property for the the TTS engine
- // "size" is the maximum size of "value" for properties "property"
- // @param property pointer to the property name
- // @param value pointer to the property value
- // @param size maximum size required to store this type of property
- // @return TTS_PROPERTY_UNSUPPORTED, or TTS_SUCCESS, or TTS_FAILURE,
- // or TTS_VALUE_INVALID
- android_tts_result_t (*setProperty)
- (void *engine,
- const char *property,
- const char *value,
- const size_t size);
-
- // Retrieve a property from the TTS engine
- // @param property pointer to the property name
- // @param[out] value pointer to the retrieved language value
- // @param[inout] iosize in: stores the size available to store the
- // property value.
- // out: stores the size required to hold the language
- // value if getLanguage() returned
- // TTS_PROPERTY_SIZE_TOO_SMALL, unchanged otherwise
- // @return TTS_PROPERTY_UNSUPPORTED, or TTS_SUCCESS,
- // or TTS_PROPERTY_SIZE_TOO_SMALL
- android_tts_result_t (*getProperty)
- (void *engine,
- const char *property,
- char *value,
- size_t *iosize);
-
- // Synthesize the text.
- // As the synthesis is performed, the engine invokes the callback to notify
- // the TTS framework that it has filled the given buffer, and indicates how
- // many bytes it wrote. The callback is called repeatedly until the engine
- // has generated all the audio data corresponding to the text.
- // Note about the format of the input: the text parameter may use the
- // following elements
- // and their respective attributes as defined in the SSML 1.0 specification:
- // * lang
- // * say-as:
- // o interpret-as
- // * phoneme
- // * voice:
- // o gender,
- // o age,
- // o variant,
- // o name
- // * emphasis
- // * break:
- // o strength,
- // o time
- // * prosody:
- // o pitch,
- // o contour,
- // o range,
- // o rate,
- // o duration,
- // o volume
- // * mark
- // Differences between this text format and SSML are:
- // * full SSML documents are not supported
- // * namespaces are not supported
- // Text is coded in UTF-8.
- // @param text the UTF-8 text to synthesize
- // @param userdata pointer to be returned when the call is invoked
- // @param buffer the location where the synthesized data must be written
- // @param bufferSize the number of bytes that can be written in buffer
- // @return TTS_SUCCESS or TTS_FAILURE
- android_tts_result_t (*synthesizeText)
- (void *engine,
- const char *text,
- int8_t *buffer,
- size_t bufferSize,
- void *userdata);
-};
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* ANDROID_TTS_H */
diff --git a/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java b/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java
index ed1af49efbb5..9bd8f36ad2ba 100644
--- a/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java
+++ b/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java
@@ -18,6 +18,7 @@ package com.android.nfc_extras;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.nfc.ApduList;
import android.nfc.INfcAdapterExtras;
import android.nfc.NfcAdapter;
import android.os.RemoteException;
@@ -184,4 +185,20 @@ public final class NfcAdapterExtras {
public NfcExecutionEnvironment getEmbeddedExecutionEnvironment() {
return sEmbeddedEe;
}
+
+ public void registerTearDownApdus(String packageName, ApduList apdus) {
+ try {
+ sService.registerTearDownApdus(packageName, apdus);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ }
+
+ public void unregisterTearDownApdus(String packageName) {
+ try {
+ sService.unregisterTearDownApdus(packageName);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ }
}
diff --git a/opengl/java/android/opengl/GLES10.java b/opengl/java/android/opengl/GLES10.java
index 7c0f94953f03..790acbd3395e 100644
--- a/opengl/java/android/opengl/GLES10.java
+++ b/opengl/java/android/opengl/GLES10.java
@@ -1,18 +1,19 @@
/*
- * 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.
- */
+**
+** Copyright 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.
+*/
// This source file is automatically generated
diff --git a/opengl/java/android/opengl/GLES10Ext.java b/opengl/java/android/opengl/GLES10Ext.java
index 116ab9dfa574..81fc59e08911 100644
--- a/opengl/java/android/opengl/GLES10Ext.java
+++ b/opengl/java/android/opengl/GLES10Ext.java
@@ -1,18 +1,19 @@
/*
- * 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.
- */
+**
+** Copyright 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.
+*/
// This source file is automatically generated
diff --git a/opengl/java/android/opengl/GLES11.java b/opengl/java/android/opengl/GLES11.java
index b24c043e579d..1ca179b573be 100644
--- a/opengl/java/android/opengl/GLES11.java
+++ b/opengl/java/android/opengl/GLES11.java
@@ -1,18 +1,19 @@
/*
- * 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.
- */
+**
+** Copyright 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.
+*/
// This source file is automatically generated
diff --git a/opengl/java/android/opengl/GLES11Ext.java b/opengl/java/android/opengl/GLES11Ext.java
index a9a7a22432b7..25d54674ca03 100644
--- a/opengl/java/android/opengl/GLES11Ext.java
+++ b/opengl/java/android/opengl/GLES11Ext.java
@@ -1,18 +1,19 @@
/*
- * 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.
- */
+**
+** Copyright 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.
+*/
// This source file is automatically generated
diff --git a/opengl/java/android/opengl/GLES20.java b/opengl/java/android/opengl/GLES20.java
index 700164b6d7e7..635f811e72f6 100644
--- a/opengl/java/android/opengl/GLES20.java
+++ b/opengl/java/android/opengl/GLES20.java
@@ -1,18 +1,19 @@
/*
- * 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.
- */
+**
+** Copyright 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.
+*/
// This source file is automatically generated
diff --git a/opengl/java/com/google/android/gles_jni/GLImpl.java b/opengl/java/com/google/android/gles_jni/GLImpl.java
index 50f67601f9b5..090c0cb7c1d9 100644
--- a/opengl/java/com/google/android/gles_jni/GLImpl.java
+++ b/opengl/java/com/google/android/gles_jni/GLImpl.java
@@ -1,18 +1,19 @@
-/*
- * Copyright (C) 2006 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.
- */
+/* //device/java/android/com/google/android/gles_jni/GLImpl.java
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
// This source file is automatically generated
diff --git a/opengl/java/javax/microedition/khronos/opengles/GL.java b/opengl/java/javax/microedition/khronos/opengles/GL.java
index d5b60c64413b..3b78f3d2ce7d 100644
--- a/opengl/java/javax/microedition/khronos/opengles/GL.java
+++ b/opengl/java/javax/microedition/khronos/opengles/GL.java
@@ -1,18 +1,19 @@
-/*
- * Copyright (C) 2006 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.
- */
+/* //device/java/android/javax/microedition/khronos/opengles/GL.java
+**
+** Copyright 2006, 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 javax.microedition.khronos.opengles;
diff --git a/opengl/java/javax/microedition/khronos/opengles/GL10.java b/opengl/java/javax/microedition/khronos/opengles/GL10.java
index f48ecde02d88..4fcfb5206da1 100644
--- a/opengl/java/javax/microedition/khronos/opengles/GL10.java
+++ b/opengl/java/javax/microedition/khronos/opengles/GL10.java
@@ -1,18 +1,19 @@
-/*
- * Copyright (C) 2006 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.
- */
+/* //device/java/android/javax/microedition/khronos/opengles/GL10.java
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
// This source file is automatically generated
diff --git a/opengl/java/javax/microedition/khronos/opengles/GL10Ext.java b/opengl/java/javax/microedition/khronos/opengles/GL10Ext.java
index f3252ab0dd64..562b20ad4d75 100644
--- a/opengl/java/javax/microedition/khronos/opengles/GL10Ext.java
+++ b/opengl/java/javax/microedition/khronos/opengles/GL10Ext.java
@@ -1,18 +1,19 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+/* //device/java/android/javax/microedition/khronos/opengles/GL10Ext.java
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
// This source file is automatically generated
diff --git a/opengl/java/javax/microedition/khronos/opengles/GL11.java b/opengl/java/javax/microedition/khronos/opengles/GL11.java
index 943a5be47426..3ba110ccec48 100644
--- a/opengl/java/javax/microedition/khronos/opengles/GL11.java
+++ b/opengl/java/javax/microedition/khronos/opengles/GL11.java
@@ -1,18 +1,19 @@
-/*
- * Copyright (C) 2006 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.
- */
+/* //device/java/android/javax/microedition/khronos/opengles/GL11.java
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
// This source file is automatically generated
diff --git a/opengl/java/javax/microedition/khronos/opengles/GL11Ext.java b/opengl/java/javax/microedition/khronos/opengles/GL11Ext.java
index 842db7ab7edd..459a1abafe0c 100644
--- a/opengl/java/javax/microedition/khronos/opengles/GL11Ext.java
+++ b/opengl/java/javax/microedition/khronos/opengles/GL11Ext.java
@@ -1,18 +1,19 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+/* //device/java/android/javax/microedition/khronos/opengles/GL11Ext.java
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
// This source file is automatically generated
diff --git a/opengl/java/javax/microedition/khronos/opengles/GL11ExtensionPack.java b/opengl/java/javax/microedition/khronos/opengles/GL11ExtensionPack.java
index 97d5fd82e764..933c91ef4965 100644
--- a/opengl/java/javax/microedition/khronos/opengles/GL11ExtensionPack.java
+++ b/opengl/java/javax/microedition/khronos/opengles/GL11ExtensionPack.java
@@ -1,18 +1,19 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+/* //device/java/android/javax/microedition/khronos/opengles/GL11ExtensionPack.java
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
// This source file is automatically generated
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index 7d72729e1e75..0747efb186ac 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -13,8 +13,8 @@ LOCAL_SRC_FILES:= \
EGL/hooks.cpp \
EGL/Loader.cpp \
#
-LOCAL_STATIC_LIBRARIES += libGLESv2_dbg libprotobuf-cpp-2.3.0-lite liblzf
-LOCAL_SHARED_LIBRARIES += libcutils libutils libstlport
+
+LOCAL_SHARED_LIBRARIES += libcutils libutils libGLESv2_dbg
LOCAL_LDLIBS := -lpthread -ldl
LOCAL_MODULE:= libEGL
LOCAL_LDFLAGS += -Wl,--exclude-libs=ALL
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 6474c87bbdef..9cf722381f53 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -46,6 +46,7 @@
#include "egl_impl.h"
#include "Loader.h"
#include "glesv2dbg.h"
+#include "egl_tls.h"
#define setError(_e, _r) setErrorEtc(__FUNCTION__, __LINE__, _e, _r)
@@ -58,7 +59,7 @@ namespace android {
static char const * const gVendorString = "Android";
static char const * const gVersionString = "1.4 Android META-EGL";
static char const * const gClientApiString = "OpenGL ES";
-static char const * const gExtensionString =
+static char const * const gExtensionString =
"EGL_KHR_image "
"EGL_KHR_image_base "
"EGL_KHR_image_pixmap "
@@ -221,18 +222,15 @@ struct egl_surface_t : public egl_object_t
struct egl_context_t : public egl_object_t
{
typedef egl_object_t::LocalRef<egl_context_t, EGLContext> Ref;
-
+
egl_context_t(EGLDisplay dpy, EGLContext context, EGLConfig config,
- int impl, egl_connection_t const* cnx, int version)
- : egl_object_t(dpy), dpy(dpy), context(context), config(config), read(0), draw(0),
- impl(impl), cnx(cnx), version(version), dbg(NULL)
+ int impl, egl_connection_t const* cnx, int version)
+ : egl_object_t(dpy), dpy(dpy), context(context), config(config), read(0), draw(0),
+ impl(impl), cnx(cnx), version(version)
{
}
~egl_context_t()
{
- if (dbg)
- DestroyDbgContext(dbg);
- dbg = NULL;
}
EGLDisplay dpy;
EGLContext context;
@@ -242,7 +240,6 @@ struct egl_context_t : public egl_object_t
int impl;
egl_connection_t const* cnx;
int version;
- DbgContext * dbg;
};
struct egl_image_t : public egl_object_t
@@ -277,15 +274,6 @@ typedef egl_context_t::Ref ContextRef;
typedef egl_image_t::Ref ImageRef;
typedef egl_sync_t::Ref SyncRef;
-struct tls_t
-{
- tls_t() : error(EGL_SUCCESS), ctx(0), logCallWithNoContext(EGL_TRUE) { }
- EGLint error;
- EGLContext ctx;
- EGLBoolean logCallWithNoContext;
-};
-
-
// ----------------------------------------------------------------------------
static egl_connection_t gEGLImpl[IMPL_NUM_IMPLEMENTATIONS];
@@ -323,7 +311,7 @@ static void initEglTraceLevel() {
int propertyLevel = atoi(value);
int applicationLevel = gEGLApplicationTraceLevel;
gEGLTraceLevel = propertyLevel > applicationLevel ? propertyLevel : applicationLevel;
-
+
property_get("debug.egl.debug_proc", value, "");
long pid = getpid();
char procPath[128] = {};
@@ -336,14 +324,20 @@ static void initEglTraceLevel() {
{
if (!strcmp(value, cmdline))
gEGLDebugLevel = 1;
- }
+ }
fclose(file);
}
-
+
if (gEGLDebugLevel > 0)
{
property_get("debug.egl.debug_port", value, "5039");
- StartDebugServer(atoi(value));
+ const unsigned short port = (unsigned short)atoi(value);
+ property_get("debug.egl.debug_forceUseFile", value, "0");
+ const bool forceUseFile = (bool)atoi(value);
+ property_get("debug.egl.debug_maxFileSize", value, "8");
+ const unsigned int maxFileSize = atoi(value) << 20;
+ property_get("debug.egl.debug_filePath", value, "/data/local/tmp/dump.gles2dbg");
+ StartDebugServer(port, forceUseFile, maxFileSize, value);
}
}
@@ -586,7 +580,7 @@ static inline NATIVE* egl_to_native_cast(EGL arg) {
}
static inline
-egl_surface_t* get_surface(EGLSurface surface) {
+egl_surface_t* get_surface(EGLSurface surface) {
return egl_to_native_cast<egl_surface_t>(surface);
}
@@ -595,11 +589,6 @@ egl_context_t* get_context(EGLContext context) {
return egl_to_native_cast<egl_context_t>(context);
}
-DbgContext * getDbgContextThreadSpecific()
-{
- return get_context(getContext())->dbg;
-}
-
static inline
egl_image_t* get_image(EGLImageKHR image) {
return egl_to_native_cast<egl_image_t>(image);
@@ -1442,10 +1431,12 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
loseCurrent(cur_c);
if (ctx != EGL_NO_CONTEXT) {
- if (!c->dbg && gEGLDebugLevel > 0)
- c->dbg = CreateDbgContext(c->version, c->cnx->hooks[c->version]);
setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
setContext(ctx);
+ tls_t * const tls = getTLS();
+ if (!tls->dbg && gEGLDebugLevel > 0)
+ tls->dbg = CreateDbgContext(gEGLThreadLocalStorageKey, c->version,
+ c->cnx->hooks[c->version]);
_c.acquire();
_r.acquire();
_d.acquire();
diff --git a/opengl/libs/GLES2_dbg/Android.mk b/opengl/libs/GLES2_dbg/Android.mk
index fc40799724fc..853cce670a21 100644
--- a/opengl/libs/GLES2_dbg/Android.mk
+++ b/opengl/libs/GLES2_dbg/Android.mk
@@ -11,7 +11,7 @@ LOCAL_SRC_FILES := \
src/server.cpp \
src/vertex.cpp
-LOCAL_C_INCLUDES := \
+LOCAL_C_INCLUDES := \
$(LOCAL_PATH) \
$(LOCAL_PATH)/../ \
external/stlport/stlport \
@@ -21,7 +21,8 @@ LOCAL_C_INCLUDES := \
#LOCAL_CFLAGS += -O0 -g -DDEBUG -UNDEBUG
LOCAL_CFLAGS := -DGOOGLE_PROTOBUF_NO_RTTI
-
+LOCAL_STATIC_LIBRARIES := libprotobuf-cpp-2.3.0-lite liblzf
+LOCAL_SHARED_LIBRARIES := libcutils libutils libstlport
ifeq ($(TARGET_ARCH),arm)
LOCAL_CFLAGS += -fstrict-aliasing
endif
@@ -43,4 +44,4 @@ endif
LOCAL_MODULE:= libGLESv2_dbg
LOCAL_MODULE_TAGS := optional
-include $(BUILD_STATIC_LIBRARY)
+include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/libs/GLES2_dbg/generate_api_cpp.py b/opengl/libs/GLES2_dbg/generate_api_cpp.py
index 66c110f4a144..aeba213d57a4 100755
--- a/opengl/libs/GLES2_dbg/generate_api_cpp.py
+++ b/opengl/libs/GLES2_dbg/generate_api_cpp.py
@@ -26,36 +26,36 @@ def RemoveAnnotation(line):
return line.replace(annotation, "*")
else:
return line
-
+
def generate_api(lines):
externs = []
i = 0
# these have been hand written
- skipFunctions = ["glReadPixels", "glDrawArrays", "glDrawElements"]
-
+ skipFunctions = ["glDrawArrays", "glDrawElements"]
+
# these have an EXTEND_Debug_* macro for getting data
- extendFunctions = ["glCopyTexImage2D", "glCopyTexSubImage2D", "glShaderSource",
-"glTexImage2D", "glTexSubImage2D"]
-
+ extendFunctions = ["glCopyTexImage2D", "glCopyTexSubImage2D", "glReadPixels",
+"glShaderSource", "glTexImage2D", "glTexSubImage2D"]
+
# these also needs to be forwarded to DbgContext
contextFunctions = ["glUseProgram", "glEnableVertexAttribArray", "glDisableVertexAttribArray",
"glVertexAttribPointer", "glBindBuffer", "glBufferData", "glBufferSubData", "glDeleteBuffers",]
-
+
for line in lines:
if line.find("API_ENTRY(") >= 0: # a function prototype
returnType = line[0: line.find(" API_ENTRY(")]
functionName = line[line.find("(") + 1: line.find(")")] #extract GL function name
parameterList = line[line.find(")(") + 2: line.find(") {")]
-
+
#if line.find("*") >= 0:
# extern = "%s Debug_%s(%s);" % (returnType, functionName, parameterList)
# externs.append(extern)
# continue
-
+
if functionName in skipFunctions:
sys.stderr.write("!\n! skipping function '%s'\n!\n" % (functionName))
continue
-
+
parameters = parameterList.split(',')
paramIndex = 0
if line.find("*") >= 0 and (line.find("*") < line.find(":") or line.find("*") > line.rfind(":")): # unannotated pointer
@@ -65,21 +65,21 @@ def generate_api(lines):
sys.stderr.write("%s should be hand written\n" % (extern))
print "// FIXME: this function has pointers, it should be hand written"
externs.append(extern)
-
+
print "%s Debug_%s(%s)\n{" % (returnType, functionName, RemoveAnnotation(parameterList))
print " glesv2debugger::Message msg;"
-
+
if parameterList == "void":
parameters = []
arguments = ""
paramNames = []
inout = ""
getData = ""
-
+
callerMembers = ""
setCallerMembers = ""
setMsgParameters = ""
-
+
for parameter in parameters:
const = parameter.find("const")
parameter = parameter.replace("const", "")
@@ -107,7 +107,7 @@ def generate_api(lines):
annotation = "strlen(%s)" % (paramName)
else:
count = int(annotation)
-
+
setMsgParameters += " msg.set_arg%d(ToInt(%s));\n" % (paramIndex, paramName)
if paramType.find("void") >= 0:
getData += " msg.mutable_data()->assign(reinterpret_cast<const char *>(%s), %s * sizeof(char));" % (paramName, annotation)
@@ -127,7 +127,7 @@ def generate_api(lines):
paramIndex += 1
callerMembers += " %s %s;\n" % (paramType, paramName)
setCallerMembers += " caller.%s = %s;\n" % (paramName, paramName)
-
+
print " struct : public FunctionCall {"
print callerMembers
print " const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {"
@@ -141,6 +141,11 @@ def generate_api(lines):
if inout in ["out", "inout"]:
print " msg.set_time((systemTime(timeMode) - c0) * 1e-6f);"
print " " + getData
+ if functionName in extendFunctions:
+ print "\
+#ifdef EXTEND_AFTER_CALL_Debug_%s\n\
+ EXTEND_AFTER_CALL_Debug_%s;\n\
+#endif" % (functionName, functionName)
if functionName in contextFunctions:
print " getDbgContextThreadSpecific()->%s(%s);" % (functionName, arguments)
if returnType == "void":
@@ -157,7 +162,10 @@ def generate_api(lines):
if inout in ["in", "inout"]:
print getData
if functionName in extendFunctions:
- print " EXTEND_Debug_%s;" % (functionName)
+ print "\
+#ifdef EXTEND_Debug_%s\n\
+ EXTEND_Debug_%s;\n\
+#endif" % (functionName, functionName)
print " int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_%s);"\
% (functionName)
if returnType != "void":
@@ -166,8 +174,8 @@ def generate_api(lines):
else:
print " return reinterpret_cast<%s>(ret);" % (returnType)
print "}\n"
-
-
+
+
print "// FIXME: the following functions should be written by hand"
for extern in externs:
print extern
@@ -189,18 +197,23 @@ if __name__ == "__main__":
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-
+
// auto generated by generate_api_cpp.py
+#include <utils/Debug.h>
+
#include "src/header.h"
#include "src/api.h"
-template<typename T> static int ToInt(const T & t) { STATIC_ASSERT(sizeof(T) == sizeof(int), bitcast); return (int &)t; }
-template<typename T> static T FromInt(const int & t) { STATIC_ASSERT(sizeof(T) == sizeof(int), bitcast); return (T &)t; }
-"""
+template<typename T> static int ToInt(const T & t)
+{
+ COMPILE_TIME_ASSERT_FUNCTION_SCOPE(sizeof(T) == sizeof(int));
+ return (int &)t;
+}
+"""
lines = open("gl2_api_annotated.in").readlines()
generate_api(lines)
#lines = open("gl2ext_api.in").readlines()
#generate_api(lines)
-
+
diff --git a/opengl/libs/GLES2_dbg/generate_caller_cpp.py b/opengl/libs/GLES2_dbg/generate_caller_cpp.py
index eac2292a8207..ee4208dd3dbf 100755
--- a/opengl/libs/GLES2_dbg/generate_caller_cpp.py
+++ b/opengl/libs/GLES2_dbg/generate_caller_cpp.py
@@ -177,7 +177,6 @@ const int * GenerateCall(DbgContext * const dbg, const glesv2debugger::Message &
{
LOGD("GenerateCall function=%u", cmd.function());
const int * ret = prevRet; // only some functions have return value
- gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl;
nsecs_t c0 = systemTime(timeMode);
switch (cmd.function()) {""")
diff --git a/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py b/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py
index 466c447cff2b..914ea2463c08 100755
--- a/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py
+++ b/opengl/libs/GLES2_dbg/generate_debugger_message_proto.py
@@ -70,41 +70,43 @@ message Message
""")
i = 0;
-
+
lines = open("gl2_api_annotated.in").readlines()
i = generate_gl_entries(output, lines, i)
output.write(" // end of GL functions\n")
-
+
#lines = open("gl2ext_api.in").readlines()
#i = generate_gl_entries(output, lines, i)
#output.write(" // end of GL EXT functions\n")
-
+
lines = open("../EGL/egl_entries.in").readlines()
i = generate_egl_entries(output, lines, i)
output.write(" // end of GL EXT functions\n")
-
+
output.write(" ACK = %d;\n" % (i))
i += 1
-
+
output.write(" NEG = %d;\n" % (i))
i += 1
-
+
output.write(" CONTINUE = %d;\n" % (i))
i += 1
-
+
output.write(" SKIP = %d;\n" % (i))
i += 1
-
+
output.write(" SETPROP = %d;\n" % (i))
i += 1
-
+
output.write(""" }
required Function function = 2 [default = NEG]; // type/function of message
enum Type
{
BeforeCall = 0;
AfterCall = 1;
- Response = 2; // currently used for misc messages
+ AfterGeneratedCall = 2;
+ Response = 3; // currently used for misc messages
+ CompleteCall = 4; // BeforeCall and AfterCall merged
}
required Type type = 3;
required bool expect_response = 4;
@@ -125,16 +127,21 @@ message Message
ReferencedImage = 0; // for image sourced from ReadPixels
NonreferencedImage = 1; // for image sourced from ReadPixels
};
- optional DataType data_type = 23; // most data types can be inferred from function
- optional int32 pixel_format = 24; // used for image data if format and type
- optional int32 pixel_type = 25; // cannot be determined from arg
-
+ // most data types can be inferred from function
+ optional DataType data_type = 23;
+ // these are used for image data when they cannot be determined from args
+ optional int32 pixel_format = 24;
+ optional int32 pixel_type = 25;
+ optional int32 image_width = 26;
+ optional int32 image_height = 27;
+
optional float time = 11; // duration of previous GL call (ms)
enum Prop
{
- Capture = 0; // arg0 = true | false
+ CaptureDraw = 0; // arg0 = number of glDrawArrays/Elements to glReadPixels
TimeMode = 1; // arg0 = SYSTEM_TIME_* in utils/Timers.h
ExpectResponse = 2; // arg0 = enum Function, arg1 = true/false
+ CaptureSwap = 3; // arg0 = number of eglSwapBuffers to glReadPixels
};
optional Prop prop = 21; // used with SETPROP, value in arg0
optional float clock = 22; // wall clock in seconds
@@ -142,6 +149,6 @@ message Message
""")
output.close()
-
+
os.system("aprotoc --cpp_out=src --java_out=../../../../../development/tools/glesv2debugger/src debugger_message.proto")
os.system('mv -f "src/debugger_message.pb.cc" "src/debugger_message.pb.cpp"')
diff --git a/opengl/libs/GLES2_dbg/src/api.cpp b/opengl/libs/GLES2_dbg/src/api.cpp
index 130ca7e0489d..c4835478d2d7 100644
--- a/opengl/libs/GLES2_dbg/src/api.cpp
+++ b/opengl/libs/GLES2_dbg/src/api.cpp
@@ -16,11 +16,16 @@
// auto generated by generate_api_cpp.py
+#include <utils/Debug.h>
+
#include "src/header.h"
#include "src/api.h"
-template<typename T> static int ToInt(const T & t) { STATIC_ASSERT(sizeof(T) == sizeof(int), bitcast); return (int &)t; }
-template<typename T> static T FromInt(const int & t) { STATIC_ASSERT(sizeof(T) == sizeof(int), bitcast); return (T &)t; }
+template<typename T> static int ToInt(const T & t)
+{
+ COMPILE_TIME_ASSERT_FUNCTION_SCOPE(sizeof(T) == sizeof(int));
+ return (int &)t;
+}
void Debug_glActiveTexture(GLenum texture)
{
@@ -592,6 +597,9 @@ void Debug_glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, G
const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
_c->glCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
+#ifdef EXTEND_AFTER_CALL_Debug_glCopyTexImage2D
+ EXTEND_AFTER_CALL_Debug_glCopyTexImage2D;
+#endif
return 0;
}
} caller;
@@ -613,7 +621,9 @@ void Debug_glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, G
msg.set_arg6(height);
msg.set_arg7(border);
+#ifdef EXTEND_Debug_glCopyTexImage2D
EXTEND_Debug_glCopyTexImage2D;
+#endif
int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCopyTexImage2D);
}
@@ -632,6 +642,9 @@ void Debug_glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint
const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
_c->glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
+#ifdef EXTEND_AFTER_CALL_Debug_glCopyTexSubImage2D
+ EXTEND_AFTER_CALL_Debug_glCopyTexSubImage2D;
+#endif
return 0;
}
} caller;
@@ -653,7 +666,9 @@ void Debug_glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint
msg.set_arg6(width);
msg.set_arg7(height);
+#ifdef EXTEND_Debug_glCopyTexSubImage2D
EXTEND_Debug_glCopyTexSubImage2D;
+#endif
int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glCopyTexSubImage2D);
}
@@ -2164,6 +2179,49 @@ void Debug_glPolygonOffset(GLfloat factor, GLfloat units)
int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glPolygonOffset);
}
+void Debug_glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels)
+{
+ glesv2debugger::Message msg;
+ struct : public FunctionCall {
+ GLint x;
+ GLint y;
+ GLsizei width;
+ GLsizei height;
+ GLenum format;
+ GLenum type;
+ GLvoid* pixels;
+
+ const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
+ _c->glReadPixels(x, y, width, height, format, type, pixels);
+#ifdef EXTEND_AFTER_CALL_Debug_glReadPixels
+ EXTEND_AFTER_CALL_Debug_glReadPixels;
+#endif
+ return 0;
+ }
+ } caller;
+ caller.x = x;
+ caller.y = y;
+ caller.width = width;
+ caller.height = height;
+ caller.format = format;
+ caller.type = type;
+ caller.pixels = pixels;
+
+ msg.set_arg0(x);
+ msg.set_arg1(y);
+ msg.set_arg2(width);
+ msg.set_arg3(height);
+ msg.set_arg4(format);
+ msg.set_arg5(type);
+ msg.set_arg6(ToInt(pixels));
+
+ // FIXME: check for pointer usage
+#ifdef EXTEND_Debug_glReadPixels
+ EXTEND_Debug_glReadPixels;
+#endif
+ int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glReadPixels);
+}
+
void Debug_glReleaseShaderCompiler(void)
{
glesv2debugger::Message msg;
@@ -2297,6 +2355,9 @@ void Debug_glShaderSource(GLuint shader, GLsizei count, const GLchar** string, c
const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
_c->glShaderSource(shader, count, string, length);
+#ifdef EXTEND_AFTER_CALL_Debug_glShaderSource
+ EXTEND_AFTER_CALL_Debug_glShaderSource;
+#endif
return 0;
}
} caller;
@@ -2311,7 +2372,9 @@ void Debug_glShaderSource(GLuint shader, GLsizei count, const GLchar** string, c
msg.set_arg3(ToInt(length));
// FIXME: check for pointer usage
+#ifdef EXTEND_Debug_glShaderSource
EXTEND_Debug_glShaderSource;
+#endif
int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glShaderSource);
}
@@ -2472,6 +2535,9 @@ void Debug_glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsize
const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
_c->glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
+#ifdef EXTEND_AFTER_CALL_Debug_glTexImage2D
+ EXTEND_AFTER_CALL_Debug_glTexImage2D;
+#endif
return 0;
}
} caller;
@@ -2496,7 +2562,9 @@ void Debug_glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsize
msg.set_arg8(ToInt(pixels));
// FIXME: check for pointer usage
+#ifdef EXTEND_Debug_glTexImage2D
EXTEND_Debug_glTexImage2D;
+#endif
int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexImage2D);
}
@@ -2616,6 +2684,9 @@ void Debug_glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoff
const int * operator()(gl_hooks_t::gl_t const * const _c, glesv2debugger::Message & msg) {
_c->glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
+#ifdef EXTEND_AFTER_CALL_Debug_glTexSubImage2D
+ EXTEND_AFTER_CALL_Debug_glTexSubImage2D;
+#endif
return 0;
}
} caller;
@@ -2640,7 +2711,9 @@ void Debug_glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoff
msg.set_arg8(ToInt(pixels));
// FIXME: check for pointer usage
+#ifdef EXTEND_Debug_glTexSubImage2D
EXTEND_Debug_glTexSubImage2D;
+#endif
int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_glTexSubImage2D);
}
diff --git a/opengl/libs/GLES2_dbg/src/api.h b/opengl/libs/GLES2_dbg/src/api.h
index b9fc341e3e61..0b227bc66c5c 100644
--- a/opengl/libs/GLES2_dbg/src/api.h
+++ b/opengl/libs/GLES2_dbg/src/api.h
@@ -16,19 +16,29 @@
#define EXTEND_Debug_glCopyTexImage2D \
DbgContext * const dbg = getDbgContextThreadSpecific(); \
- GLint readFormat, readType; \
- dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readFormat); \
- dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &readType); \
- unsigned readSize = GetBytesPerPixel(readFormat, readType) * width * height; \
- void * readData = dbg->GetReadPixelsBuffer(readSize); \
- dbg->hooks->gl.glReadPixels(x, y, width, height, readFormat, readType, readData); \
+ void * readData = dbg->GetReadPixelsBuffer(4 * width * height); \
+ /* pick easy format for client to convert */ \
+ dbg->hooks->gl.glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, readData); \
dbg->CompressReadPixelBuffer(msg.mutable_data()); \
msg.set_data_type(msg.ReferencedImage); \
- msg.set_pixel_format(readFormat); \
- msg.set_pixel_type(readType);
+ msg.set_pixel_format(GL_RGBA); \
+ msg.set_pixel_type(GL_UNSIGNED_BYTE);
#define EXTEND_Debug_glCopyTexSubImage2D EXTEND_Debug_glCopyTexImage2D
+#define EXTEND_AFTER_CALL_Debug_glReadPixels \
+ { \
+ DbgContext * const dbg = getDbgContextThreadSpecific(); \
+ if (dbg->IsReadPixelBuffer(pixels)) { \
+ dbg->CompressReadPixelBuffer(msg.mutable_data()); \
+ msg.set_data_type(msg.ReferencedImage); \
+ } else { \
+ const unsigned int size = width * height * GetBytesPerPixel(format, type); \
+ dbg->Compress(pixels, size, msg.mutable_data()); \
+ msg.set_data_type(msg.NonreferencedImage); \
+ } \
+ }
+
#define EXTEND_Debug_glShaderSource \
std::string * const data = msg.mutable_data(); \
for (unsigned i = 0; i < count; i++) \
diff --git a/opengl/libs/GLES2_dbg/src/caller.cpp b/opengl/libs/GLES2_dbg/src/caller.cpp
index 9992f05fe669..6b72751bd009 100644
--- a/opengl/libs/GLES2_dbg/src/caller.cpp
+++ b/opengl/libs/GLES2_dbg/src/caller.cpp
@@ -105,7 +105,6 @@ const int * GenerateCall(DbgContext * const dbg, const glesv2debugger::Message &
{
LOGD("GenerateCall function=%u", cmd.function());
const int * ret = prevRet; // only some functions have return value
- gl_hooks_t::gl_t const * const _c = &getGLTraceThreadSpecific()->gl;
nsecs_t c0 = systemTime(timeMode);
switch (cmd.function()) { case glesv2debugger::Message_Function_glActiveTexture:
dbg->hooks->gl.glActiveTexture(
@@ -772,7 +771,7 @@ const int * GenerateCall(DbgContext * const dbg, const glesv2debugger::Message &
msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
msg.set_context_id(reinterpret_cast<int>(dbg));
msg.set_function(cmd.function());
- msg.set_type(glesv2debugger::Message_Type_AfterCall);
+ msg.set_type(glesv2debugger::Message_Type_AfterGeneratedCall);
return ret;
}
diff --git a/opengl/libs/GLES2_dbg/src/caller.h b/opengl/libs/GLES2_dbg/src/caller.h
index 54477575aa78..e8111b329224 100644
--- a/opengl/libs/GLES2_dbg/src/caller.h
+++ b/opengl/libs/GLES2_dbg/src/caller.h
@@ -138,7 +138,9 @@ static const int * GenerateCall_glGetProgramiv(DbgContext * const dbg,
const glesv2debugger::Message & cmd,
glesv2debugger::Message & msg, const int * const prevRet)
{
- assert(0);
+ GLint params = -1;
+ dbg->hooks->gl.glGetProgramiv(cmd.arg0(), cmd.arg1(), &params);
+ msg.mutable_data()->append(reinterpret_cast<char *>(&params), sizeof(params));
return prevRet;
}
@@ -146,7 +148,10 @@ static const int * GenerateCall_glGetProgramInfoLog(DbgContext * const dbg,
const glesv2debugger::Message & cmd,
glesv2debugger::Message & msg, const int * const prevRet)
{
- assert(0);
+ const GLsizei bufSize = static_cast<GLsizei>(dbg->GetBufferSize());
+ GLsizei length = -1;
+ dbg->hooks->gl.glGetProgramInfoLog(cmd.arg0(), bufSize, &length, dbg->GetBuffer());
+ msg.mutable_data()->append(dbg->GetBuffer(), length);
return prevRet;
}
@@ -162,7 +167,9 @@ static const int * GenerateCall_glGetShaderiv(DbgContext * const dbg,
const glesv2debugger::Message & cmd,
glesv2debugger::Message & msg, const int * const prevRet)
{
- assert(0);
+ GLint params = -1;
+ dbg->hooks->gl.glGetShaderiv(cmd.arg0(), cmd.arg1(), &params);
+ msg.mutable_data()->append(reinterpret_cast<char *>(&params), sizeof(params));
return prevRet;
}
@@ -170,7 +177,10 @@ static const int * GenerateCall_glGetShaderInfoLog(DbgContext * const dbg,
const glesv2debugger::Message & cmd,
glesv2debugger::Message & msg, const int * const prevRet)
{
- assert(0);
+ const GLsizei bufSize = static_cast<GLsizei>(dbg->GetBufferSize());
+ GLsizei length = -1;
+ dbg->hooks->gl.glGetShaderInfoLog(cmd.arg0(), bufSize, &length, dbg->GetBuffer());
+ msg.mutable_data()->append(dbg->GetBuffer(), length);
return prevRet;
}
diff --git a/opengl/libs/GLES2_dbg/src/dbgcontext.cpp b/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
index cc7336cf318f..fe938748125f 100644
--- a/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
+++ b/opengl/libs/GLES2_dbg/src/dbgcontext.cpp
@@ -15,6 +15,7 @@
*/
#include "header.h"
+#include "egl_tls.h"
extern "C"
{
@@ -24,11 +25,23 @@ extern "C"
namespace android
{
+static pthread_key_t sEGLThreadLocalStorageKey = -1;
+
+DbgContext * getDbgContextThreadSpecific()
+{
+ tls_t* tls = (tls_t*)pthread_getspecific(sEGLThreadLocalStorageKey);
+ return tls->dbg;
+}
+
DbgContext::DbgContext(const unsigned version, const gl_hooks_t * const hooks,
- const unsigned MAX_VERTEX_ATTRIBS)
+ const unsigned MAX_VERTEX_ATTRIBS, const GLenum readFormat,
+ const GLenum readType)
: lzf_buf(NULL), lzf_readIndex(0), lzf_refSize(0), lzf_refBufSize(0)
, version(version), hooks(hooks)
, MAX_VERTEX_ATTRIBS(MAX_VERTEX_ATTRIBS)
+ , readFormat(readFormat), readType(readType)
+ , readBytesPerPixel(GetBytesPerPixel(readFormat, readType))
+ , captureSwap(0), captureDraw(0)
, vertexAttribs(new VertexAttrib[MAX_VERTEX_ATTRIBS])
, hasNonVBOAttribs(false), indexBuffers(NULL), indexBuffer(NULL)
, program(0), maxAttrib(0)
@@ -47,13 +60,18 @@ DbgContext::~DbgContext()
free(lzf_ref[1]);
}
-DbgContext * CreateDbgContext(const unsigned version, const gl_hooks_t * const hooks)
+DbgContext * CreateDbgContext(const pthread_key_t EGLThreadLocalStorageKey,
+ const unsigned version, const gl_hooks_t * const hooks)
{
+ sEGLThreadLocalStorageKey = EGLThreadLocalStorageKey;
assert(version < 2);
assert(GL_NO_ERROR == hooks->gl.glGetError());
GLint MAX_VERTEX_ATTRIBS = 0;
hooks->gl.glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &MAX_VERTEX_ATTRIBS);
- return new DbgContext(version, hooks, MAX_VERTEX_ATTRIBS);
+ GLint readFormat, readType;
+ hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readFormat);
+ hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &readType);
+ return new DbgContext(version, hooks, MAX_VERTEX_ATTRIBS, readFormat, readType);
}
void DestroyDbgContext(DbgContext * const dbg)
@@ -113,6 +131,7 @@ void DbgContext::Compress(const void * in_data, unsigned int in_len,
{
if (!lzf_buf)
lzf_buf = (char *)malloc(LZF_CHUNK_SIZE);
+ assert(lzf_buf);
const uint32_t totalDecompSize = in_len;
outStr->append((const char *)&totalDecompSize, sizeof(totalDecompSize));
for (unsigned int i = 0; i < in_len; i += LZF_CHUNK_SIZE) {
@@ -135,8 +154,10 @@ void * DbgContext::GetReadPixelsBuffer(const unsigned size)
if (lzf_refBufSize < size + 8) {
lzf_refBufSize = size + 8;
lzf_ref[0] = (unsigned *)realloc(lzf_ref[0], lzf_refBufSize);
+ assert(lzf_ref[0]);
memset(lzf_ref[0], 0, lzf_refBufSize);
lzf_ref[1] = (unsigned *)realloc(lzf_ref[1], lzf_refBufSize);
+ assert(lzf_ref[1]);
memset(lzf_ref[1], 0, lzf_refBufSize);
}
if (lzf_refSize != size) // need to clear unused ref to maintain consistency
@@ -151,6 +172,7 @@ void * DbgContext::GetReadPixelsBuffer(const unsigned size)
void DbgContext::CompressReadPixelBuffer(std::string * const outStr)
{
+ assert(lzf_ref[0] && lzf_ref[1]);
unsigned * const ref = lzf_ref[lzf_readIndex ^ 1];
unsigned * const src = lzf_ref[lzf_readIndex];
for (unsigned i = 0; i < lzf_refSize / sizeof(*ref) + 1; i++)
@@ -158,13 +180,34 @@ void DbgContext::CompressReadPixelBuffer(std::string * const outStr)
Compress(ref, lzf_refSize, outStr);
}
+char * DbgContext::GetBuffer()
+{
+ if (!lzf_buf)
+ lzf_buf = (char *)malloc(LZF_CHUNK_SIZE);
+ assert(lzf_buf);
+ return lzf_buf;
+}
+
+unsigned int DbgContext::GetBufferSize()
+{
+ if (!lzf_buf)
+ lzf_buf = (char *)malloc(LZF_CHUNK_SIZE);
+ assert(lzf_buf);
+ if (lzf_buf)
+ return LZF_CHUNK_SIZE;
+ else
+ return 0;
+}
+
void DbgContext::glUseProgram(GLuint program)
{
while (GLenum error = hooks->gl.glGetError())
- LOGD("DbgContext::glUseProgram: before glGetError() = 0x%.4X", error);
-
+ LOGD("DbgContext::glUseProgram(%u): before glGetError() = 0x%.4X",
+ program, error);
this->program = program;
-
+ maxAttrib = 0;
+ if (program == 0)
+ return;
GLint activeAttributes = 0;
hooks->gl.glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &activeAttributes);
maxAttrib = 0;
@@ -202,9 +245,9 @@ void DbgContext::glUseProgram(GLuint program)
maxAttrib = slot;
}
delete name;
-
while (GLenum error = hooks->gl.glGetError())
- LOGD("DbgContext::glUseProgram: after glGetError() = 0x%.4X", error);
+ LOGD("DbgContext::glUseProgram(%u): after glGetError() = 0x%.4X",
+ program, error);
}
static bool HasNonVBOAttribs(const DbgContext * const ctx)
@@ -254,14 +297,16 @@ void DbgContext::glVertexAttribPointer(GLuint indx, GLint size, GLenum type,
void DbgContext::glEnableVertexAttribArray(GLuint index)
{
- assert(index < MAX_VERTEX_ATTRIBS);
+ if (index >= MAX_VERTEX_ATTRIBS)
+ return;
vertexAttribs[index].enabled = true;
hasNonVBOAttribs = HasNonVBOAttribs(this);
}
void DbgContext::glDisableVertexAttribArray(GLuint index)
{
- assert(index < MAX_VERTEX_ATTRIBS);
+ if (index >= MAX_VERTEX_ATTRIBS)
+ return;
vertexAttribs[index].enabled = false;
hasNonVBOAttribs = HasNonVBOAttribs(this);
}
diff --git a/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp b/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp
index 046c954000ee..40478c357197 100644
--- a/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp
+++ b/opengl/libs/GLES2_dbg/src/debugger_message.pb.cpp
@@ -436,6 +436,8 @@ bool Message_Type_IsValid(int value) {
case 0:
case 1:
case 2:
+ case 3:
+ case 4:
return true;
default:
return false;
@@ -445,7 +447,9 @@ bool Message_Type_IsValid(int value) {
#ifndef _MSC_VER
const Message_Type Message::BeforeCall;
const Message_Type Message::AfterCall;
+const Message_Type Message::AfterGeneratedCall;
const Message_Type Message::Response;
+const Message_Type Message::CompleteCall;
const Message_Type Message::Type_MIN;
const Message_Type Message::Type_MAX;
const int Message::Type_ARRAYSIZE;
@@ -472,6 +476,7 @@ bool Message_Prop_IsValid(int value) {
case 0:
case 1:
case 2:
+ case 3:
return true;
default:
return false;
@@ -479,9 +484,10 @@ bool Message_Prop_IsValid(int value) {
}
#ifndef _MSC_VER
-const Message_Prop Message::Capture;
+const Message_Prop Message::CaptureDraw;
const Message_Prop Message::TimeMode;
const Message_Prop Message::ExpectResponse;
+const Message_Prop Message::CaptureSwap;
const Message_Prop Message::Prop_MIN;
const Message_Prop Message::Prop_MAX;
const int Message::Prop_ARRAYSIZE;
@@ -506,6 +512,8 @@ const int Message::kDataFieldNumber;
const int Message::kDataTypeFieldNumber;
const int Message::kPixelFormatFieldNumber;
const int Message::kPixelTypeFieldNumber;
+const int Message::kImageWidthFieldNumber;
+const int Message::kImageHeightFieldNumber;
const int Message::kTimeFieldNumber;
const int Message::kPropFieldNumber;
const int Message::kClockFieldNumber;
@@ -545,6 +553,8 @@ void Message::SharedCtor() {
data_type_ = 0;
pixel_format_ = 0;
pixel_type_ = 0;
+ image_width_ = 0;
+ image_height_ = 0;
time_ = 0;
prop_ = 0;
clock_ = 0;
@@ -606,6 +616,8 @@ void Message::Clear() {
if (_has_bits_[16 / 32] & (0xffu << (16 % 32))) {
pixel_format_ = 0;
pixel_type_ = 0;
+ image_width_ = 0;
+ image_height_ = 0;
time_ = 0;
prop_ = 0;
clock_ = 0;
@@ -790,7 +802,7 @@ bool Message::MergePartialFromCodedStream(
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
input, &time_)));
- _set_bit(18);
+ _set_bit(20);
} else {
goto handle_uninterpreted;
}
@@ -905,7 +917,7 @@ bool Message::MergePartialFromCodedStream(
DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
float, ::google::protobuf::internal::WireFormatLite::TYPE_FLOAT>(
input, &clock_)));
- _set_bit(20);
+ _set_bit(22);
} else {
goto handle_uninterpreted;
}
@@ -960,6 +972,38 @@ bool Message::MergePartialFromCodedStream(
} else {
goto handle_uninterpreted;
}
+ if (input->ExpectTag(208)) goto parse_image_width;
+ break;
+ }
+
+ // optional int32 image_width = 26;
+ case 26: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ parse_image_width:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+ input, &image_width_)));
+ _set_bit(18);
+ } else {
+ goto handle_uninterpreted;
+ }
+ if (input->ExpectTag(216)) goto parse_image_height;
+ break;
+ }
+
+ // optional int32 image_height = 27;
+ case 27: {
+ if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+ ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+ parse_image_height:
+ DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+ ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+ input, &image_height_)));
+ _set_bit(19);
+ } else {
+ goto handle_uninterpreted;
+ }
if (input->ExpectAtEnd()) return true;
break;
}
@@ -1035,7 +1079,7 @@ void Message::SerializeWithCachedSizes(
}
// optional float time = 11;
- if (_has_bit(18)) {
+ if (_has_bit(20)) {
::google::protobuf::internal::WireFormatLite::WriteFloat(11, this->time(), output);
}
@@ -1065,13 +1109,13 @@ void Message::SerializeWithCachedSizes(
}
// optional .com.android.glesv2debugger.Message.Prop prop = 21;
- if (_has_bit(19)) {
+ if (_has_bit(21)) {
::google::protobuf::internal::WireFormatLite::WriteEnum(
21, this->prop(), output);
}
// optional float clock = 22;
- if (_has_bit(20)) {
+ if (_has_bit(22)) {
::google::protobuf::internal::WireFormatLite::WriteFloat(22, this->clock(), output);
}
@@ -1091,6 +1135,16 @@ void Message::SerializeWithCachedSizes(
::google::protobuf::internal::WireFormatLite::WriteInt32(25, this->pixel_type(), output);
}
+ // optional int32 image_width = 26;
+ if (_has_bit(18)) {
+ ::google::protobuf::internal::WireFormatLite::WriteInt32(26, this->image_width(), output);
+ }
+
+ // optional int32 image_height = 27;
+ if (_has_bit(19)) {
+ ::google::protobuf::internal::WireFormatLite::WriteInt32(27, this->image_height(), output);
+ }
+
}
int Message::ByteSize() const {
@@ -1222,6 +1276,20 @@ int Message::ByteSize() const {
this->pixel_type());
}
+ // optional int32 image_width = 26;
+ if (has_image_width()) {
+ total_size += 2 +
+ ::google::protobuf::internal::WireFormatLite::Int32Size(
+ this->image_width());
+ }
+
+ // optional int32 image_height = 27;
+ if (has_image_height()) {
+ total_size += 2 +
+ ::google::protobuf::internal::WireFormatLite::Int32Size(
+ this->image_height());
+ }
+
// optional float time = 11;
if (has_time()) {
total_size += 1 + 4;
@@ -1312,12 +1380,18 @@ void Message::MergeFrom(const Message& from) {
set_pixel_type(from.pixel_type());
}
if (from._has_bit(18)) {
- set_time(from.time());
+ set_image_width(from.image_width());
}
if (from._has_bit(19)) {
- set_prop(from.prop());
+ set_image_height(from.image_height());
}
if (from._has_bit(20)) {
+ set_time(from.time());
+ }
+ if (from._has_bit(21)) {
+ set_prop(from.prop());
+ }
+ if (from._has_bit(22)) {
set_clock(from.clock());
}
}
@@ -1355,6 +1429,8 @@ void Message::Swap(Message* other) {
std::swap(data_type_, other->data_type_);
std::swap(pixel_format_, other->pixel_format_);
std::swap(pixel_type_, other->pixel_type_);
+ std::swap(image_width_, other->image_width_);
+ std::swap(image_height_, other->image_height_);
std::swap(time_, other->time_);
std::swap(prop_, other->prop_);
std::swap(clock_, other->clock_);
diff --git a/opengl/libs/GLES2_dbg/src/debugger_message.pb.h b/opengl/libs/GLES2_dbg/src/debugger_message.pb.h
index b2ec5a0ac31b..4ccfebb2cc53 100644
--- a/opengl/libs/GLES2_dbg/src/debugger_message.pb.h
+++ b/opengl/libs/GLES2_dbg/src/debugger_message.pb.h
@@ -236,11 +236,13 @@ const int Message_Function_Function_ARRAYSIZE = Message_Function_Function_MAX +
enum Message_Type {
Message_Type_BeforeCall = 0,
Message_Type_AfterCall = 1,
- Message_Type_Response = 2
+ Message_Type_AfterGeneratedCall = 2,
+ Message_Type_Response = 3,
+ Message_Type_CompleteCall = 4
};
bool Message_Type_IsValid(int value);
const Message_Type Message_Type_Type_MIN = Message_Type_BeforeCall;
-const Message_Type Message_Type_Type_MAX = Message_Type_Response;
+const Message_Type Message_Type_Type_MAX = Message_Type_CompleteCall;
const int Message_Type_Type_ARRAYSIZE = Message_Type_Type_MAX + 1;
enum Message_DataType {
@@ -253,13 +255,14 @@ const Message_DataType Message_DataType_DataType_MAX = Message_DataType_Nonrefer
const int Message_DataType_DataType_ARRAYSIZE = Message_DataType_DataType_MAX + 1;
enum Message_Prop {
- Message_Prop_Capture = 0,
+ Message_Prop_CaptureDraw = 0,
Message_Prop_TimeMode = 1,
- Message_Prop_ExpectResponse = 2
+ Message_Prop_ExpectResponse = 2,
+ Message_Prop_CaptureSwap = 3
};
bool Message_Prop_IsValid(int value);
-const Message_Prop Message_Prop_Prop_MIN = Message_Prop_Capture;
-const Message_Prop Message_Prop_Prop_MAX = Message_Prop_ExpectResponse;
+const Message_Prop Message_Prop_Prop_MIN = Message_Prop_CaptureDraw;
+const Message_Prop Message_Prop_Prop_MAX = Message_Prop_CaptureSwap;
const int Message_Prop_Prop_ARRAYSIZE = Message_Prop_Prop_MAX + 1;
// ===================================================================
@@ -510,7 +513,9 @@ class Message : public ::google::protobuf::MessageLite {
typedef Message_Type Type;
static const Type BeforeCall = Message_Type_BeforeCall;
static const Type AfterCall = Message_Type_AfterCall;
+ static const Type AfterGeneratedCall = Message_Type_AfterGeneratedCall;
static const Type Response = Message_Type_Response;
+ static const Type CompleteCall = Message_Type_CompleteCall;
static inline bool Type_IsValid(int value) {
return Message_Type_IsValid(value);
}
@@ -535,9 +540,10 @@ class Message : public ::google::protobuf::MessageLite {
Message_DataType_DataType_ARRAYSIZE;
typedef Message_Prop Prop;
- static const Prop Capture = Message_Prop_Capture;
+ static const Prop CaptureDraw = Message_Prop_CaptureDraw;
static const Prop TimeMode = Message_Prop_TimeMode;
static const Prop ExpectResponse = Message_Prop_ExpectResponse;
+ static const Prop CaptureSwap = Message_Prop_CaptureSwap;
static inline bool Prop_IsValid(int value) {
return Message_Prop_IsValid(value);
}
@@ -679,6 +685,20 @@ class Message : public ::google::protobuf::MessageLite {
inline ::google::protobuf::int32 pixel_type() const;
inline void set_pixel_type(::google::protobuf::int32 value);
+ // optional int32 image_width = 26;
+ inline bool has_image_width() const;
+ inline void clear_image_width();
+ static const int kImageWidthFieldNumber = 26;
+ inline ::google::protobuf::int32 image_width() const;
+ inline void set_image_width(::google::protobuf::int32 value);
+
+ // optional int32 image_height = 27;
+ inline bool has_image_height() const;
+ inline void clear_image_height();
+ static const int kImageHeightFieldNumber = 27;
+ inline ::google::protobuf::int32 image_height() const;
+ inline void set_image_height(::google::protobuf::int32 value);
+
// optional float time = 11;
inline bool has_time() const;
inline void clear_time();
@@ -723,6 +743,8 @@ class Message : public ::google::protobuf::MessageLite {
int data_type_;
::google::protobuf::int32 pixel_format_;
::google::protobuf::int32 pixel_type_;
+ ::google::protobuf::int32 image_width_;
+ ::google::protobuf::int32 image_height_;
float time_;
int prop_;
float clock_;
@@ -730,7 +752,7 @@ class Message : public ::google::protobuf::MessageLite {
friend void protobuf_AssignDesc_debugger_5fmessage_2eproto();
friend void protobuf_ShutdownFile_debugger_5fmessage_2eproto();
- ::google::protobuf::uint32 _has_bits_[(21 + 31) / 32];
+ ::google::protobuf::uint32 _has_bits_[(23 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
inline bool _has_bit(int index) const {
@@ -1070,52 +1092,84 @@ inline void Message::set_pixel_type(::google::protobuf::int32 value) {
pixel_type_ = value;
}
+// optional int32 image_width = 26;
+inline bool Message::has_image_width() const {
+ return _has_bit(18);
+}
+inline void Message::clear_image_width() {
+ image_width_ = 0;
+ _clear_bit(18);
+}
+inline ::google::protobuf::int32 Message::image_width() const {
+ return image_width_;
+}
+inline void Message::set_image_width(::google::protobuf::int32 value) {
+ _set_bit(18);
+ image_width_ = value;
+}
+
+// optional int32 image_height = 27;
+inline bool Message::has_image_height() const {
+ return _has_bit(19);
+}
+inline void Message::clear_image_height() {
+ image_height_ = 0;
+ _clear_bit(19);
+}
+inline ::google::protobuf::int32 Message::image_height() const {
+ return image_height_;
+}
+inline void Message::set_image_height(::google::protobuf::int32 value) {
+ _set_bit(19);
+ image_height_ = value;
+}
+
// optional float time = 11;
inline bool Message::has_time() const {
- return _has_bit(18);
+ return _has_bit(20);
}
inline void Message::clear_time() {
time_ = 0;
- _clear_bit(18);
+ _clear_bit(20);
}
inline float Message::time() const {
return time_;
}
inline void Message::set_time(float value) {
- _set_bit(18);
+ _set_bit(20);
time_ = value;
}
// optional .com.android.glesv2debugger.Message.Prop prop = 21;
inline bool Message::has_prop() const {
- return _has_bit(19);
+ return _has_bit(21);
}
inline void Message::clear_prop() {
prop_ = 0;
- _clear_bit(19);
+ _clear_bit(21);
}
inline ::com::android::glesv2debugger::Message_Prop Message::prop() const {
return static_cast< ::com::android::glesv2debugger::Message_Prop >(prop_);
}
inline void Message::set_prop(::com::android::glesv2debugger::Message_Prop value) {
GOOGLE_DCHECK(::com::android::glesv2debugger::Message_Prop_IsValid(value));
- _set_bit(19);
+ _set_bit(21);
prop_ = value;
}
// optional float clock = 22;
inline bool Message::has_clock() const {
- return _has_bit(20);
+ return _has_bit(22);
}
inline void Message::clear_clock() {
clock_ = 0;
- _clear_bit(20);
+ _clear_bit(22);
}
inline float Message::clock() const {
return clock_;
}
inline void Message::set_clock(float value) {
- _set_bit(20);
+ _set_bit(22);
clock_ = value;
}
diff --git a/opengl/libs/GLES2_dbg/src/egl.cpp b/opengl/libs/GLES2_dbg/src/egl.cpp
index 3a20e21ba2cc..eb28d0607693 100644
--- a/opengl/libs/GLES2_dbg/src/egl.cpp
+++ b/opengl/libs/GLES2_dbg/src/egl.cpp
@@ -18,6 +18,7 @@
EGLBoolean Debug_eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
{
+ DbgContext * const dbg = getDbgContextThreadSpecific();
glesv2debugger::Message msg;
struct : public FunctionCall {
EGLDisplay dpy;
@@ -33,7 +34,21 @@ EGLBoolean Debug_eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
msg.set_arg0(reinterpret_cast<int>(dpy));
msg.set_arg1(reinterpret_cast<int>(draw));
-
+ if (dbg->captureSwap > 0) {
+ dbg->captureSwap--;
+ int viewport[4] = {};
+ dbg->hooks->gl.glGetIntegerv(GL_VIEWPORT, viewport);
+ void * pixels = dbg->GetReadPixelsBuffer(viewport[2] * viewport[3] *
+ dbg->readBytesPerPixel);
+ dbg->hooks->gl.glReadPixels(viewport[0], viewport[1], viewport[2],
+ viewport[3], dbg->readFormat, dbg->readType, pixels);
+ dbg->CompressReadPixelBuffer(msg.mutable_data());
+ msg.set_data_type(msg.ReferencedImage);
+ msg.set_pixel_format(dbg->readFormat);
+ msg.set_pixel_type(dbg->readType);
+ msg.set_image_width(viewport[2]);
+ msg.set_image_height(viewport[3]);
+ }
int * ret = MessageLoop(caller, msg, glesv2debugger::Message_Function_eglSwapBuffers);
return static_cast<EGLBoolean>(reinterpret_cast<int>(ret));
}
diff --git a/opengl/libs/GLES2_dbg/src/header.h b/opengl/libs/GLES2_dbg/src/header.h
index 9218da5b31b0..c9e6c4167694 100644
--- a/opengl/libs/GLES2_dbg/src/header.h
+++ b/opengl/libs/GLES2_dbg/src/header.h
@@ -14,6 +14,9 @@
** limitations under the License.
*/
+#ifndef ANDROID_GLES2_DBG_HEADER_H
+#define ANDROID_GLES2_DBG_HEADER_H
+
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
@@ -24,9 +27,7 @@
#include <cutils/log.h>
#include <utils/Timers.h>
-#include <../../../libcore/include/StaticAssert.h>
-#define EGL_TRACE 1
#include "hooks.h"
#include "glesv2dbg.h"
@@ -39,8 +40,6 @@
using namespace android;
using namespace com::android;
-#define API_ENTRY(_api) Debug_##_api
-
#ifndef __location__
#define __HIERALLOC_STRING_0__(s) #s
#define __HIERALLOC_STRING_1__(s) __HIERALLOC_STRING_0__(s)
@@ -76,7 +75,7 @@ struct GLFunctionBitfield {
struct DbgContext {
private:
static const unsigned int LZF_CHUNK_SIZE = 256 * 1024;
- char * lzf_buf; // malloc / free; for lzf chunk compression
+ char * lzf_buf; // malloc / free; for lzf chunk compression and other uses
// used as buffer and reference frame for ReadPixels; malloc/free
unsigned * lzf_ref [2];
@@ -84,9 +83,14 @@ private:
unsigned lzf_refSize, lzf_refBufSize; // bytes
public:
- const unsigned version; // 0 is GLES1, 1 is GLES2
+ const unsigned int version; // 0 is GLES1, 1 is GLES2
const gl_hooks_t * const hooks;
- const unsigned MAX_VERTEX_ATTRIBS;
+ const unsigned int MAX_VERTEX_ATTRIBS;
+ const GLenum readFormat, readType; // implementation supported glReadPixels
+ const unsigned int readBytesPerPixel;
+
+ unsigned int captureSwap; // number of eglSwapBuffers to glReadPixels
+ unsigned int captureDraw; // number of glDrawArrays/Elements to glReadPixels
GLFunctionBitfield expectResponse;
@@ -119,7 +123,8 @@ public:
unsigned maxAttrib; // number of slots used by program
DbgContext(const unsigned version, const gl_hooks_t * const hooks,
- const unsigned MAX_VERTEX_ATTRIBS);
+ const unsigned MAX_VERTEX_ATTRIBS, const GLenum readFormat,
+ const GLenum readType);
~DbgContext();
void Fetch(const unsigned index, std::string * const data) const;
@@ -129,6 +134,8 @@ public:
return ptr == lzf_ref[lzf_readIndex];
}
void CompressReadPixelBuffer(std::string * const outStr);
+ char * GetBuffer(); // allocates lzf_buf if NULL
+ unsigned int GetBufferSize(); // allocates lzf_buf if NULL
void glUseProgram(GLuint program);
void glEnableVertexAttribArray(GLuint index);
@@ -141,9 +148,7 @@ public:
void glDeleteBuffers(GLsizei n, const GLuint *buffers);
};
-
DbgContext * getDbgContextThreadSpecific();
-#define DBGCONTEXT(ctx) DbgContext * const ctx = getDbgContextThreadSpecific();
struct FunctionCall {
virtual const int * operator()(gl_hooks_t::gl_t const * const _c,
@@ -152,7 +157,6 @@ struct FunctionCall {
};
// move these into DbgContext as static
-extern bool capture;
extern int timeMode; // SYSTEM_TIME_
extern int clientSock, serverSock;
@@ -169,3 +173,5 @@ void SetProp(DbgContext * const dbg, const glesv2debugger::Message & cmd);
const int * GenerateCall(DbgContext * const dbg, const glesv2debugger::Message & cmd,
glesv2debugger::Message & msg, const int * const prevRet);
}; // namespace android {
+
+#endif // #ifndef ANDROID_GLES2_DBG_HEADER_H
diff --git a/opengl/libs/GLES2_dbg/src/server.cpp b/opengl/libs/GLES2_dbg/src/server.cpp
index 7039c8485036..f13d6cc84939 100644
--- a/opengl/libs/GLES2_dbg/src/server.cpp
+++ b/opengl/libs/GLES2_dbg/src/server.cpp
@@ -28,7 +28,8 @@ namespace android
{
int serverSock = -1, clientSock = -1;
-
+FILE * file = NULL;
+unsigned int MAX_FILE_SIZE = 0;
int timeMode = SYSTEM_TIME_THREAD;
static void Die(const char * msg)
@@ -38,18 +39,25 @@ static void Die(const char * msg)
exit(1);
}
-void StartDebugServer(unsigned short port)
+void StartDebugServer(const unsigned short port, const bool forceUseFile,
+ const unsigned int maxFileSize, const char * const filePath)
{
+ MAX_FILE_SIZE = maxFileSize;
+
LOGD("GLESv2_dbg: StartDebugServer");
- if (serverSock >= 0)
+ if (serverSock >= 0 || file)
return;
LOGD("GLESv2_dbg: StartDebugServer create socket");
struct sockaddr_in server = {}, client = {};
/* Create the TCP socket */
- if ((serverSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
- Die("Failed to create socket");
+ if (forceUseFile || (serverSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
+ file = fopen(filePath, "wb");
+ if (!file)
+ Die("Failed to create socket and file");
+ else
+ return;
}
/* Construct the server sockaddr_in structure */
server.sin_family = AF_INET; /* Internet/IP */
@@ -92,13 +100,17 @@ void StopDebugServer()
close(serverSock);
serverSock = -1;
}
-
+ if (file) {
+ fclose(file);
+ file = NULL;
+ }
}
void Receive(glesv2debugger::Message & cmd)
{
+ if (clientSock < 0)
+ return;
unsigned len = 0;
-
int received = recv(clientSock, &len, 4, MSG_WAITALL);
if (received < 0)
Die("Failed to receive response length");
@@ -106,7 +118,6 @@ void Receive(glesv2debugger::Message & cmd)
LOGD("received %dB: %.8X", received, len);
Die("Received length mismatch, expected 4");
}
- len = ntohl(len);
static void * buffer = NULL;
static unsigned bufferSize = 0;
if (bufferSize < len) {
@@ -125,6 +136,8 @@ void Receive(glesv2debugger::Message & cmd)
bool TryReceive(glesv2debugger::Message & cmd)
{
+ if (clientSock < 0)
+ return false;
fd_set readSet;
FD_ZERO(&readSet);
FD_SET(clientSock, &readSet);
@@ -153,7 +166,19 @@ float Send(const glesv2debugger::Message & msg, glesv2debugger::Message & cmd)
assert(msg.has_context_id() && msg.context_id() != 0);
static std::string str;
msg.SerializeToString(&str);
- uint32_t len = htonl(str.length());
+ const uint32_t len = str.length();
+ if (clientSock < 0) {
+ if (file) {
+ fwrite(&len, sizeof(len), 1, file);
+ fwrite(str.data(), len, 1, file);
+ if (ftell(file) >= MAX_FILE_SIZE) {
+ fclose(file);
+ Die("MAX_FILE_SIZE reached");
+ }
+ }
+ pthread_mutex_unlock(&mutex);
+ return 0;
+ }
int sent = -1;
sent = send(clientSock, &len, sizeof(len), 0);
if (sent != sizeof(len)) {
@@ -169,14 +194,13 @@ float Send(const glesv2debugger::Message & msg, glesv2debugger::Message & cmd)
}
// try to receive commands even though not expecting response,
- // since client can send SETPROP commands anytime
+ // since client can send SETPROP and other commands anytime
if (!msg.expect_response()) {
if (TryReceive(cmd)) {
- LOGD("Send: TryReceived");
if (glesv2debugger::Message_Function_SETPROP == cmd.function())
- LOGD("Send: received SETPROP");
+ LOGD("Send: TryReceived SETPROP");
else
- LOGD("Send: received something else");
+ LOGD("Send: TryReceived %u", cmd.function());
}
} else
Receive(cmd);
@@ -188,9 +212,9 @@ float Send(const glesv2debugger::Message & msg, glesv2debugger::Message & cmd)
void SetProp(DbgContext * const dbg, const glesv2debugger::Message & cmd)
{
switch (cmd.prop()) {
- case glesv2debugger::Message_Prop_Capture:
- LOGD("SetProp Message_Prop_Capture %d", cmd.arg0());
- capture = cmd.arg0();
+ case glesv2debugger::Message_Prop_CaptureDraw:
+ LOGD("SetProp Message_Prop_CaptureDraw %d", cmd.arg0());
+ dbg->captureDraw = cmd.arg0();
break;
case glesv2debugger::Message_Prop_TimeMode:
LOGD("SetProp Message_Prop_TimeMode %d", cmd.arg0());
@@ -200,6 +224,10 @@ void SetProp(DbgContext * const dbg, const glesv2debugger::Message & cmd)
LOGD("SetProp Message_Prop_ExpectResponse %d=%d", cmd.arg0(), cmd.arg1());
dbg->expectResponse.Bit((glesv2debugger::Message_Function)cmd.arg0(), cmd.arg1());
break;
+ case glesv2debugger::Message_Prop_CaptureSwap:
+ LOGD("SetProp CaptureSwap %d", cmd.arg0());
+ dbg->captureSwap = cmd.arg0();
+ break;
default:
assert(0);
}
@@ -213,12 +241,16 @@ int * MessageLoop(FunctionCall & functionCall, glesv2debugger::Message & msg,
glesv2debugger::Message cmd;
msg.set_context_id(reinterpret_cast<int>(dbg));
msg.set_type(glesv2debugger::Message_Type_BeforeCall);
- const bool expectResponse = dbg->expectResponse.Bit(function);
+ bool expectResponse = dbg->expectResponse.Bit(function);
msg.set_expect_response(expectResponse);
msg.set_function(function);
- if (!expectResponse)
- cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
+
+ // when not exectResponse, set cmd to CONTINUE then SKIP
+ cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
+ cmd.set_expect_response(false);
+ glesv2debugger::Message_Function oldCmd = cmd.function();
Send(msg, cmd);
+ expectResponse = cmd.expect_response();
while (true) {
msg.Clear();
nsecs_t c0 = systemTime(timeMode);
@@ -233,22 +265,34 @@ int * MessageLoop(FunctionCall & functionCall, glesv2debugger::Message & msg,
msg.set_function(function);
msg.set_type(glesv2debugger::Message_Type_AfterCall);
msg.set_expect_response(expectResponse);
- if (!expectResponse)
+ if (!expectResponse) {
cmd.set_function(glesv2debugger::Message_Function_SKIP);
+ cmd.set_expect_response(false);
+ }
+ oldCmd = cmd.function();
Send(msg, cmd);
+ expectResponse = cmd.expect_response();
break;
case glesv2debugger::Message_Function_SKIP:
return const_cast<int *>(ret);
case glesv2debugger::Message_Function_SETPROP:
SetProp(dbg, cmd);
- Receive(cmd);
+ expectResponse = cmd.expect_response();
+ if (!expectResponse) // SETPROP is "out of band"
+ cmd.set_function(oldCmd);
+ else
+ Receive(cmd);
break;
default:
ret = GenerateCall(dbg, cmd, msg, ret);
msg.set_expect_response(expectResponse);
- if (!expectResponse)
+ if (!expectResponse) {
cmd.set_function(cmd.SKIP);
+ cmd.set_expect_response(expectResponse);
+ }
+ oldCmd = cmd.function();
Send(msg, cmd);
+ expectResponse = cmd.expect_response();
break;
}
}
diff --git a/opengl/libs/GLES2_dbg/src/vertex.cpp b/opengl/libs/GLES2_dbg/src/vertex.cpp
index 471e5adf9115..7edc0503316d 100644
--- a/opengl/libs/GLES2_dbg/src/vertex.cpp
+++ b/opengl/libs/GLES2_dbg/src/vertex.cpp
@@ -21,74 +21,13 @@ namespace android
bool capture; // capture after each glDraw*
}
-void Debug_glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels)
-{
- DbgContext * const dbg = getDbgContextThreadSpecific();
- glesv2debugger::Message msg, cmd;
- msg.set_context_id(reinterpret_cast<int>(dbg));
- msg.set_type(glesv2debugger::Message_Type_BeforeCall);
- const bool expectResponse = dbg->expectResponse.Bit(glesv2debugger::Message_Function_glReadPixels);
- msg.set_expect_response(expectResponse);
- msg.set_function(glesv2debugger::Message_Function_glReadPixels);
- msg.set_arg0(x);
- msg.set_arg1(y);
- msg.set_arg2(width);
- msg.set_arg3(height);
- msg.set_arg4(format);
- msg.set_arg5(type);
- msg.set_arg6(reinterpret_cast<int>(pixels));
-
- const unsigned size = width * height * GetBytesPerPixel(format, type);
- if (!expectResponse)
- cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
- Send(msg, cmd);
- float t = 0;
- while (true) {
- msg.Clear();
- nsecs_t c0 = systemTime(timeMode);
- switch (cmd.function()) {
- case glesv2debugger::Message_Function_CONTINUE:
- dbg->hooks->gl.glReadPixels(x, y, width, height, format, type, pixels);
- msg.set_time((systemTime(timeMode) - c0) * 1e-6f);
- msg.set_context_id(reinterpret_cast<int>(dbg));
- msg.set_function(glesv2debugger::Message_Function_glReadPixels);
- msg.set_type(glesv2debugger::Message_Type_AfterCall);
- msg.set_expect_response(expectResponse);
- if (dbg->IsReadPixelBuffer(pixels)) {
- dbg->CompressReadPixelBuffer(msg.mutable_data());
- msg.set_data_type(msg.ReferencedImage);
- } else {
- dbg->Compress(pixels, size, msg.mutable_data());
- msg.set_data_type(msg.NonreferencedImage);
- }
- if (!expectResponse)
- cmd.set_function(glesv2debugger::Message_Function_SKIP);
- Send(msg, cmd);
- break;
- case glesv2debugger::Message_Function_SKIP:
- return;
- case glesv2debugger::Message_Function_SETPROP:
- SetProp(dbg, cmd);
- Receive(cmd);
- break;
- default:
- GenerateCall(dbg, cmd, msg, NULL);
- msg.set_expect_response(expectResponse);
- if (!expectResponse)
- cmd.set_function(cmd.SKIP);
- Send(msg, cmd);
- break;
- }
- }
-}
-
void Debug_glDrawArrays(GLenum mode, GLint first, GLsizei count)
{
DbgContext * const dbg = getDbgContextThreadSpecific();
glesv2debugger::Message msg, cmd;
msg.set_context_id(reinterpret_cast<int>(dbg));
msg.set_type(glesv2debugger::Message_Type_BeforeCall);
- const bool expectResponse = dbg->expectResponse.Bit(glesv2debugger::Message_Function_glDrawArrays);
+ bool expectResponse = dbg->expectResponse.Bit(glesv2debugger::Message_Function_glDrawArrays);
msg.set_expect_response(expectResponse);
msg.set_function(glesv2debugger::Message_Function_glDrawArrays);
msg.set_arg0(mode);
@@ -103,11 +42,14 @@ void Debug_glDrawArrays(GLenum mode, GLint first, GLsizei count)
}
void * pixels = NULL;
- GLint readFormat = 0, readType = 0;
int viewport[4] = {};
- if (!expectResponse)
+ if (!expectResponse) {
cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
+ cmd.set_expect_response(false);
+ }
+ glesv2debugger::Message_Function oldCmd = cmd.function();
Send(msg, cmd);
+ expectResponse = cmd.expect_response();
while (true) {
msg.Clear();
nsecs_t c0 = systemTime(timeMode);
@@ -121,31 +63,47 @@ void Debug_glDrawArrays(GLenum mode, GLint first, GLsizei count)
msg.set_expect_response(expectResponse);
if (!expectResponse)
cmd.set_function(glesv2debugger::Message_Function_SKIP);
+ if (!expectResponse) {
+ cmd.set_function(glesv2debugger::Message_Function_SKIP);
+ cmd.set_expect_response(false);
+ }
+ oldCmd = cmd.function();
Send(msg, cmd);
- if (capture) {
+ expectResponse = cmd.expect_response();
+ // TODO: pack glReadPixels data with vertex data instead of
+ // relying on sperate call for transport, this would allow
+ // auto generated message loop using EXTEND_Debug macro
+ if (dbg->captureDraw > 0) {
+ dbg->captureDraw--;
dbg->hooks->gl.glGetIntegerv(GL_VIEWPORT, viewport);
- dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readFormat);
- dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &readType);
// LOGD("glDrawArrays CAPTURE: x=%d y=%d width=%d height=%d format=0x%.4X type=0x%.4X",
// viewport[0], viewport[1], viewport[2], viewport[3], readFormat, readType);
pixels = dbg->GetReadPixelsBuffer(viewport[2] * viewport[3] *
- GetBytesPerPixel(readFormat, readType));
+ dbg->readBytesPerPixel);
Debug_glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3],
- readFormat, readType, pixels);
+ dbg->readFormat, dbg->readType, pixels);
}
break;
case glesv2debugger::Message_Function_SKIP:
return;
case glesv2debugger::Message_Function_SETPROP:
SetProp(dbg, cmd);
- Receive(cmd);
+ expectResponse = cmd.expect_response();
+ if (!expectResponse) // SETPROP is "out of band"
+ cmd.set_function(oldCmd);
+ else
+ Receive(cmd);
break;
default:
GenerateCall(dbg, cmd, msg, NULL);
msg.set_expect_response(expectResponse);
- if (!expectResponse)
+ if (!expectResponse) {
cmd.set_function(cmd.SKIP);
+ cmd.set_expect_response(expectResponse);
+ }
+ oldCmd = cmd.function();
Send(msg, cmd);
+ expectResponse = cmd.expect_response();
break;
}
}
@@ -169,7 +127,7 @@ void Debug_glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid*
glesv2debugger::Message msg, cmd;
msg.set_context_id(reinterpret_cast<int>(dbg));
msg.set_type(glesv2debugger::Message_Type_BeforeCall);
- const bool expectResponse = dbg->expectResponse.Bit(glesv2debugger::Message_Function_glDrawElements);
+ bool expectResponse = dbg->expectResponse.Bit(glesv2debugger::Message_Function_glDrawElements);
msg.set_expect_response(expectResponse);
msg.set_function(glesv2debugger::Message_Function_glDrawElements);
msg.set_arg0(mode);
@@ -195,11 +153,14 @@ void Debug_glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid*
assert(0);
void * pixels = NULL;
- GLint readFormat = 0, readType = 0;
int viewport[4] = {};
- if (!expectResponse)
+ if (!expectResponse) {
cmd.set_function(glesv2debugger::Message_Function_CONTINUE);
+ cmd.set_expect_response(false);
+ }
+ glesv2debugger::Message_Function oldCmd = cmd.function();
Send(msg, cmd);
+ expectResponse = cmd.expect_response();
while (true) {
msg.Clear();
nsecs_t c0 = systemTime(timeMode);
@@ -213,31 +174,45 @@ void Debug_glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid*
msg.set_expect_response(expectResponse);
if (!expectResponse)
cmd.set_function(glesv2debugger::Message_Function_SKIP);
+ if (!expectResponse) {
+ cmd.set_function(glesv2debugger::Message_Function_SKIP);
+ cmd.set_expect_response(false);
+ }
+ oldCmd = cmd.function();
Send(msg, cmd);
- if (capture) {
+ expectResponse = cmd.expect_response();
+ // TODO: pack glReadPixels data with vertex data instead of
+ // relying on sperate call for transport, this would allow
+ // auto generated message loop using EXTEND_Debug macro
+ if (dbg->captureDraw > 0) {
+ dbg->captureDraw--;
dbg->hooks->gl.glGetIntegerv(GL_VIEWPORT, viewport);
- dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &readFormat);
- dbg->hooks->gl.glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &readType);
-// LOGD("glDrawArrays CAPTURE: x=%d y=%d width=%d height=%d format=0x%.4X type=0x%.4X",
-// viewport[0], viewport[1], viewport[2], viewport[3], readFormat, readType);
pixels = dbg->GetReadPixelsBuffer(viewport[2] * viewport[3] *
- GetBytesPerPixel(readFormat, readType));
+ dbg->readBytesPerPixel);
Debug_glReadPixels(viewport[0], viewport[1], viewport[2], viewport[3],
- readFormat, readType, pixels);
+ dbg->readFormat, dbg->readType, pixels);
}
break;
case glesv2debugger::Message_Function_SKIP:
return;
case glesv2debugger::Message_Function_SETPROP:
SetProp(dbg, cmd);
- Receive(cmd);
+ expectResponse = cmd.expect_response();
+ if (!expectResponse) // SETPROP is "out of band"
+ cmd.set_function(oldCmd);
+ else
+ Receive(cmd);
break;
default:
GenerateCall(dbg, cmd, msg, NULL);
msg.set_expect_response(expectResponse);
- if (!expectResponse)
+ if (!expectResponse) {
cmd.set_function(cmd.SKIP);
+ cmd.set_expect_response(expectResponse);
+ }
+ oldCmd = cmd.function();
Send(msg, cmd);
+ expectResponse = cmd.expect_response();
break;
}
}
diff --git a/opengl/libs/egl_tls.h b/opengl/libs/egl_tls.h
new file mode 100644
index 000000000000..087989a06e12
--- /dev/null
+++ b/opengl/libs/egl_tls.h
@@ -0,0 +1,40 @@
+/*
+ ** Copyright 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_EGL_TLS_H
+#define ANDROID_EGL_TLS_H
+
+#include <EGL/egl.h>
+
+#include "glesv2dbg.h"
+
+namespace android
+{
+struct tls_t {
+ tls_t() : error(EGL_SUCCESS), ctx(0), logCallWithNoContext(EGL_TRUE), dbg(0) { }
+ ~tls_t() {
+ if (dbg)
+ DestroyDbgContext(dbg);
+ }
+
+ EGLint error;
+ EGLContext ctx;
+ EGLBoolean logCallWithNoContext;
+ DbgContext* dbg;
+};
+}
+
+#endif
diff --git a/opengl/libs/glesv2dbg.h b/opengl/libs/glesv2dbg.h
index 8029dcedf933..ee2c0112dd0d 100644
--- a/opengl/libs/glesv2dbg.h
+++ b/opengl/libs/glesv2dbg.h
@@ -13,20 +13,27 @@
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-
+
#ifndef _GLESV2_DBG_H_
#define _GLESV2_DBG_H_
+#include <pthread.h>
+
namespace android
{
- struct DbgContext;
-
- DbgContext * CreateDbgContext(const unsigned version, const gl_hooks_t * const hooks);
- void DestroyDbgContext(DbgContext * const dbg);
-
- void StartDebugServer(unsigned short port); // create and bind socket if haven't already
- void StopDebugServer(); // close socket if open
-
+struct DbgContext;
+
+DbgContext * CreateDbgContext(const pthread_key_t EGLThreadLocalStorageKey,
+ const unsigned version, const gl_hooks_t * const hooks);
+
+void DestroyDbgContext(DbgContext * const dbg);
+
+// create and bind socket if haven't already, if failed to create socket or
+// forceUseFile, then open /data/local/tmp/dump.gles2dbg, exit when size reached
+void StartDebugServer(const unsigned short port, const bool forceUseFile,
+ const unsigned int maxFileSize, const char * const filePath);
+void StopDebugServer(); // close socket if open
+
}; // namespace android
#endif // #ifndef _GLESV2_DBG_H_
diff --git a/opengl/tools/glgen/gen b/opengl/tools/glgen/gen
index 6c1a2318536b..31f41906ff25 100755
--- a/opengl/tools/glgen/gen
+++ b/opengl/tools/glgen/gen
@@ -21,7 +21,7 @@ mkdir -p out/android/util
echo "package android.graphics;" > out/android/graphics/Canvas.java
echo "public interface Canvas {}" >> out/android/graphics/Canvas.java
-echo "package android.app; import android.content.pm.IPackageManager; public class ActivityThread { public static final ActivityThread currentActivityThread() { return null; } public static final String currentPackageName(){ return null; } public static IPackageManager getPackageManager() { return null;} }" > out/android/app/ActivityThread.java
+echo "package android.app; import android.content.pm.IPackageManager; public class AppGlobals { public static IPackageManager getPackageManager() { return null;} }" > out/android/app/AppGlobals.java
# echo "package android.content; import android.content.pm.PackageManager; public interface Context { public PackageManager getPackageManager(); }" > out/android/content/Context.java
echo "package android.content.pm; public class ApplicationInfo {public int targetSdkVersion;}" > out/android/content/pm/ApplicationInfo.java
echo "package android.content.pm; public interface IPackageManager {ApplicationInfo getApplicationInfo(java.lang.String packageName, int flags) throws android.os.RemoteException;}" > out/android/content/pm/IPackageManager.java
diff --git a/opengl/tools/glgen/src/JniCodeEmitter.java b/opengl/tools/glgen/src/JniCodeEmitter.java
index 9d8c5a061698..9fa2b7418cca 100644
--- a/opengl/tools/glgen/src/JniCodeEmitter.java
+++ b/opengl/tools/glgen/src/JniCodeEmitter.java
@@ -58,7 +58,7 @@ public class JniCodeEmitter {
} else if (baseType.equals("void")) {
// nothing.
} else {
- throw new RuntimeException("Uknown primitive basetype " + baseType);
+ throw new RuntimeException("Unknown primitive basetype " + baseType);
}
return jniName;
}
@@ -200,15 +200,9 @@ public class JniCodeEmitter {
if (emitExceptionCheck) {
out.println(iii + indent + "_exception = 1;");
}
- out.println(iii + indent +
- (mUseCPlusPlus ? "_env" : "(*_env)") +
- "->ThrowNew(" +
- (mUseCPlusPlus ? "" : "_env, ") +
- "IAEClass, " +
- "\"" +
- (isBuffer ?
- "remaining()" : "length - " + offset) +
- " < needed\");");
+ out.println(iii + indent + "jniThrowException(_env, " +
+ "\"java/lang/IllegalArgumentException\", " +
+ "\"" + (isBuffer ? "remaining()" : "length - " + offset) + " < needed\");");
out.println(iii + indent + "goto exit;");
needsExit = true;
out.println(iii + "}");
@@ -302,7 +296,7 @@ public class JniCodeEmitter {
}
return false;
}
-
+
String isRequiresFunc(CFunc cfunc) {
String[] checks = mChecker.getChecks(cfunc.getName());
int index = 1;
@@ -329,109 +323,94 @@ public class JniCodeEmitter {
}
return null;
}
-
+
void emitNativeBoundsChecks(CFunc cfunc, String cname, PrintStream out,
boolean isBuffer, boolean emitExceptionCheck, String offset, String remaining, String iii) {
- String[] checks = mChecker.getChecks(cfunc.getName());
-
- boolean lastWasIfcheck = false;
-
- int index = 1;
- if (checks != null) {
- while (index < checks.length) {
- if (checks[index].startsWith("check")) {
- if (lastWasIfcheck) {
- printIfcheckPostamble(out, isBuffer, emitExceptionCheck,
- offset, remaining, iii);
- }
- lastWasIfcheck = false;
- if (cname != null && !cname.equals(checks[index + 1])) {
- index += 3;
- continue;
- }
- out.println(iii + "if (" + remaining + " < " +
- checks[index + 2] +
- ") {");
- if (emitExceptionCheck) {
- out.println(iii + indent + "_exception = 1;");
- }
- String exceptionClassName = "IAEClass";
+ String[] checks = mChecker.getChecks(cfunc.getName());
+
+ boolean lastWasIfcheck = false;
+
+ int index = 1;
+ if (checks != null) {
+ while (index < checks.length) {
+ if (checks[index].startsWith("check")) {
+ if (lastWasIfcheck) {
+ printIfcheckPostamble(out, isBuffer, emitExceptionCheck,
+ offset, remaining, iii);
+ }
+ lastWasIfcheck = false;
+ if (cname != null && !cname.equals(checks[index + 1])) {
+ index += 3;
+ continue;
+ }
+ out.println(iii + "if (" + remaining + " < " + checks[index + 2] + ") {");
+ if (emitExceptionCheck) {
+ out.println(iii + indent + "_exception = 1;");
+ }
+ String exceptionClassName = "java/lang/IllegalArgumentException";
// If the "check" keyword was of the form
// "check_<class name>", use the class name in the
// exception to be thrown
int underscore = checks[index].indexOf('_');
if (underscore >= 0) {
- exceptionClassName = checks[index].substring(underscore + 1) + "Class";
- }
- out.println(iii + indent +
- (mUseCPlusPlus ? "_env" : "(*_env)") +
- "->ThrowNew(" +
- (mUseCPlusPlus ? "" : "_env, ") +
- exceptionClassName + ", " +
- "\"" +
- (isBuffer ?
- "remaining()" : "length - " + offset) +
- " < " + checks[index + 2] +
- "\");");
-
- out.println(iii + indent + "goto exit;");
- needsExit = true;
- out.println(iii + "}");
-
- index += 3;
- } else if (checks[index].equals("ifcheck")) {
- String[] matches = checks[index + 4].split(",");
-
- if (!lastWasIfcheck) {
- out.println(iii + "int _needed;");
- out.println(iii +
- "switch (" +
- checks[index + 3] +
- ") {");
- }
-
- for (int i = 0; i < matches.length; i++) {
- out.println("#if defined(" + matches[i] + ")");
- out.println(iii +
- " case " +
- matches[i] +
- ":");
- out.println("#endif // defined(" + matches[i] + ")");
- }
- out.println(iii +
- " _needed = " +
- checks[index + 2] +
- ";");
- out.println(iii +
- " break;");
-
- lastWasIfcheck = true;
- index += 5;
- } else if (checks[index].equals("return")) {
- // ignore
- index += 2;
- } else if (checks[index].equals("unsupported")) {
- // ignore
- index += 1;
- } else if (checks[index].equals("requires")) {
- // ignore
- index += 2;
- } else if (checks[index].equals("nullAllowed")) {
- // ignore
- index += 1;
+ String abbr = checks[index].substring(underscore + 1);
+ if (abbr.equals("AIOOBE")) {
+ exceptionClassName = "java/lang/ArrayIndexOutOfBoundsException";
} else {
- System.out.println("Error: unknown keyword \"" +
- checks[index] + "\"");
- System.exit(0);
+ throw new RuntimeException("unknown exception abbreviation: " + abbr);
}
}
- }
+ out.println(iii + indent + "jniThrowException(_env, " +
+ "\"" + exceptionClassName + "\", " +
+ "\"" + (isBuffer ? "remaining()" : "length - " + offset) + " < " + checks[index + 2] + "\");");
+
+ out.println(iii + indent + "goto exit;");
+ needsExit = true;
+ out.println(iii + "}");
+
+ index += 3;
+ } else if (checks[index].equals("ifcheck")) {
+ String[] matches = checks[index + 4].split(",");
+
+ if (!lastWasIfcheck) {
+ out.println(iii + "int _needed;");
+ out.println(iii + "switch (" + checks[index + 3] + ") {");
+ }
+
+ for (int i = 0; i < matches.length; i++) {
+ out.println("#if defined(" + matches[i] + ")");
+ out.println(iii + " case " + matches[i] + ":");
+ out.println("#endif // defined(" + matches[i] + ")");
+ }
+ out.println(iii + " _needed = " + checks[index + 2] + ";");
+ out.println(iii + " break;");
- if (lastWasIfcheck) {
- printIfcheckPostamble(out, isBuffer, emitExceptionCheck, iii);
+ lastWasIfcheck = true;
+ index += 5;
+ } else if (checks[index].equals("return")) {
+ // ignore
+ index += 2;
+ } else if (checks[index].equals("unsupported")) {
+ // ignore
+ index += 1;
+ } else if (checks[index].equals("requires")) {
+ // ignore
+ index += 2;
+ } else if (checks[index].equals("nullAllowed")) {
+ // ignore
+ index += 1;
+ } else {
+ System.out.println("Error: unknown keyword \"" + checks[index] + "\"");
+ System.exit(0);
}
}
+ }
+
+ if (lastWasIfcheck) {
+ printIfcheckPostamble(out, isBuffer, emitExceptionCheck, iii);
+ }
+ }
boolean hasNonConstArg(JFunc jfunc, CFunc cfunc, List<Integer> nonPrimitiveArgs) {
if (nonPrimitiveArgs.size() > 0) {
@@ -817,7 +796,7 @@ public class JniCodeEmitter {
boolean isUnsupported = isUnsupportedFunc(cfunc);
if (isUnsupported) {
out.println(indent +
- "_env->ThrowNew(UOEClass,");
+ "jniThrowException(_env, \"java/lang/UnsupportedOperationException\",");
out.println(indent +
" \"" + cfunc.getName() + "\");");
if (!isVoid) {
@@ -828,13 +807,13 @@ public class JniCodeEmitter {
out.println();
return;
}
-
+
String requiresExtension = isRequiresFunc(cfunc);
if (requiresExtension != null) {
out.println(indent +
"if (! supportsExtension(_env, _this, have_" + requiresExtension + "ID)) {");
out.println(indent + indent +
- "_env->ThrowNew(UOEClass,");
+ "jniThrowException(_env, \"java/lang/UnsupportedOperationException\",");
out.println(indent + indent +
" \"" + cfunc.getName() + "\");");
if (isVoid) {
@@ -945,7 +924,8 @@ public class JniCodeEmitter {
CType type = cfunc.getArgType(jfunc.getArgCIndex(idx));
String decl = type.getDeclaration();
out.println(indent + "if (!" + cname + ") {");
- out.println(indent + " _env->ThrowNew(IAEClass, \"" + cname + " == null\");");
+ out.println(indent + " jniThrowException(_env, " +
+ "\"java/lang/IllegalArgumentException\", \"" + cname + " == null\");");
out.println(indent + " goto exit;");
needsExit = true;
out.println(indent + "}");
@@ -978,13 +958,9 @@ public class JniCodeEmitter {
if (emitExceptionCheck) {
out.println(indent + indent + "_exception = 1;");
}
- out.println(indent + " " +
- (mUseCPlusPlus ? "_env" : "(*_env)") +
- "->ThrowNew(" +
- (mUseCPlusPlus ? "" : "_env, ") +
- "IAEClass, " +
- "\"" + cname +
- " == null\");");
+ out.println(indent + " jniThrowException(_env, " +
+ "\"java/lang/IllegalArgumentException\", " +
+ "\"" + cname + " == null\");");
out.println(indent + " goto exit;");
needsExit = true;
out.println(indent + "}");
@@ -993,12 +969,8 @@ public class JniCodeEmitter {
if (emitExceptionCheck) {
out.println(indent + indent + "_exception = 1;");
}
- out.println(indent + " " +
- (mUseCPlusPlus ? "_env" : "(*_env)") +
- "->ThrowNew(" +
- (mUseCPlusPlus ? "" : "_env, ") +
- "IAEClass, " +
- "\"" + offset + " < 0\");");
+ out.println(indent + " jniThrowException(_env, " +
+ "\"java/lang/IllegalArgumentException\", \"" + offset + " < 0\");");
out.println(indent + " goto exit;");
needsExit = true;
out.println(indent + "}");
diff --git a/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp
index 294d1ce82e72..5d418d7c4024 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES10ExtcHeader.cpp
@@ -1,21 +1,23 @@
**
** Copyright 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
+** 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
+** 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
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
// This source file is automatically generated
+#include "jni.h"
+#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
@@ -27,10 +29,6 @@ static int initialized = 0;
static jclass nioAccessClass;
static jclass bufferClass;
-static jclass OOMEClass;
-static jclass UOEClass;
-static jclass IAEClass;
-static jclass AIOOBEClass;
static jmethodID getBasePointerID;
static jmethodID getBaseArrayID;
static jmethodID getBaseArrayOffsetID;
@@ -41,7 +39,7 @@ static jfieldID elementSizeShiftID;
/* Cache method IDs each time the class is loaded. */
static void
-nativeClassInitBuffer(JNIEnv *_env)
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
{
jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
@@ -63,26 +61,6 @@ nativeClassInitBuffer(JNIEnv *_env)
}
-static void
-nativeClassInit(JNIEnv *_env, jclass glImplClass)
-{
- nativeClassInitBuffer(_env);
-
- jclass IAEClassLocal =
- _env->FindClass("java/lang/IllegalArgumentException");
- jclass OOMEClassLocal =
- _env->FindClass("java/lang/OutOfMemoryError");
- jclass UOEClassLocal =
- _env->FindClass("java/lang/UnsupportedOperationException");
- jclass AIOOBEClassLocal =
- _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
-
- IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
- OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
- UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
- AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
-}
-
static void *
getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
{
@@ -103,13 +81,13 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
*array = NULL;
return (void *) (jint) pointer;
}
-
+
*array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
getBaseArrayID, buffer);
offset = _env->CallStaticIntMethod(nioAccessClass,
getBaseArrayOffsetID, buffer);
data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-
+
return (void *) ((char *) data + offset);
}
@@ -122,4 +100,3 @@ releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit)
}
// --------------------------------------------------------------------------
-
diff --git a/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp
index e1c09f4614d6..35a3c333a6a1 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES10cHeader.cpp
@@ -1,21 +1,23 @@
**
** Copyright 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
+** 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
+** 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
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
// This source file is automatically generated
+#include "jni.h"
+#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
@@ -40,10 +42,6 @@ static int initialized = 0;
static jclass nioAccessClass;
static jclass bufferClass;
-static jclass OOMEClass;
-static jclass UOEClass;
-static jclass IAEClass;
-static jclass AIOOBEClass;
static jmethodID getBasePointerID;
static jmethodID getBaseArrayID;
static jmethodID getBaseArrayOffsetID;
@@ -54,7 +52,7 @@ static jfieldID elementSizeShiftID;
/* Cache method IDs each time the class is loaded. */
static void
-nativeClassInitBuffer(JNIEnv *_env)
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
{
jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
@@ -75,26 +73,6 @@ nativeClassInitBuffer(JNIEnv *_env)
_env->GetFieldID(bufferClass, "_elementSizeShift", "I");
}
-static void
-nativeClassInit(JNIEnv *_env, jclass glImplClass)
-{
- nativeClassInitBuffer(_env);
-
- jclass IAEClassLocal =
- _env->FindClass("java/lang/IllegalArgumentException");
- jclass OOMEClassLocal =
- _env->FindClass("java/lang/OutOfMemoryError");
- jclass UOEClassLocal =
- _env->FindClass("java/lang/UnsupportedOperationException");
- jclass AIOOBEClassLocal =
- _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
-
- IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
- OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
- UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
- AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
-}
-
static void *
getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
{
@@ -115,13 +93,13 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
*array = NULL;
return (void *) (jint) pointer;
}
-
+
*array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
getBaseArrayID, buffer);
offset = _env->CallStaticIntMethod(nioAccessClass,
getBaseArrayOffsetID, buffer);
data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-
+
return (void *) ((char *) data + offset);
}
@@ -140,7 +118,8 @@ getDirectBufferPointer(JNIEnv *_env, jobject buffer) {
jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
buf += position << elementSizeShift;
} else {
- _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+ jniThrowException(_env, "java/lang/IllegalArgumentException",
+ "Must use a native order direct Buffer");
}
return (void*) buf;
}
@@ -153,4 +132,3 @@ getNumCompressedTextureFormats() {
}
// --------------------------------------------------------------------------
-
diff --git a/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp
index 2548b32a24c9..9b29a4410920 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES11ExtcHeader.cpp
@@ -1,21 +1,23 @@
**
** Copyright 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
+** 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
+** 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
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
// This source file is automatically generated
+#include "jni.h"
+#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
@@ -36,10 +38,6 @@ static int initialized = 0;
static jclass nioAccessClass;
static jclass bufferClass;
-static jclass OOMEClass;
-static jclass UOEClass;
-static jclass IAEClass;
-static jclass AIOOBEClass;
static jmethodID getBasePointerID;
static jmethodID getBaseArrayID;
static jmethodID getBaseArrayOffsetID;
@@ -50,7 +48,7 @@ static jfieldID elementSizeShiftID;
/* Cache method IDs each time the class is loaded. */
static void
-nativeClassInitBuffer(JNIEnv *_env)
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
{
jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
@@ -72,26 +70,6 @@ nativeClassInitBuffer(JNIEnv *_env)
}
-static void
-nativeClassInit(JNIEnv *_env, jclass glImplClass)
-{
- nativeClassInitBuffer(_env);
-
- jclass IAEClassLocal =
- _env->FindClass("java/lang/IllegalArgumentException");
- jclass OOMEClassLocal =
- _env->FindClass("java/lang/OutOfMemoryError");
- jclass UOEClassLocal =
- _env->FindClass("java/lang/UnsupportedOperationException");
- jclass AIOOBEClassLocal =
- _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
-
- IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
- OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
- UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
- AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
-}
-
static void *
getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
{
@@ -112,13 +90,13 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
*array = NULL;
return (void *) (jint) pointer;
}
-
+
*array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
getBaseArrayID, buffer);
offset = _env->CallStaticIntMethod(nioAccessClass,
getBaseArrayOffsetID, buffer);
data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-
+
return (void *) ((char *) data + offset);
}
@@ -138,9 +116,9 @@ getDirectBufferPointer(JNIEnv *_env, jobject buffer) {
jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
buf += position << elementSizeShift;
} else {
- _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+ jniThrowException(_env, "java/lang/IllegalArgumentException",
+ "Must use a native order direct Buffer");
}
return (void*) buf;
}
// --------------------------------------------------------------------------
-
diff --git a/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp
index 4c297f786950..823079f39f28 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES11cHeader.cpp
@@ -1,21 +1,23 @@
**
** Copyright 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
+** 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
+** 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
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
// This source file is automatically generated
+#include "jni.h"
+#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
@@ -34,10 +36,6 @@ static int initialized = 0;
static jclass nioAccessClass;
static jclass bufferClass;
-static jclass OOMEClass;
-static jclass UOEClass;
-static jclass IAEClass;
-static jclass AIOOBEClass;
static jmethodID getBasePointerID;
static jmethodID getBaseArrayID;
static jmethodID getBaseArrayOffsetID;
@@ -48,7 +46,7 @@ static jfieldID elementSizeShiftID;
/* Cache method IDs each time the class is loaded. */
static void
-nativeClassInitBuffer(JNIEnv *_env)
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
{
jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
@@ -70,26 +68,6 @@ nativeClassInitBuffer(JNIEnv *_env)
}
-static void
-nativeClassInit(JNIEnv *_env, jclass glImplClass)
-{
- nativeClassInitBuffer(_env);
-
- jclass IAEClassLocal =
- _env->FindClass("java/lang/IllegalArgumentException");
- jclass OOMEClassLocal =
- _env->FindClass("java/lang/OutOfMemoryError");
- jclass UOEClassLocal =
- _env->FindClass("java/lang/UnsupportedOperationException");
- jclass AIOOBEClassLocal =
- _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
-
- IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
- OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
- UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
- AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
-}
-
static void *
getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
{
@@ -110,13 +88,13 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
*array = NULL;
return (void *) (jint) pointer;
}
-
+
*array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
getBaseArrayID, buffer);
offset = _env->CallStaticIntMethod(nioAccessClass,
getBaseArrayOffsetID, buffer);
data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-
+
return (void *) ((char *) data + offset);
}
@@ -136,10 +114,10 @@ getDirectBufferPointer(JNIEnv *_env, jobject buffer) {
jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
buf += position << elementSizeShift;
} else {
- _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+ jniThrowException(_env, "java/lang/IllegalArgumentException",
+ "Must use a native order direct Buffer");
}
return (void*) buf;
}
// --------------------------------------------------------------------------
-
diff --git a/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp b/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp
index e451e9ad9023..13a2577c2838 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp
+++ b/opengl/tools/glgen/stubs/gles11/GLES20cHeader.cpp
@@ -1,21 +1,23 @@
**
** Copyright 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
+** 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
+** 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
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
// This source file is automatically generated
+#include "jni.h"
+#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
@@ -27,10 +29,6 @@ static int initialized = 0;
static jclass nioAccessClass;
static jclass bufferClass;
-static jclass OOMEClass;
-static jclass UOEClass;
-static jclass IAEClass;
-static jclass AIOOBEClass;
static jmethodID getBasePointerID;
static jmethodID getBaseArrayID;
static jmethodID getBaseArrayOffsetID;
@@ -41,7 +39,7 @@ static jfieldID elementSizeShiftID;
/* Cache method IDs each time the class is loaded. */
static void
-nativeClassInitBuffer(JNIEnv *_env)
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
{
jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
@@ -63,26 +61,6 @@ nativeClassInitBuffer(JNIEnv *_env)
}
-static void
-nativeClassInit(JNIEnv *_env, jclass glImplClass)
-{
- nativeClassInitBuffer(_env);
-
- jclass IAEClassLocal =
- _env->FindClass("java/lang/IllegalArgumentException");
- jclass OOMEClassLocal =
- _env->FindClass("java/lang/OutOfMemoryError");
- jclass UOEClassLocal =
- _env->FindClass("java/lang/UnsupportedOperationException");
- jclass AIOOBEClassLocal =
- _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
-
- IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
- OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
- UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
- AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
-}
-
static void *
getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
{
@@ -103,13 +81,13 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
*array = NULL;
return (void *) (jint) pointer;
}
-
+
*array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
getBaseArrayID, buffer);
offset = _env->CallStaticIntMethod(nioAccessClass,
getBaseArrayOffsetID, buffer);
data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-
+
return (void *) ((char *) data + offset);
}
@@ -129,7 +107,8 @@ getDirectBufferPointer(JNIEnv *_env, jobject buffer) {
jint elementSizeShift = _env->GetIntField(buffer, elementSizeShiftID);
buf += position << elementSizeShift;
} else {
- _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+ jniThrowException(_env, "java/lang/IllegalArgumentException",
+ "Must use a native order direct Buffer");
}
return (void*) buf;
}
@@ -147,4 +126,3 @@ static void glVertexAttribPointerBounds(GLuint indx, GLint size, GLenum type,
}
// --------------------------------------------------------------------------
-
diff --git a/opengl/tools/glgen/stubs/gles11/glGetProgramInfoLog.cpp b/opengl/tools/glgen/stubs/gles11/glGetProgramInfoLog.cpp
index d92f51598352..ce6ab240443f 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetProgramInfoLog.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetProgramInfoLog.cpp
@@ -1,27 +1,19 @@
-#include <string.h>
+#include <stdlib.h>
/* void glGetProgramInfoLog ( GLuint shader, GLsizei maxLength, GLsizei* length, GLchar* infoLog ) */
-static
-jstring
-android_glGetProgramInfoLog (JNIEnv *_env, jobject _this, jint shader) {
+static jstring android_glGetProgramInfoLog(JNIEnv *_env, jobject, jint shader) {
GLint infoLen = 0;
- jstring _result = 0;
- char* buf = 0;
glGetProgramiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
- if (infoLen) {
- char* buf = (char*) malloc(infoLen);
- if (buf == 0) {
- _env->ThrowNew(IAEClass, "out of memory");
- goto exit;
- }
- glGetProgramInfoLog(shader, infoLen, NULL, buf);
- _result = _env->NewStringUTF(buf);
- } else {
- _result = _env->NewStringUTF("");
+ if (!infoLen) {
+ return _env->NewStringUTF("");
}
-exit:
- if (buf) {
- free(buf);
+ char* buf = (char*) malloc(infoLen);
+ if (buf == NULL) {
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "out of memory");
+ return NULL;
}
- return _result;
-} \ No newline at end of file
+ glGetProgramInfoLog(shader, infoLen, NULL, buf);
+ jstring result = _env->NewStringUTF(buf);
+ free(buf);
+ return result;
+}
diff --git a/opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.cpp b/opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.cpp
index 5441d66817a0..dd656b60c127 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetShaderInfoLog.cpp
@@ -1,27 +1,19 @@
-#include <string.h>
+#include <stdlib.h>
/* void glGetShaderInfoLog ( GLuint shader, GLsizei maxLength, GLsizei* length, GLchar* infoLog ) */
-static
-jstring
-android_glGetShaderInfoLog (JNIEnv *_env, jobject _this, jint shader) {
+static jstring android_glGetShaderInfoLog(JNIEnv *_env, jobject, jint shader) {
GLint infoLen = 0;
- jstring _result = 0;
- char* buf = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
- if (infoLen) {
- char* buf = (char*) malloc(infoLen);
- if (buf == 0) {
- _env->ThrowNew(IAEClass, "out of memory");
- goto exit;
- }
- glGetShaderInfoLog(shader, infoLen, NULL, buf);
- _result = _env->NewStringUTF(buf);
- } else {
- _result = _env->NewStringUTF("");
+ if (!infoLen) {
+ return _env->NewStringUTF("");
}
-exit:
- if (buf) {
- free(buf);
+ char* buf = (char*) malloc(infoLen);
+ if (buf == NULL) {
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "out of memory");
+ return NULL;
}
- return _result;
-} \ No newline at end of file
+ glGetShaderInfoLog(shader, infoLen, NULL, buf);
+ jstring result = _env->NewStringUTF(buf);
+ free(buf);
+ return result;
+}
diff --git a/opengl/tools/glgen/stubs/gles11/glGetString.cpp b/opengl/tools/glgen/stubs/gles11/glGetString.cpp
index a400859f771f..239fe4ac2e64 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetString.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetString.cpp
@@ -1,11 +1,5 @@
-#include <string.h>
-
/* const GLubyte * glGetString ( GLenum name ) */
-static
-jstring
-android_glGetString
- (JNIEnv *_env, jobject _this, jint name) {
- const char * chars = (const char *)glGetString((GLenum)name);
- jstring output = _env->NewStringUTF(chars);
- return output;
+static jstring android_glGetString(JNIEnv* _env, jobject, jint name) {
+ const char* chars = (const char*) glGetString((GLenum) name);
+ return _env->NewStringUTF(chars);
}
diff --git a/opengl/tools/glgen/stubs/gles11/glShaderSource.cpp b/opengl/tools/glgen/stubs/gles11/glShaderSource.cpp
index c2741089a6bd..125fd0ff1992 100644
--- a/opengl/tools/glgen/stubs/gles11/glShaderSource.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glShaderSource.cpp
@@ -6,7 +6,7 @@ android_glShaderSource
(JNIEnv *_env, jobject _this, jint shader, jstring string) {
if (!string) {
- _env->ThrowNew(IAEClass, "string == null");
+ jniThrowException(_env, "java/lang/IllegalArgumentException", "string == null");
return;
}
diff --git a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
index c2464b05626e..f7315eefdddf 100644
--- a/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
+++ b/opengl/tools/glgen/stubs/jsr239/GLCHeader.cpp
@@ -1,21 +1,23 @@
**
** Copyright 2006, 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
+** 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
+** 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
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
// This source file is automatically generated
+#include "jni.h"
+#include "JNIHelp.h"
#include <android_runtime/AndroidRuntime.h>
#include <utils/misc.h>
@@ -63,10 +65,6 @@ static int initialized = 0;
static jclass nioAccessClass;
static jclass bufferClass;
-static jclass OOMEClass;
-static jclass UOEClass;
-static jclass IAEClass;
-static jclass AIOOBEClass;
static jclass G11ImplClass;
static jmethodID getBasePointerID;
static jmethodID getBaseArrayID;
@@ -84,7 +82,7 @@ static jfieldID have_OES_texture_cube_mapID;
/* Cache method IDs each time the class is loaded. */
static void
-nativeClassInitBuffer(JNIEnv *_env)
+nativeClassInit(JNIEnv *_env, jclass glImplClass)
{
jclass nioAccessClassLocal = _env->FindClass("java/nio/NIOAccess");
nioAccessClass = (jclass) _env->NewGlobalRef(nioAccessClassLocal);
@@ -114,26 +112,6 @@ nativeClassInitBuffer(JNIEnv *_env)
_env->GetFieldID(bufferClass, "_elementSizeShift", "I");
}
-static void
-nativeClassInit(JNIEnv *_env, jclass glImplClass)
-{
- nativeClassInitBuffer(_env);
-
- jclass IAEClassLocal =
- _env->FindClass("java/lang/IllegalArgumentException");
- jclass OOMEClassLocal =
- _env->FindClass("java/lang/OutOfMemoryError");
- jclass UOEClassLocal =
- _env->FindClass("java/lang/UnsupportedOperationException");
- jclass AIOOBEClassLocal =
- _env->FindClass("java/lang/ArrayIndexOutOfBoundsException");
-
- IAEClass = (jclass) _env->NewGlobalRef(IAEClassLocal);
- OOMEClass = (jclass) _env->NewGlobalRef(OOMEClassLocal);
- UOEClass = (jclass) _env->NewGlobalRef(UOEClassLocal);
- AIOOBEClass = (jclass) _env->NewGlobalRef(AIOOBEClassLocal);
-}
-
static void *
getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
{
@@ -154,7 +132,7 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
*array = NULL;
return (void *) (jint) pointer;
}
-
+
*array = (jarray) _env->CallStaticObjectMethod(nioAccessClass,
getBaseArrayID, buffer);
if (*array == NULL) {
@@ -163,7 +141,7 @@ getPointer(JNIEnv *_env, jobject buffer, jarray *array, jint *remaining)
offset = _env->CallStaticIntMethod(nioAccessClass,
getBaseArrayOffsetID, buffer);
data = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-
+
return (void *) ((char *) data + offset);
}
@@ -207,7 +185,8 @@ getDirectBufferPointer(JNIEnv *_env, jobject buffer) {
releasePointer(_env, array, buf, 0);
}
} else {
- _env->ThrowNew(IAEClass, "Must use a native order direct Buffer");
+ jniThrowException(_env, "java/lang/IllegalArgumentException",
+ "Must use a native order direct Buffer");
}
}
return buf;
@@ -250,7 +229,7 @@ nextExtension(const GLubyte* pExtensions) {
}
}
}
-
+
static bool
checkForExtension(const GLubyte* pExtensions, const GLubyte* pExtension) {
for (;*pExtensions != '\0'; pExtensions = nextExtension(pExtensions)) {
@@ -279,4 +258,3 @@ supportsExtension(JNIEnv *_env, jobject impl, jfieldID fieldId) {
}
// --------------------------------------------------------------------------
-
diff --git a/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl b/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl
index 372710625e4c..cd730aa95b21 100644
--- a/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl
+++ b/opengl/tools/glgen/stubs/jsr239/GLImplHeader.java-impl
@@ -18,7 +18,7 @@
package com.google.android.gles_jni;
-import android.app.ActivityThread;
+import android.app.AppGlobals;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.os.Build;
@@ -64,7 +64,7 @@ public class GLImpl implements GL10, GL10Ext, GL11, GL11Ext, GL11ExtensionPack {
private static boolean allowIndirectBuffers(String appName) {
boolean result = false;
int version = 0;
- IPackageManager pm = ActivityThread.getPackageManager();
+ IPackageManager pm = AppGlobals.getPackageManager();
try {
ApplicationInfo applicationInfo = pm.getApplicationInfo(appName, 0);
if (applicationInfo != null) {
diff --git a/opengl/tools/glgen/stubs/jsr239/glGetString.cpp b/opengl/tools/glgen/stubs/jsr239/glGetString.cpp
index a400859f771f..cd6e3f39578a 100644
--- a/opengl/tools/glgen/stubs/jsr239/glGetString.cpp
+++ b/opengl/tools/glgen/stubs/jsr239/glGetString.cpp
@@ -1,11 +1,5 @@
-#include <string.h>
-
/* const GLubyte * glGetString ( GLenum name ) */
-static
-jstring
-android_glGetString
- (JNIEnv *_env, jobject _this, jint name) {
- const char * chars = (const char *)glGetString((GLenum)name);
- jstring output = _env->NewStringUTF(chars);
- return output;
+static jstring android_glGetString(JNIEnv *_env, jobject, jint name) {
+ const char* chars = (const char*) glGetString((GLenum) name);
+ return _env->NewStringUTF(chars);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentApplicationsActivity.java b/packages/SystemUI/src/com/android/systemui/recent/RecentApplicationsActivity.java
index 8c6eefb358b5..7d4629e89357 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentApplicationsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentApplicationsActivity.java
@@ -410,7 +410,7 @@ public class RecentApplicationsActivity extends Activity {
void updateRunningTasks() {
mRunningTaskList = mActivityManager.getRunningTasks(MAX_TASKS,
- ActivityManager.TASKS_GET_THUMBNAILS, mThumbnailReceiver);
+ 0, mThumbnailReceiver);
if (DBG) Log.v(TAG, "Portrait: " + mPortraitMode);
for (RunningTaskInfo r : mRunningTaskList) {
if (r.thumbnail != null) {
@@ -441,8 +441,7 @@ public class RecentApplicationsActivity extends Activity {
final ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
final List<ActivityManager.RecentTaskInfo> recentTasks =
- am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE
- | ActivityManager.TASKS_GET_THUMBNAILS);
+ am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
.resolveActivityInfo(pm, 0);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
index a39bef8daf26..cfb49751f5ab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/RecentAppsPanel.java
@@ -429,8 +429,7 @@ public class RecentAppsPanel extends RelativeLayout implements StatusBarPanel, O
mContext.getSystemService(Context.ACTIVITY_SERVICE);
final List<ActivityManager.RecentTaskInfo> recentTasks =
- am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE
- | ActivityManager.TASKS_GET_THUMBNAILS);
+ am.getRecentTasks(MAX_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE);
ActivityInfo homeInfo = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)
.resolveActivityInfo(pm, 0);
diff --git a/packages/TtsService/Android.mk b/packages/TtsService/Android.mk
deleted file mode 100644
index a1a3b9f77e01..000000000000
--- a/packages/TtsService/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files) \
-
-LOCAL_PACKAGE_NAME := TtsService
-LOCAL_CERTIFICATE := platform
-
-LOCAL_PROGUARD_FLAG_FILES := proguard.flags
-
-include $(BUILD_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/TtsService/AndroidManifest.xml b/packages/TtsService/AndroidManifest.xml
deleted file mode 100755
index 46e0ad100c5a..000000000000
--- a/packages/TtsService/AndroidManifest.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.tts">
- <application android:label="TTS Service"
- android:icon="@drawable/ic_launcher_text_to_speech">
- <service android:enabled="true"
- android:name=".TtsService"
- android:label="TTS Service">
- <intent-filter>
- <action android:name="android.intent.action.START_TTS_SERVICE"/>
- <category android:name="android.intent.category.TTS"/>
- </intent-filter>
- </service>
- </application>
- <uses-permission android:name="android.permission.INTERNET"/>
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-</manifest>
diff --git a/packages/TtsService/MODULE_LICENSE_APACHE2 b/packages/TtsService/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/packages/TtsService/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/packages/TtsService/NOTICE b/packages/TtsService/NOTICE
deleted file mode 100644
index 64aaa8dbd68e..000000000000
--- a/packages/TtsService/NOTICE
+++ /dev/null
@@ -1,190 +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.
-
- 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.
-
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
diff --git a/packages/TtsService/jni/Android.mk b/packages/TtsService/jni/Android.mk
deleted file mode 100755
index 5dc0c305900b..000000000000
--- a/packages/TtsService/jni/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- android_tts_SynthProxy.cpp
-
-LOCAL_C_INCLUDES += \
- frameworks/base/native/include \
- $(JNI_H_INCLUDE)
-
-LOCAL_SHARED_LIBRARIES := \
- libandroid_runtime \
- libnativehelper \
- libmedia \
- libutils \
- libcutils
-
-ifeq ($(TARGET_SIMULATOR),true)
- LOCAL_LDLIBS += -ldl
-else
- LOCAL_SHARED_LIBRARIES += libdl
-endif
-
-
-LOCAL_MODULE:= libttssynthproxy
-
-LOCAL_ARM_MODE := arm
-
-include $(BUILD_SHARED_LIBRARY)
-
diff --git a/packages/TtsService/jni/android_tts_SynthProxy.cpp b/packages/TtsService/jni/android_tts_SynthProxy.cpp
deleted file mode 100644
index e00fa852f41a..000000000000
--- a/packages/TtsService/jni/android_tts_SynthProxy.cpp
+++ /dev/null
@@ -1,1071 +0,0 @@
-/*
- * Copyright (C) 2009-2010 Google Inc.
- *
- * 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 <stdio.h>
-#include <unistd.h>
-
-#define LOG_TAG "SynthProxyJNI"
-
-#include <utils/Log.h>
-#include <nativehelper/jni.h>
-#include <nativehelper/JNIHelp.h>
-#include <android_runtime/AndroidRuntime.h>
-#include <android/tts.h>
-#include <media/AudioTrack.h>
-#include <math.h>
-
-#include <dlfcn.h>
-
-#define DEFAULT_TTS_RATE 16000
-#define DEFAULT_TTS_FORMAT AudioSystem::PCM_16_BIT
-#define DEFAULT_TTS_NB_CHANNELS 1
-#define DEFAULT_TTS_BUFFERSIZE 2048
-#define DEFAULT_TTS_STREAM_TYPE AudioSystem::MUSIC
-#define DEFAULT_VOLUME 1.0f
-
-// EQ + BOOST parameters
-#define FILTER_LOWSHELF_ATTENUATION -18.0f // in dB
-#define FILTER_TRANSITION_FREQ 1100.0f // in Hz
-#define FILTER_SHELF_SLOPE 1.0f // Q
-#define FILTER_GAIN 5.5f // linear gain
-
-#define USAGEMODE_PLAY_IMMEDIATELY 0
-#define USAGEMODE_WRITE_TO_FILE 1
-
-#define SYNTHPLAYSTATE_IS_STOPPED 0
-#define SYNTHPLAYSTATE_IS_PLAYING 1
-
-using namespace android;
-
-// ----------------------------------------------------------------------------
-struct fields_t {
- jfieldID synthProxyFieldJniData;
- jmethodID synthProxyMethodPost;
-};
-
-// structure to hold the data that is used each time the TTS engine has synthesized more data
-struct afterSynthData_t {
- jint jniStorage;
- int usageMode;
- FILE* outputFile;
- AudioSystem::stream_type streamType;
-};
-
-// ----------------------------------------------------------------------------
-// EQ data
-double amp;
-double w;
-double sinw;
-double cosw;
-double beta;
-double a0, a1, a2, b0, b1, b2;
-double m_fa, m_fb, m_fc, m_fd, m_fe;
-double x0; // x[n]
-double x1; // x[n-1]
-double x2; // x[n-2]
-double out0;// y[n]
-double out1;// y[n-1]
-double out2;// y[n-2]
-
-static float fFilterLowshelfAttenuation = FILTER_LOWSHELF_ATTENUATION;
-static float fFilterTransitionFreq = FILTER_TRANSITION_FREQ;
-static float fFilterShelfSlope = FILTER_SHELF_SLOPE;
-static float fFilterGain = FILTER_GAIN;
-static bool bUseFilter = false;
-
-void initializeEQ() {
-
- amp = float(pow(10.0, fFilterLowshelfAttenuation / 40.0));
- w = 2.0 * M_PI * (fFilterTransitionFreq / DEFAULT_TTS_RATE);
- sinw = float(sin(w));
- cosw = float(cos(w));
- beta = float(sqrt(amp)/fFilterShelfSlope);
-
- // initialize low-shelf parameters
- b0 = amp * ((amp+1.0F) - ((amp-1.0F)*cosw) + (beta*sinw));
- b1 = 2.0F * amp * ((amp-1.0F) - ((amp+1.0F)*cosw));
- b2 = amp * ((amp+1.0F) - ((amp-1.0F)*cosw) - (beta*sinw));
- a0 = (amp+1.0F) + ((amp-1.0F)*cosw) + (beta*sinw);
- a1 = 2.0F * ((amp-1.0F) + ((amp+1.0F)*cosw));
- a2 = -((amp+1.0F) + ((amp-1.0F)*cosw) - (beta*sinw));
-
- m_fa = fFilterGain * b0/a0;
- m_fb = fFilterGain * b1/a0;
- m_fc = fFilterGain * b2/a0;
- m_fd = a1/a0;
- m_fe = a2/a0;
-}
-
-void initializeFilter() {
- x0 = 0.0f;
- x1 = 0.0f;
- x2 = 0.0f;
- out0 = 0.0f;
- out1 = 0.0f;
- out2 = 0.0f;
-}
-
-void applyFilter(int16_t* buffer, size_t sampleCount) {
-
- for (size_t i=0 ; i<sampleCount ; i++) {
-
- x0 = (double) buffer[i];
-
- out0 = (m_fa*x0) + (m_fb*x1) + (m_fc*x2) + (m_fd*out1) + (m_fe*out2);
-
- x2 = x1;
- x1 = x0;
-
- out2 = out1;
- out1 = out0;
-
- if (out0 > 32767.0f) {
- buffer[i] = 32767;
- } else if (out0 < -32768.0f) {
- buffer[i] = -32768;
- } else {
- buffer[i] = (int16_t) out0;
- }
- }
-}
-
-
-// ----------------------------------------------------------------------------
-static fields_t javaTTSFields;
-
-// TODO move to synth member once we have multiple simultaneous engines running
-static Mutex engineMutex;
-
-// ----------------------------------------------------------------------------
-class SynthProxyJniStorage {
- public :
- jobject tts_ref;
- android_tts_engine_t* mEngine;
- void* mEngineLibHandle;
- AudioTrack* mAudioOut;
- int8_t mPlayState;
- Mutex mPlayLock;
- AudioSystem::stream_type mStreamType;
- uint32_t mSampleRate;
- uint32_t mAudFormat;
- int mNbChannels;
- int8_t * mBuffer;
- size_t mBufferSize;
- float mVolume[2];
-
- SynthProxyJniStorage() {
- tts_ref = NULL;
- mEngine = NULL;
- mEngineLibHandle = NULL;
- mAudioOut = NULL;
- mPlayState = SYNTHPLAYSTATE_IS_STOPPED;
- mStreamType = DEFAULT_TTS_STREAM_TYPE;
- mSampleRate = DEFAULT_TTS_RATE;
- mAudFormat = DEFAULT_TTS_FORMAT;
- mNbChannels = DEFAULT_TTS_NB_CHANNELS;
- mBufferSize = DEFAULT_TTS_BUFFERSIZE;
- mBuffer = new int8_t[mBufferSize];
- memset(mBuffer, 0, mBufferSize);
- mVolume[AudioTrack::LEFT] = DEFAULT_VOLUME;
- mVolume[AudioTrack::RIGHT] = DEFAULT_VOLUME;
- }
-
- ~SynthProxyJniStorage() {
- //LOGV("entering ~SynthProxyJniStorage()");
- killAudio();
- if (mEngine) {
- mEngine->funcs->shutdown(mEngine);
- mEngine = NULL;
- }
- if (mEngineLibHandle) {
- //LOGV("~SynthProxyJniStorage(): before close library");
- int res = dlclose(mEngineLibHandle);
- LOGE_IF( res != 0, "~SynthProxyJniStorage(): dlclose returned %d", res);
- }
- delete mBuffer;
- }
-
- void killAudio() {
- if (mAudioOut) {
- mAudioOut->stop();
- delete mAudioOut;
- mAudioOut = NULL;
- }
- }
-
- void createAudioOut(AudioSystem::stream_type streamType, uint32_t rate,
- AudioSystem::audio_format format, int channel) {
- mSampleRate = rate;
- mAudFormat = format;
- mNbChannels = channel;
- mStreamType = streamType;
-
- // retrieve system properties to ensure successful creation of the
- // AudioTrack object for playback
- int afSampleRate;
- if (AudioSystem::getOutputSamplingRate(&afSampleRate, mStreamType) != NO_ERROR) {
- afSampleRate = 44100;
- }
- int afFrameCount;
- if (AudioSystem::getOutputFrameCount(&afFrameCount, mStreamType) != NO_ERROR) {
- afFrameCount = 2048;
- }
- uint32_t afLatency;
- if (AudioSystem::getOutputLatency(&afLatency, mStreamType) != NO_ERROR) {
- afLatency = 500;
- }
- uint32_t minBufCount = afLatency / ((1000 * afFrameCount)/afSampleRate);
- if (minBufCount < 2) minBufCount = 2;
- int minFrameCount = (afFrameCount * rate * minBufCount)/afSampleRate;
-
- mPlayLock.lock();
- mAudioOut = new AudioTrack(mStreamType, rate, format,
- (channel == 2) ? AudioSystem::CHANNEL_OUT_STEREO : AudioSystem::CHANNEL_OUT_MONO,
- minFrameCount > 4096 ? minFrameCount : 4096,
- 0, 0, 0, 0); // not using an AudioTrack callback
-
- if (mAudioOut->initCheck() != NO_ERROR) {
- LOGE("createAudioOut(): AudioTrack error");
- delete mAudioOut;
- mAudioOut = NULL;
- } else {
- //LOGI("AudioTrack OK");
- mAudioOut->setVolume(mVolume[AudioTrack::LEFT], mVolume[AudioTrack::RIGHT]);
- LOGV("AudioTrack ready");
- }
- mPlayLock.unlock();
- }
-};
-
-
-// ----------------------------------------------------------------------------
-void prepAudioTrack(SynthProxyJniStorage* pJniData, AudioSystem::stream_type streamType,
- uint32_t rate, AudioSystem::audio_format format, int channel) {
- // Don't bother creating a new audiotrack object if the current
- // object is already initialized with the same audio parameters.
- if ( pJniData->mAudioOut &&
- (rate == pJniData->mSampleRate) &&
- (format == pJniData->mAudFormat) &&
- (channel == pJniData->mNbChannels) &&
- (streamType == pJniData->mStreamType) ){
- return;
- }
- if (pJniData->mAudioOut){
- pJniData->killAudio();
- }
- pJniData->createAudioOut(streamType, rate, format, channel);
-}
-
-
-// ----------------------------------------------------------------------------
-/*
- * Callback from TTS engine.
- * Directly speaks using AudioTrack or write to file
- */
-extern "C" android_tts_callback_status_t
-__ttsSynthDoneCB(void ** pUserdata, uint32_t rate,
- android_tts_audio_format_t format, int channel,
- int8_t **pWav, size_t *pBufferSize,
- android_tts_synth_status_t status)
-{
- //LOGV("ttsSynthDoneCallback: %d bytes", bufferSize);
- AudioSystem::audio_format encoding;
-
- if (*pUserdata == NULL){
- LOGE("userdata == NULL");
- return ANDROID_TTS_CALLBACK_HALT;
- }
- switch (format) {
- case ANDROID_TTS_AUDIO_FORMAT_PCM_8_BIT:
- encoding = AudioSystem::PCM_8_BIT;
- break;
- case ANDROID_TTS_AUDIO_FORMAT_PCM_16_BIT:
- encoding = AudioSystem::PCM_16_BIT;
- break;
- default:
- LOGE("Can't play, bad format");
- return ANDROID_TTS_CALLBACK_HALT;
- }
- afterSynthData_t* pForAfter = (afterSynthData_t*) *pUserdata;
- SynthProxyJniStorage* pJniData = (SynthProxyJniStorage*)(pForAfter->jniStorage);
-
- if (pForAfter->usageMode == USAGEMODE_PLAY_IMMEDIATELY){
- //LOGV("Direct speech");
-
- if (*pWav == NULL) {
- delete pForAfter;
- pForAfter = NULL;
- LOGV("Null: speech has completed");
- return ANDROID_TTS_CALLBACK_HALT;
- }
-
- if (*pBufferSize > 0) {
- prepAudioTrack(pJniData, pForAfter->streamType, rate, encoding, channel);
- if (pJniData->mAudioOut) {
- pJniData->mPlayLock.lock();
- if(pJniData->mAudioOut->stopped()
- && (pJniData->mPlayState == SYNTHPLAYSTATE_IS_PLAYING)) {
- pJniData->mAudioOut->start();
- }
- pJniData->mPlayLock.unlock();
- if (bUseFilter) {
- applyFilter((int16_t*)*pWav, *pBufferSize/2);
- }
- pJniData->mAudioOut->write(*pWav, *pBufferSize);
- memset(*pWav, 0, *pBufferSize);
- //LOGV("AudioTrack wrote: %d bytes", bufferSize);
- } else {
- LOGE("Can't play, null audiotrack");
- delete pForAfter;
- pForAfter = NULL;
- return ANDROID_TTS_CALLBACK_HALT;
- }
- }
- } else if (pForAfter->usageMode == USAGEMODE_WRITE_TO_FILE) {
- //LOGV("Save to file");
- if (*pWav == NULL) {
- delete pForAfter;
- LOGV("Null: speech has completed");
- return ANDROID_TTS_CALLBACK_HALT;
- }
- if (*pBufferSize > 0){
- if (bUseFilter) {
- applyFilter((int16_t*)*pWav, *pBufferSize/2);
- }
- fwrite(*pWav, 1, *pBufferSize, pForAfter->outputFile);
- memset(*pWav, 0, *pBufferSize);
- }
- }
- // Future update:
- // For sync points in the speech, call back into the SynthProxy class through the
- // javaTTSFields.synthProxyMethodPost methode to notify
- // playback has completed if the synthesis is done or if a marker has been reached.
-
- if (status == ANDROID_TTS_SYNTH_DONE) {
- // this struct was allocated in the original android_tts_SynthProxy_speak call,
- // all processing matching this call is now done.
- LOGV("Speech synthesis done.");
- if (pForAfter->usageMode == USAGEMODE_PLAY_IMMEDIATELY) {
- // only delete for direct playback. When writing to a file, we still have work to do
- // in android_tts_SynthProxy_synthesizeToFile. The struct will be deleted there.
- delete pForAfter;
- pForAfter = NULL;
- }
- return ANDROID_TTS_CALLBACK_HALT;
- }
-
- // we don't update the wav (output) parameter as we'll let the next callback
- // write at the same location, we've consumed the data already, but we need
- // to update bufferSize to let the TTS engine know how much it can write the
- // next time it calls this function.
- *pBufferSize = pJniData->mBufferSize;
-
- return ANDROID_TTS_CALLBACK_CONTINUE;
-}
-
-
-// ----------------------------------------------------------------------------
-static int
-android_tts_SynthProxy_setLowShelf(JNIEnv *env, jobject thiz, jboolean applyFilter,
- jfloat filterGain, jfloat attenuationInDb, jfloat freqInHz, jfloat slope)
-{
- int result = ANDROID_TTS_SUCCESS;
-
- bUseFilter = applyFilter;
- if (applyFilter) {
- fFilterLowshelfAttenuation = attenuationInDb;
- fFilterTransitionFreq = freqInHz;
- fFilterShelfSlope = slope;
- fFilterGain = filterGain;
-
- if (fFilterShelfSlope != 0.0f) {
- initializeEQ();
- } else {
- LOGE("Invalid slope, can't be null");
- result = ANDROID_TTS_FAILURE;
- }
- }
-
- return result;
-}
-
-// ----------------------------------------------------------------------------
-static int
-android_tts_SynthProxy_native_setup(JNIEnv *env, jobject thiz,
- jobject weak_this, jstring nativeSoLib, jstring engConfig)
-{
- int result = ANDROID_TTS_FAILURE;
-
- bUseFilter = false;
-
- SynthProxyJniStorage* pJniStorage = new SynthProxyJniStorage();
-
- prepAudioTrack(pJniStorage,
- DEFAULT_TTS_STREAM_TYPE, DEFAULT_TTS_RATE, DEFAULT_TTS_FORMAT, DEFAULT_TTS_NB_CHANNELS);
-
- const char *nativeSoLibNativeString = env->GetStringUTFChars(nativeSoLib, 0);
- const char *engConfigString = env->GetStringUTFChars(engConfig, 0);
-
- void *engine_lib_handle = dlopen(nativeSoLibNativeString,
- RTLD_NOW | RTLD_LOCAL);
- if (engine_lib_handle == NULL) {
- LOGE("android_tts_SynthProxy_native_setup(): engine_lib_handle == NULL");
- } else {
- android_tts_engine_t * (*get_TtsEngine)() =
- reinterpret_cast<android_tts_engine_t* (*)()>(dlsym(engine_lib_handle, "android_getTtsEngine"));
-
- // Support obsolete/legacy binary modules
- if (get_TtsEngine == NULL) {
- get_TtsEngine =
- reinterpret_cast<android_tts_engine_t* (*)()>(dlsym(engine_lib_handle, "getTtsEngine"));
- }
-
- pJniStorage->mEngine = (*get_TtsEngine)();
- pJniStorage->mEngineLibHandle = engine_lib_handle;
-
- android_tts_engine_t *engine = pJniStorage->mEngine;
- if (engine) {
- Mutex::Autolock l(engineMutex);
- engine->funcs->init(
- engine,
- __ttsSynthDoneCB,
- engConfigString);
- }
-
- result = ANDROID_TTS_SUCCESS;
- }
-
- // we use a weak reference so the SynthProxy object can be garbage collected.
- pJniStorage->tts_ref = env->NewGlobalRef(weak_this);
-
- // save the JNI resources so we can use them (and free them) later
- env->SetIntField(thiz, javaTTSFields.synthProxyFieldJniData, (int)pJniStorage);
-
- env->ReleaseStringUTFChars(nativeSoLib, nativeSoLibNativeString);
- env->ReleaseStringUTFChars(engConfig, engConfigString);
-
- return result;
-}
-
-
-static void
-android_tts_SynthProxy_native_finalize(JNIEnv *env, jobject thiz, jint jniData)
-{
- //LOGV("entering android_tts_SynthProxy_finalize()");
- if (jniData == 0) {
- //LOGE("android_tts_SynthProxy_native_finalize(): invalid JNI data");
- return;
- }
-
- Mutex::Autolock l(engineMutex);
-
- SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
- env->DeleteGlobalRef(pSynthData->tts_ref);
- delete pSynthData;
-
- env->SetIntField(thiz, javaTTSFields.synthProxyFieldJniData, 0);
-}
-
-
-static void
-android_tts_SynthProxy_shutdown(JNIEnv *env, jobject thiz, jint jniData)
-{
- //LOGV("entering android_tts_SynthProxy_shutdown()");
-
- // do everything a call to finalize would
- android_tts_SynthProxy_native_finalize(env, thiz, jniData);
-}
-
-
-static int
-android_tts_SynthProxy_isLanguageAvailable(JNIEnv *env, jobject thiz, jint jniData,
- jstring language, jstring country, jstring variant)
-{
- int result = ANDROID_TTS_LANG_NOT_SUPPORTED;
-
- if (jniData == 0) {
- LOGE("android_tts_SynthProxy_isLanguageAvailable(): invalid JNI data");
- return result;
- }
-
- SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
- const char *langNativeString = env->GetStringUTFChars(language, 0);
- const char *countryNativeString = env->GetStringUTFChars(country, 0);
- const char *variantNativeString = env->GetStringUTFChars(variant, 0);
-
- android_tts_engine_t *engine = pSynthData->mEngine;
-
- if (engine) {
- result = engine->funcs->isLanguageAvailable(engine,langNativeString,
- countryNativeString, variantNativeString);
- }
- env->ReleaseStringUTFChars(language, langNativeString);
- env->ReleaseStringUTFChars(country, countryNativeString);
- env->ReleaseStringUTFChars(variant, variantNativeString);
- return result;
-}
-
-static int
-android_tts_SynthProxy_setConfig(JNIEnv *env, jobject thiz, jint jniData, jstring engineConfig)
-{
- int result = ANDROID_TTS_FAILURE;
-
- if (jniData == 0) {
- LOGE("android_tts_SynthProxy_setConfig(): invalid JNI data");
- return result;
- }
-
- Mutex::Autolock l(engineMutex);
-
- SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
- const char *engineConfigNativeString = env->GetStringUTFChars(engineConfig, 0);
- android_tts_engine_t *engine = pSynthData->mEngine;
-
- if (engine) {
- result = engine->funcs->setProperty(engine,ANDROID_TTS_ENGINE_PROPERTY_CONFIG,
- engineConfigNativeString, strlen(engineConfigNativeString));
- }
- env->ReleaseStringUTFChars(engineConfig, engineConfigNativeString);
-
- return result;
-}
-
-static int
-android_tts_SynthProxy_setLanguage(JNIEnv *env, jobject thiz, jint jniData,
- jstring language, jstring country, jstring variant)
-{
- int result = ANDROID_TTS_LANG_NOT_SUPPORTED;
-
- if (jniData == 0) {
- LOGE("android_tts_SynthProxy_setLanguage(): invalid JNI data");
- return result;
- }
-
- Mutex::Autolock l(engineMutex);
-
- SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
- const char *langNativeString = env->GetStringUTFChars(language, 0);
- const char *countryNativeString = env->GetStringUTFChars(country, 0);
- const char *variantNativeString = env->GetStringUTFChars(variant, 0);
- android_tts_engine_t *engine = pSynthData->mEngine;
-
- if (engine) {
- result = engine->funcs->setLanguage(engine, langNativeString,
- countryNativeString, variantNativeString);
- }
- env->ReleaseStringUTFChars(language, langNativeString);
- env->ReleaseStringUTFChars(country, countryNativeString);
- env->ReleaseStringUTFChars(variant, variantNativeString);
- return result;
-}
-
-
-static int
-android_tts_SynthProxy_loadLanguage(JNIEnv *env, jobject thiz, jint jniData,
- jstring language, jstring country, jstring variant)
-{
- int result = ANDROID_TTS_LANG_NOT_SUPPORTED;
-
- if (jniData == 0) {
- LOGE("android_tts_SynthProxy_loadLanguage(): invalid JNI data");
- return result;
- }
-
- SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
- const char *langNativeString = env->GetStringUTFChars(language, 0);
- const char *countryNativeString = env->GetStringUTFChars(country, 0);
- const char *variantNativeString = env->GetStringUTFChars(variant, 0);
- android_tts_engine_t *engine = pSynthData->mEngine;
-
- if (engine) {
- result = engine->funcs->loadLanguage(engine, langNativeString,
- countryNativeString, variantNativeString);
- }
- env->ReleaseStringUTFChars(language, langNativeString);
- env->ReleaseStringUTFChars(country, countryNativeString);
- env->ReleaseStringUTFChars(variant, variantNativeString);
-
- return result;
-}
-
-
-static int
-android_tts_SynthProxy_setSpeechRate(JNIEnv *env, jobject thiz, jint jniData,
- jint speechRate)
-{
- int result = ANDROID_TTS_FAILURE;
-
- if (jniData == 0) {
- LOGE("android_tts_SynthProxy_setSpeechRate(): invalid JNI data");
- return result;
- }
-
- int bufSize = 12;
- char buffer [bufSize];
- sprintf(buffer, "%d", speechRate);
-
- Mutex::Autolock l(engineMutex);
-
- SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
- //LOGI("setting speech rate to %d", speechRate);
- android_tts_engine_t *engine = pSynthData->mEngine;
-
- if (engine) {
- result = engine->funcs->setProperty(engine, "rate", buffer, bufSize);
- }
-
- return result;
-}
-
-
-static int
-android_tts_SynthProxy_setPitch(JNIEnv *env, jobject thiz, jint jniData,
- jint pitch)
-{
- int result = ANDROID_TTS_FAILURE;
-
- if (jniData == 0) {
- LOGE("android_tts_SynthProxy_setPitch(): invalid JNI data");
- return result;
- }
-
- Mutex::Autolock l(engineMutex);
-
- int bufSize = 12;
- char buffer [bufSize];
- sprintf(buffer, "%d", pitch);
-
- SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
- //LOGI("setting pitch to %d", pitch);
- android_tts_engine_t *engine = pSynthData->mEngine;
-
- if (engine) {
- result = engine->funcs->setProperty(engine, "pitch", buffer, bufSize);
- }
-
- return result;
-}
-
-
-static int
-android_tts_SynthProxy_synthesizeToFile(JNIEnv *env, jobject thiz, jint jniData,
- jstring textJavaString, jstring filenameJavaString)
-{
- int result = ANDROID_TTS_FAILURE;
-
- if (jniData == 0) {
- LOGE("android_tts_SynthProxy_synthesizeToFile(): invalid JNI data");
- return result;
- }
-
- SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
- if (!pSynthData->mEngine) {
- LOGE("android_tts_SynthProxy_synthesizeToFile(): invalid engine handle");
- return result;
- }
-
- initializeFilter();
-
- Mutex::Autolock l(engineMutex);
-
- // Retrieve audio parameters before writing the file header
- AudioSystem::audio_format encoding;
- uint32_t rate = DEFAULT_TTS_RATE;
- int channels = DEFAULT_TTS_NB_CHANNELS;
- android_tts_engine_t *engine = pSynthData->mEngine;
- android_tts_audio_format_t format = ANDROID_TTS_AUDIO_FORMAT_DEFAULT;
-
- engine->funcs->setAudioFormat(engine, &format, &rate, &channels);
-
- switch (format) {
- case ANDROID_TTS_AUDIO_FORMAT_PCM_16_BIT:
- encoding = AudioSystem::PCM_16_BIT;
- break;
- case ANDROID_TTS_AUDIO_FORMAT_PCM_8_BIT:
- encoding = AudioSystem::PCM_8_BIT;
- break;
- default:
- LOGE("android_tts_SynthProxy_synthesizeToFile(): engine uses invalid format");
- return result;
- }
-
- const char *filenameNativeString =
- env->GetStringUTFChars(filenameJavaString, 0);
- const char *textNativeString = env->GetStringUTFChars(textJavaString, 0);
-
- afterSynthData_t* pForAfter = new (afterSynthData_t);
- pForAfter->jniStorage = jniData;
- pForAfter->usageMode = USAGEMODE_WRITE_TO_FILE;
-
- pForAfter->outputFile = fopen(filenameNativeString, "wb");
-
- if (pForAfter->outputFile == NULL) {
- LOGE("android_tts_SynthProxy_synthesizeToFile(): error creating output file");
- delete pForAfter;
- return result;
- }
-
- // Write 44 blank bytes for WAV header, then come back and fill them in
- // after we've written the audio data
- char header[44];
- fwrite(header, 1, 44, pForAfter->outputFile);
-
- unsigned int unique_identifier;
-
- memset(pSynthData->mBuffer, 0, pSynthData->mBufferSize);
-
- result = engine->funcs->synthesizeText(engine, textNativeString,
- pSynthData->mBuffer, pSynthData->mBufferSize, (void *)pForAfter);
-
- long filelen = ftell(pForAfter->outputFile);
-
- int samples = (((int)filelen) - 44) / 2;
- header[0] = 'R';
- header[1] = 'I';
- header[2] = 'F';
- header[3] = 'F';
- ((uint32_t *)(&header[4]))[0] = filelen - 8;
- header[8] = 'W';
- header[9] = 'A';
- header[10] = 'V';
- header[11] = 'E';
-
- header[12] = 'f';
- header[13] = 'm';
- header[14] = 't';
- header[15] = ' ';
-
- ((uint32_t *)(&header[16]))[0] = 16; // size of fmt
-
- int sampleSizeInByte = (encoding == AudioSystem::PCM_16_BIT ? 2 : 1);
-
- ((unsigned short *)(&header[20]))[0] = 1; // format
- ((unsigned short *)(&header[22]))[0] = channels; // channels
- ((uint32_t *)(&header[24]))[0] = rate; // samplerate
- ((uint32_t *)(&header[28]))[0] = rate * sampleSizeInByte * channels;// byterate
- ((unsigned short *)(&header[32]))[0] = sampleSizeInByte * channels; // block align
- ((unsigned short *)(&header[34]))[0] = sampleSizeInByte * 8; // bits per sample
-
- header[36] = 'd';
- header[37] = 'a';
- header[38] = 't';
- header[39] = 'a';
-
- ((uint32_t *)(&header[40]))[0] = samples * 2; // size of data
-
- // Skip back to the beginning and rewrite the header
- fseek(pForAfter->outputFile, 0, SEEK_SET);
- fwrite(header, 1, 44, pForAfter->outputFile);
-
- fflush(pForAfter->outputFile);
- fclose(pForAfter->outputFile);
-
- delete pForAfter;
- pForAfter = NULL;
-
- env->ReleaseStringUTFChars(textJavaString, textNativeString);
- env->ReleaseStringUTFChars(filenameJavaString, filenameNativeString);
-
- return result;
-}
-
-
-static int
-android_tts_SynthProxy_speak(JNIEnv *env, jobject thiz, jint jniData,
- jstring textJavaString, jint javaStreamType, jfloat volume, jfloat pan)
-{
- int result = ANDROID_TTS_FAILURE;
-
- if (jniData == 0) {
- LOGE("android_tts_SynthProxy_speak(): invalid JNI data");
- return result;
- }
-
- initializeFilter();
-
- Mutex::Autolock l(engineMutex);
-
- SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
-
- {//scope for lock on mPlayLock
- Mutex::Autolock _l(pSynthData->mPlayLock);
-
- pSynthData->mPlayState = SYNTHPLAYSTATE_IS_PLAYING;
-
- // clip volume and pan
- float vol = (volume > 1.0f) ? 1.0f : (volume < 0.0f) ? 0.0f : volume;
- float panning = (pan > 1.0f) ? 1.0f : (pan < -1.0f) ? -1.0f : pan;
- // compute playback volume based on volume and pan, using balance rule, in order to avoid
- // lowering volume when panning in center
- pSynthData->mVolume[AudioTrack::LEFT] = vol;
- pSynthData->mVolume[AudioTrack::RIGHT] = vol;
- if (panning > 0.0f) {
- pSynthData->mVolume[AudioTrack::LEFT] *= (1.0f - panning);
- } else if (panning < 0.0f) {
- pSynthData->mVolume[AudioTrack::RIGHT] *= (1.0f + panning);
- }
-
- // apply the volume if there is an output
- if (NULL != pSynthData->mAudioOut) {
- pSynthData->mAudioOut->setVolume(pSynthData->mVolume[AudioTrack::LEFT],
- pSynthData->mVolume[AudioTrack::RIGHT]);
- }
-
- //LOGV("android_tts_SynthProxy_speak() vol=%.3f pan=%.3f, mVolume=[%.1f %.1f]",
- // volume, pan,
- // pSynthData->mVolume[AudioTrack::LEFT], pSynthData->mVolume[AudioTrack::RIGHT]);
- }
-
- afterSynthData_t* pForAfter = new (afterSynthData_t);
- pForAfter->jniStorage = jniData;
- pForAfter->usageMode = USAGEMODE_PLAY_IMMEDIATELY;
- pForAfter->streamType = (AudioSystem::stream_type) javaStreamType;
-
- if (pSynthData->mEngine) {
- const char *textNativeString = env->GetStringUTFChars(textJavaString, 0);
- memset(pSynthData->mBuffer, 0, pSynthData->mBufferSize);
- android_tts_engine_t *engine = pSynthData->mEngine;
-
- result = engine->funcs->synthesizeText(engine, textNativeString,
- pSynthData->mBuffer, pSynthData->mBufferSize, (void *)pForAfter);
- env->ReleaseStringUTFChars(textJavaString, textNativeString);
- }
-
- return result;
-}
-
-
-static int
-android_tts_SynthProxy_stop(JNIEnv *env, jobject thiz, jint jniData)
-{
- int result = ANDROID_TTS_FAILURE;
-
- if (jniData == 0) {
- LOGE("android_tts_SynthProxy_stop(): invalid JNI data");
- return result;
- }
-
- SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
-
- pSynthData->mPlayLock.lock();
- pSynthData->mPlayState = SYNTHPLAYSTATE_IS_STOPPED;
- if (pSynthData->mAudioOut) {
- pSynthData->mAudioOut->stop();
- }
- pSynthData->mPlayLock.unlock();
-
- android_tts_engine_t *engine = pSynthData->mEngine;
- if (engine) {
- result = engine->funcs->stop(engine);
- }
-
- return result;
-}
-
-
-static int
-android_tts_SynthProxy_stopSync(JNIEnv *env, jobject thiz, jint jniData)
-{
- int result = ANDROID_TTS_FAILURE;
-
- if (jniData == 0) {
- LOGE("android_tts_SynthProxy_stop(): invalid JNI data");
- return result;
- }
-
- // perform a regular stop
- result = android_tts_SynthProxy_stop(env, thiz, jniData);
- // but wait on the engine having released the engine mutex which protects
- // the synthesizer resources.
- engineMutex.lock();
- engineMutex.unlock();
-
- return result;
-}
-
-
-static jobjectArray
-android_tts_SynthProxy_getLanguage(JNIEnv *env, jobject thiz, jint jniData)
-{
- if (jniData == 0) {
- LOGE("android_tts_SynthProxy_getLanguage(): invalid JNI data");
- return NULL;
- }
-
- SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
-
- if (pSynthData->mEngine) {
- size_t bufSize = 100;
- char lang[bufSize];
- char country[bufSize];
- char variant[bufSize];
- memset(lang, 0, bufSize);
- memset(country, 0, bufSize);
- memset(variant, 0, bufSize);
- jobjectArray retLocale = (jobjectArray)env->NewObjectArray(3,
- env->FindClass("java/lang/String"), env->NewStringUTF(""));
-
- android_tts_engine_t *engine = pSynthData->mEngine;
- engine->funcs->getLanguage(engine, lang, country, variant);
- env->SetObjectArrayElement(retLocale, 0, env->NewStringUTF(lang));
- env->SetObjectArrayElement(retLocale, 1, env->NewStringUTF(country));
- env->SetObjectArrayElement(retLocale, 2, env->NewStringUTF(variant));
- return retLocale;
- } else {
- return NULL;
- }
-}
-
-
-JNIEXPORT int JNICALL
-android_tts_SynthProxy_getRate(JNIEnv *env, jobject thiz, jint jniData)
-{
- if (jniData == 0) {
- LOGE("android_tts_SynthProxy_getRate(): invalid JNI data");
- return 0;
- }
-
- SynthProxyJniStorage* pSynthData = (SynthProxyJniStorage*)jniData;
- size_t bufSize = 100;
-
- char buf[bufSize];
- memset(buf, 0, bufSize);
- // TODO check return codes
- android_tts_engine_t *engine = pSynthData->mEngine;
- if (engine) {
- engine->funcs->getProperty(engine,"rate", buf, &bufSize);
- }
- return atoi(buf);
-}
-
-// Dalvik VM type signatures
-static JNINativeMethod gMethods[] = {
- { "native_stop",
- "(I)I",
- (void*)android_tts_SynthProxy_stop
- },
- { "native_stopSync",
- "(I)I",
- (void*)android_tts_SynthProxy_stopSync
- },
- { "native_speak",
- "(ILjava/lang/String;IFF)I",
- (void*)android_tts_SynthProxy_speak
- },
- { "native_synthesizeToFile",
- "(ILjava/lang/String;Ljava/lang/String;)I",
- (void*)android_tts_SynthProxy_synthesizeToFile
- },
- { "native_isLanguageAvailable",
- "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
- (void*)android_tts_SynthProxy_isLanguageAvailable
- },
- { "native_setConfig",
- "(ILjava/lang/String;)I",
- (void*)android_tts_SynthProxy_setConfig
- },
- { "native_setLanguage",
- "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
- (void*)android_tts_SynthProxy_setLanguage
- },
- { "native_loadLanguage",
- "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
- (void*)android_tts_SynthProxy_loadLanguage
- },
- { "native_setSpeechRate",
- "(II)I",
- (void*)android_tts_SynthProxy_setSpeechRate
- },
- { "native_setPitch",
- "(II)I",
- (void*)android_tts_SynthProxy_setPitch
- },
- { "native_getLanguage",
- "(I)[Ljava/lang/String;",
- (void*)android_tts_SynthProxy_getLanguage
- },
- { "native_getRate",
- "(I)I",
- (void*)android_tts_SynthProxy_getRate
- },
- { "native_shutdown",
- "(I)V",
- (void*)android_tts_SynthProxy_shutdown
- },
- { "native_setup",
- "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)I",
- (void*)android_tts_SynthProxy_native_setup
- },
- { "native_setLowShelf",
- "(ZFFFF)I",
- (void*)android_tts_SynthProxy_setLowShelf
- },
- { "native_finalize",
- "(I)V",
- (void*)android_tts_SynthProxy_native_finalize
- }
-};
-
-#define SP_JNIDATA_FIELD_NAME "mJniData"
-#define SP_POSTSPEECHSYNTHESIZED_METHOD_NAME "postNativeSpeechSynthesizedInJava"
-
-static const char* const kClassPathName = "android/tts/SynthProxy";
-
-jint JNI_OnLoad(JavaVM* vm, void* reserved)
-{
- JNIEnv* env = NULL;
- jint result = -1;
- jclass clazz;
-
- if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
- LOGE("ERROR: GetEnv failed\n");
- goto bail;
- }
- assert(env != NULL);
-
- clazz = env->FindClass(kClassPathName);
- if (clazz == NULL) {
- LOGE("Can't find %s", kClassPathName);
- goto bail;
- }
-
- javaTTSFields.synthProxyFieldJniData = NULL;
- javaTTSFields.synthProxyMethodPost = NULL;
-
- javaTTSFields.synthProxyFieldJniData = env->GetFieldID(clazz,
- SP_JNIDATA_FIELD_NAME, "I");
- if (javaTTSFields.synthProxyFieldJniData == NULL) {
- LOGE("Can't find %s.%s field", kClassPathName, SP_JNIDATA_FIELD_NAME);
- goto bail;
- }
-
- javaTTSFields.synthProxyMethodPost = env->GetStaticMethodID(clazz,
- SP_POSTSPEECHSYNTHESIZED_METHOD_NAME, "(Ljava/lang/Object;II)V");
- if (javaTTSFields.synthProxyMethodPost == NULL) {
- LOGE("Can't find %s.%s method", kClassPathName, SP_POSTSPEECHSYNTHESIZED_METHOD_NAME);
- goto bail;
- }
-
- if (jniRegisterNativeMethods(
- env, kClassPathName, gMethods, NELEM(gMethods)) < 0)
- goto bail;
-
- /* success -- return valid version number */
- result = JNI_VERSION_1_4;
-
- bail:
- return result;
-}
diff --git a/packages/TtsService/proguard.flags b/packages/TtsService/proguard.flags
deleted file mode 100644
index e8bee6b8b0e8..000000000000
--- a/packages/TtsService/proguard.flags
+++ /dev/null
@@ -1,5 +0,0 @@
--keep class android.tts.SynthProxy {
- int mJniData;
- # keep all declarations for native methods
- <methods>;
-}
diff --git a/packages/TtsService/res/drawable-hdpi/ic_launcher_text_to_speech.png b/packages/TtsService/res/drawable-hdpi/ic_launcher_text_to_speech.png
deleted file mode 100644
index f075e0f3f909..000000000000
--- a/packages/TtsService/res/drawable-hdpi/ic_launcher_text_to_speech.png
+++ /dev/null
Binary files differ
diff --git a/packages/TtsService/res/drawable-mdpi/ic_launcher_text_to_speech.png b/packages/TtsService/res/drawable-mdpi/ic_launcher_text_to_speech.png
deleted file mode 100644
index cbae7de2cfc5..000000000000
--- a/packages/TtsService/res/drawable-mdpi/ic_launcher_text_to_speech.png
+++ /dev/null
Binary files differ
diff --git a/packages/TtsService/src/android/tts/SynthProxy.java b/packages/TtsService/src/android/tts/SynthProxy.java
deleted file mode 100755
index f5f5fcf2b876..000000000000
--- a/packages/TtsService/src/android/tts/SynthProxy.java
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * Copyright (C) 2009 Google Inc.
- *
- * 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.tts;
-
-import android.media.AudioManager;
-import android.media.AudioSystem;
-import android.util.Log;
-import java.lang.ref.WeakReference;
-
-/**
- * @hide
- *
- * The SpeechSynthesis class provides a high-level api to create and play
- * synthesized speech. This class is used internally to talk to a native
- * TTS library that implements the interface defined in
- * frameworks/base/include/tts/TtsEngine.h
- *
- */
-@SuppressWarnings("unused")
-public class SynthProxy {
-
- // Default parameters of a filter to be applied when using the Pico engine.
- // Such a huge filter gain is justified by how much energy in the low frequencies is "wasted" at
- // the output of the synthesis. The low shelving filter removes it, leaving room for
- // amplification.
- private final static float PICO_FILTER_GAIN = 5.0f; // linear gain
- private final static float PICO_FILTER_LOWSHELF_ATTENUATION = -18.0f; // in dB
- private final static float PICO_FILTER_TRANSITION_FREQ = 1100.0f; // in Hz
- private final static float PICO_FILTER_SHELF_SLOPE = 1.0f; // Q
-
- //
- // External API
- //
-
- /**
- * Constructor; pass the location of the native TTS .so to use.
- */
- public SynthProxy(String nativeSoLib, String engineConfig) {
- boolean applyFilter = nativeSoLib.toLowerCase().contains("pico");
- Log.v(TtsService.SERVICE_TAG, "About to load "+ nativeSoLib + ", applyFilter="+applyFilter);
- native_setup(new WeakReference<SynthProxy>(this), nativeSoLib, engineConfig);
- native_setLowShelf(applyFilter, PICO_FILTER_GAIN, PICO_FILTER_LOWSHELF_ATTENUATION,
- PICO_FILTER_TRANSITION_FREQ, PICO_FILTER_SHELF_SLOPE);
- }
-
- /**
- * Stops and clears the AudioTrack.
- */
- public int stop() {
- return native_stop(mJniData);
- }
-
- /**
- * Synchronous stop of the synthesizer. This method returns when the synth
- * has completed the stop procedure and doesn't use any of the resources it
- * was using while synthesizing.
- *
- * @return {@link android.speech.tts.TextToSpeech.SUCCESS} or
- * {@link android.speech.tts.TextToSpeech.ERROR}
- */
- public int stopSync() {
- return native_stopSync(mJniData);
- }
-
- /**
- * Synthesize speech and speak it directly using AudioTrack.
- */
- public int speak(String text, int streamType, float volume, float pan) {
- Log.i(TAG, "speak() on stream "+ streamType);
- if ((streamType > -1) && (streamType < AudioSystem.getNumStreamTypes())) {
- return native_speak(mJniData, text, streamType, volume, pan);
- } else {
- Log.e("SynthProxy", "Trying to speak with invalid stream type " + streamType);
- return native_speak(mJniData, text, AudioManager.STREAM_MUSIC, volume, pan);
- }
- }
-
- /**
- * Synthesize speech to a file. The current implementation writes a valid
- * WAV file to the given path, assuming it is writable. Something like
- * "/sdcard/???.wav" is recommended.
- */
- public int synthesizeToFile(String text, String filename) {
- Log.i(TAG, "synthesizeToFile() to file "+ filename);
- return native_synthesizeToFile(mJniData, text, filename);
- }
-
- /**
- * Queries for language support.
- * Return codes are defined in android.speech.tts.TextToSpeech
- */
- public int isLanguageAvailable(String language, String country, String variant) {
- return native_isLanguageAvailable(mJniData, language, country, variant);
- }
-
- /**
- * Updates the engine configuration.
- */
- public int setConfig(String engineConfig) {
- return native_setConfig(mJniData, engineConfig);
- }
-
- /**
- * Sets the language.
- */
- public int setLanguage(String language, String country, String variant) {
- return native_setLanguage(mJniData, language, country, variant);
- }
-
- /**
- * Loads the language: it's not set, but prepared for use later.
- */
- public int loadLanguage(String language, String country, String variant) {
- return native_loadLanguage(mJniData, language, country, variant);
- }
-
- /**
- * Sets the speech rate.
- */
- public final int setSpeechRate(int speechRate) {
- return native_setSpeechRate(mJniData, speechRate);
- }
-
- /**
- * Sets the pitch of the synthesized voice.
- */
- public final int setPitch(int pitch) {
- return native_setPitch(mJniData, pitch);
- }
-
- /**
- * Returns the currently set language, country and variant information.
- */
- public String[] getLanguage() {
- return native_getLanguage(mJniData);
- }
-
- /**
- * Gets the currently set rate.
- */
- public int getRate() {
- return native_getRate(mJniData);
- }
-
- /**
- * Shuts down the native synthesizer.
- */
- public void shutdown() {
- native_shutdown(mJniData);
- }
-
- //
- // Internal
- //
-
- protected void finalize() {
- native_finalize(mJniData);
- mJniData = 0;
- }
-
- static {
- System.loadLibrary("ttssynthproxy");
- }
-
- private final static String TAG = "SynthProxy";
-
- /**
- * Accessed by native methods
- */
- private int mJniData = 0;
-
- private native final int native_setup(Object weak_this, String nativeSoLib,
- String engineConfig);
-
- private native final int native_setLowShelf(boolean applyFilter, float filterGain,
- float attenuationInDb, float freqInHz, float slope);
-
- private native final void native_finalize(int jniData);
-
- private native final int native_stop(int jniData);
-
- private native final int native_stopSync(int jniData);
-
- private native final int native_speak(int jniData, String text, int streamType, float volume,
- float pan);
-
- private native final int native_synthesizeToFile(int jniData, String text, String filename);
-
- private native final int native_isLanguageAvailable(int jniData, String language,
- String country, String variant);
-
- private native final int native_setLanguage(int jniData, String language, String country,
- String variant);
-
- private native final int native_loadLanguage(int jniData, String language, String country,
- String variant);
-
- private native final int native_setConfig(int jniData, String engineConfig);
-
- private native final int native_setSpeechRate(int jniData, int speechRate);
-
- private native final int native_setPitch(int jniData, int speechRate);
-
- private native final String[] native_getLanguage(int jniData);
-
- private native final int native_getRate(int jniData);
-
- private native final void native_shutdown(int jniData);
-
-
- /**
- * Callback from the C layer
- */
- @SuppressWarnings("unused")
- private static void postNativeSpeechSynthesizedInJava(Object tts_ref,
- int bufferPointer, int bufferSize) {
-
- Log.i("TTS plugin debug", "bufferPointer: " + bufferPointer
- + " bufferSize: " + bufferSize);
-
- SynthProxy nativeTTS = (SynthProxy)((WeakReference)tts_ref).get();
- // TODO notify TTS service of synthesis/playback completion,
- // method definition to be changed.
- }
-}
diff --git a/packages/TtsService/src/android/tts/TtsService.java b/packages/TtsService/src/android/tts/TtsService.java
deleted file mode 100755
index c562327d15b6..000000000000
--- a/packages/TtsService/src/android/tts/TtsService.java
+++ /dev/null
@@ -1,1503 +0,0 @@
-/*
- * Copyright (C) 2009 Google Inc.
- *
- * 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.tts;
-
-import android.app.Service;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ResolveInfo;
-import android.database.Cursor;
-import android.media.AudioManager;
-import android.media.MediaPlayer;
-import android.media.MediaPlayer.OnCompletionListener;
-import android.net.Uri;
-import android.os.IBinder;
-import android.os.RemoteCallbackList;
-import android.os.RemoteException;
-import android.preference.PreferenceManager;
-import android.speech.tts.ITts.Stub;
-import android.speech.tts.ITtsCallback;
-import android.speech.tts.TextToSpeech;
-import android.util.Log;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.concurrent.locks.ReentrantLock;
-import java.util.concurrent.TimeUnit;
-
-
-/**
- * @hide Synthesizes speech from text. This is implemented as a service so that
- * other applications can call the TTS without needing to bundle the TTS
- * in the build.
- *
- */
-public class TtsService extends Service implements OnCompletionListener {
-
- private static class SpeechItem {
- public static final int TEXT = 0;
- public static final int EARCON = 1;
- public static final int SILENCE = 2;
- public static final int TEXT_TO_FILE = 3;
- public String mText = "";
- public ArrayList<String> mParams = null;
- public int mType = TEXT;
- public long mDuration = 0;
- public String mFilename = null;
- public String mCallingApp = "";
-
- public SpeechItem(String source, String text, ArrayList<String> params, int itemType) {
- mText = text;
- mParams = params;
- mType = itemType;
- mCallingApp = source;
- }
-
- public SpeechItem(String source, long silenceTime, ArrayList<String> params) {
- mDuration = silenceTime;
- mParams = params;
- mType = SILENCE;
- mCallingApp = source;
- }
-
- public SpeechItem(String source, String text, ArrayList<String> params,
- int itemType, String filename) {
- mText = text;
- mParams = params;
- mType = itemType;
- mFilename = filename;
- mCallingApp = source;
- }
-
- }
-
- /**
- * Contains the information needed to access a sound resource; the name of
- * the package that contains the resource and the resID of the resource
- * within that package.
- */
- private static class SoundResource {
- public String mSourcePackageName = null;
- public int mResId = -1;
- public String mFilename = null;
-
- public SoundResource(String packageName, int id) {
- mSourcePackageName = packageName;
- mResId = id;
- mFilename = null;
- }
-
- public SoundResource(String file) {
- mSourcePackageName = null;
- mResId = -1;
- mFilename = file;
- }
- }
- // If the speech queue is locked for more than 5 seconds, something has gone
- // very wrong with processSpeechQueue.
- private static final int SPEECHQUEUELOCK_TIMEOUT = 5000;
- private static final int MAX_SPEECH_ITEM_CHAR_LENGTH = 4000;
- private static final int MAX_FILENAME_LENGTH = 250;
- private static final int DEFAULT_STREAM_TYPE = AudioManager.STREAM_MUSIC;
- // TODO use TextToSpeech.DEFAULT_SYNTH once it is unhidden
- private static final String DEFAULT_SYNTH = "com.svox.pico";
- private static final String ACTION = "android.intent.action.START_TTS_SERVICE";
- private static final String CATEGORY = "android.intent.category.TTS";
- private static final String PKGNAME = "android.tts";
- protected static final String SERVICE_TAG = "TtsService";
-
- private final RemoteCallbackList<ITtsCallback> mCallbacks
- = new RemoteCallbackList<ITtsCallback>();
-
- private HashMap<String, ITtsCallback> mCallbacksMap;
-
- private Boolean mIsSpeaking;
- private Boolean mSynthBusy;
- private ArrayList<SpeechItem> mSpeechQueue;
- private HashMap<String, SoundResource> mEarcons;
- private HashMap<String, SoundResource> mUtterances;
- private MediaPlayer mPlayer;
- private SpeechItem mCurrentSpeechItem;
- private HashMap<SpeechItem, Boolean> mKillList; // Used to ensure that in-flight synth calls
- // are killed when stop is used.
- private TtsService mSelf;
-
- private ContentResolver mResolver;
-
- // lock for the speech queue (mSpeechQueue) and the current speech item (mCurrentSpeechItem)
- private final ReentrantLock speechQueueLock = new ReentrantLock();
- private final ReentrantLock synthesizerLock = new ReentrantLock();
-
- private static SynthProxy sNativeSynth = null;
- private String currentSpeechEngineSOFile = "";
-
- @Override
- public void onCreate() {
- super.onCreate();
- Log.v("TtsService", "TtsService.onCreate()");
-
- mResolver = getContentResolver();
-
- currentSpeechEngineSOFile = "";
- setEngine(getDefaultEngine());
-
- mSelf = this;
- mIsSpeaking = false;
- mSynthBusy = false;
-
- mEarcons = new HashMap<String, SoundResource>();
- mUtterances = new HashMap<String, SoundResource>();
- mCallbacksMap = new HashMap<String, android.speech.tts.ITtsCallback>();
-
- mSpeechQueue = new ArrayList<SpeechItem>();
- mPlayer = null;
- mCurrentSpeechItem = null;
- mKillList = new HashMap<SpeechItem, Boolean>();
-
- setDefaultSettings();
- }
-
- @Override
- public void onDestroy() {
- super.onDestroy();
-
- killAllUtterances();
-
- // Don't hog the media player
- cleanUpPlayer();
-
- if (sNativeSynth != null) {
- sNativeSynth.shutdown();
- }
- sNativeSynth = null;
-
- // Unregister all callbacks.
- mCallbacks.kill();
-
- Log.v(SERVICE_TAG, "onDestroy() completed");
- }
-
-
- private int setEngine(String enginePackageName) {
- String soFilename = "";
- if (isDefaultEnforced()) {
- enginePackageName = getDefaultEngine();
- }
-
- // Make sure that the engine has been allowed by the user
- if (!enginePackageName.equals(DEFAULT_SYNTH)) {
- String[] enabledEngines = android.provider.Settings.Secure.getString(mResolver,
- android.provider.Settings.Secure.TTS_ENABLED_PLUGINS).split(" ");
- boolean isEnabled = false;
- for (int i=0; i<enabledEngines.length; i++) {
- if (enabledEngines[i].equals(enginePackageName)) {
- isEnabled = true;
- break;
- }
- }
- if (!isEnabled) {
- // Do not use an engine that the user has not enabled; fall back
- // to using the default synthesizer.
- enginePackageName = DEFAULT_SYNTH;
- }
- }
-
- // The SVOX TTS is an exception to how the TTS packaging scheme works
- // because it is part of the system and not a 3rd party add-on; thus
- // its binary is actually located under /system/lib/
- if (enginePackageName.equals(DEFAULT_SYNTH)) {
- soFilename = "/system/lib/libttspico.so";
- } else {
- // Find the package
- Intent intent = new Intent("android.intent.action.START_TTS_ENGINE");
- intent.setPackage(enginePackageName);
- ResolveInfo[] enginesArray = new ResolveInfo[0];
- PackageManager pm = getPackageManager();
- List <ResolveInfo> resolveInfos = pm.queryIntentActivities(intent, 0);
- if ((resolveInfos == null) || resolveInfos.isEmpty()) {
- Log.e(SERVICE_TAG, "Invalid TTS Engine Package: " + enginePackageName);
- return TextToSpeech.ERROR;
- }
- enginesArray = resolveInfos.toArray(enginesArray);
- // Generate the TTS .so filename from the package
- ActivityInfo aInfo = enginesArray[0].activityInfo;
- soFilename = aInfo.name.replace(aInfo.packageName + ".", "") + ".so";
- soFilename = soFilename.toLowerCase();
- soFilename = "/data/data/" + aInfo.packageName + "/lib/libtts" + soFilename;
- }
-
- if (currentSpeechEngineSOFile.equals(soFilename)) {
- return TextToSpeech.SUCCESS;
- }
-
- File f = new File(soFilename);
- if (!f.exists()) {
- Log.e(SERVICE_TAG, "Invalid TTS Binary: " + soFilename);
- return TextToSpeech.ERROR;
- }
-
- if (sNativeSynth != null) {
- sNativeSynth.stopSync();
- sNativeSynth.shutdown();
- sNativeSynth = null;
- }
-
- // Load the engineConfig from the plugin if it has any special configuration
- // to be loaded. By convention, if an engine wants the TTS framework to pass
- // in any configuration, it must put it into its content provider which has the URI:
- // content://<packageName>.providers.SettingsProvider
- // That content provider must provide a Cursor which returns the String that
- // is to be passed back to the native .so file for the plugin when getString(0) is
- // called on it.
- // Note that the TTS framework does not care what this String data is: it is something
- // that comes from the engine plugin and is consumed only by the engine plugin itself.
- String engineConfig = "";
- Cursor c = getContentResolver().query(Uri.parse("content://" + enginePackageName
- + ".providers.SettingsProvider"), null, null, null, null);
- if (c != null){
- c.moveToFirst();
- engineConfig = c.getString(0);
- c.close();
- }
- sNativeSynth = new SynthProxy(soFilename, engineConfig);
- currentSpeechEngineSOFile = soFilename;
- return TextToSpeech.SUCCESS;
- }
-
-
-
- private void setDefaultSettings() {
- setLanguage("", this.getDefaultLanguage(), getDefaultCountry(), getDefaultLocVariant());
-
- // speech rate
- setSpeechRate("", getDefaultRate());
- }
-
-
- private boolean isDefaultEnforced() {
- return (android.provider.Settings.Secure.getInt(mResolver,
- android.provider.Settings.Secure.TTS_USE_DEFAULTS,
- TextToSpeech.Engine.USE_DEFAULTS)
- == 1 );
- }
-
- private String getDefaultEngine() {
- String defaultEngine = android.provider.Settings.Secure.getString(mResolver,
- android.provider.Settings.Secure.TTS_DEFAULT_SYNTH);
- if (defaultEngine == null) {
- return TextToSpeech.Engine.DEFAULT_SYNTH;
- } else {
- return defaultEngine;
- }
- }
-
- private int getDefaultRate() {
- return android.provider.Settings.Secure.getInt(mResolver,
- android.provider.Settings.Secure.TTS_DEFAULT_RATE,
- TextToSpeech.Engine.DEFAULT_RATE);
- }
-
- private int getDefaultPitch() {
- // Pitch is not user settable; the default pitch is always 100.
- return 100;
- }
-
- private String getDefaultLanguage() {
- String defaultLang = android.provider.Settings.Secure.getString(mResolver,
- android.provider.Settings.Secure.TTS_DEFAULT_LANG);
- if (defaultLang == null) {
- // no setting found, use the current Locale to determine the default language
- return Locale.getDefault().getISO3Language();
- } else {
- return defaultLang;
- }
- }
-
-
- private String getDefaultCountry() {
- String defaultCountry = android.provider.Settings.Secure.getString(mResolver,
- android.provider.Settings.Secure.TTS_DEFAULT_COUNTRY);
- if (defaultCountry == null) {
- // no setting found, use the current Locale to determine the default country
- return Locale.getDefault().getISO3Country();
- } else {
- return defaultCountry;
- }
- }
-
-
- private String getDefaultLocVariant() {
- String defaultVar = android.provider.Settings.Secure.getString(mResolver,
- android.provider.Settings.Secure.TTS_DEFAULT_VARIANT);
- if (defaultVar == null) {
- // no setting found, use the current Locale to determine the default variant
- return Locale.getDefault().getVariant();
- } else {
- return defaultVar;
- }
- }
-
-
- private int setSpeechRate(String callingApp, int rate) {
- int res = TextToSpeech.ERROR;
- try {
- if (isDefaultEnforced()) {
- res = sNativeSynth.setSpeechRate(getDefaultRate());
- } else {
- res = sNativeSynth.setSpeechRate(rate);
- }
- } catch (NullPointerException e) {
- // synth will become null during onDestroy()
- res = TextToSpeech.ERROR;
- }
- return res;
- }
-
-
- private int setPitch(String callingApp, int pitch) {
- int res = TextToSpeech.ERROR;
- try {
- res = sNativeSynth.setPitch(pitch);
- } catch (NullPointerException e) {
- // synth will become null during onDestroy()
- res = TextToSpeech.ERROR;
- }
- return res;
- }
-
-
- private int isLanguageAvailable(String lang, String country, String variant) {
- int res = TextToSpeech.LANG_NOT_SUPPORTED;
- try {
- res = sNativeSynth.isLanguageAvailable(lang, country, variant);
- } catch (NullPointerException e) {
- // synth will become null during onDestroy()
- res = TextToSpeech.LANG_NOT_SUPPORTED;
- }
- return res;
- }
-
-
- private String[] getLanguage() {
- try {
- return sNativeSynth.getLanguage();
- } catch (Exception e) {
- return null;
- }
- }
-
-
- private int setLanguage(String callingApp, String lang, String country, String variant) {
- Log.v(SERVICE_TAG, "TtsService.setLanguage(" + lang + ", " + country + ", " + variant + ")");
- int res = TextToSpeech.ERROR;
- try {
- if (isDefaultEnforced()) {
- res = sNativeSynth.setLanguage(getDefaultLanguage(), getDefaultCountry(),
- getDefaultLocVariant());
- } else {
- res = sNativeSynth.setLanguage(lang, country, variant);
- }
- } catch (NullPointerException e) {
- // synth will become null during onDestroy()
- res = TextToSpeech.ERROR;
- }
- return res;
- }
-
-
- /**
- * Adds a sound resource to the TTS.
- *
- * @param text
- * The text that should be associated with the sound resource
- * @param packageName
- * The name of the package which has the sound resource
- * @param resId
- * The resource ID of the sound within its package
- */
- private void addSpeech(String callingApp, String text, String packageName, int resId) {
- mUtterances.put(text, new SoundResource(packageName, resId));
- }
-
- /**
- * Adds a sound resource to the TTS.
- *
- * @param text
- * The text that should be associated with the sound resource
- * @param filename
- * The filename of the sound resource. This must be a complete
- * path like: (/sdcard/mysounds/mysoundbite.mp3).
- */
- private void addSpeech(String callingApp, String text, String filename) {
- mUtterances.put(text, new SoundResource(filename));
- }
-
- /**
- * Adds a sound resource to the TTS as an earcon.
- *
- * @param earcon
- * The text that should be associated with the sound resource
- * @param packageName
- * The name of the package which has the sound resource
- * @param resId
- * The resource ID of the sound within its package
- */
- private void addEarcon(String callingApp, String earcon, String packageName, int resId) {
- mEarcons.put(earcon, new SoundResource(packageName, resId));
- }
-
- /**
- * Adds a sound resource to the TTS as an earcon.
- *
- * @param earcon
- * The text that should be associated with the sound resource
- * @param filename
- * The filename of the sound resource. This must be a complete
- * path like: (/sdcard/mysounds/mysoundbite.mp3).
- */
- private void addEarcon(String callingApp, String earcon, String filename) {
- mEarcons.put(earcon, new SoundResource(filename));
- }
-
- /**
- * Speaks the given text using the specified queueing mode and parameters.
- *
- * @param text
- * The text that should be spoken
- * @param queueMode
- * TextToSpeech.TTS_QUEUE_FLUSH for no queue (interrupts all previous utterances),
- * TextToSpeech.TTS_QUEUE_ADD for queued
- * @param params
- * An ArrayList of parameters. This is not implemented for all
- * engines.
- */
- private int speak(String callingApp, String text, int queueMode, ArrayList<String> params) {
- // Log.v(SERVICE_TAG, "TTS service received " + text);
- if (queueMode == TextToSpeech.QUEUE_FLUSH) {
- stop(callingApp);
- } else if (queueMode == 2) {
- stopAll(callingApp);
- }
- mSpeechQueue.add(new SpeechItem(callingApp, text, params, SpeechItem.TEXT));
- if (!mIsSpeaking) {
- processSpeechQueue();
- }
- return TextToSpeech.SUCCESS;
- }
-
- /**
- * Plays the earcon using the specified queueing mode and parameters.
- *
- * @param earcon
- * The earcon that should be played
- * @param queueMode
- * TextToSpeech.TTS_QUEUE_FLUSH for no queue (interrupts all previous utterances),
- * TextToSpeech.TTS_QUEUE_ADD for queued
- * @param params
- * An ArrayList of parameters. This is not implemented for all
- * engines.
- */
- private int playEarcon(String callingApp, String earcon, int queueMode,
- ArrayList<String> params) {
- if (queueMode == TextToSpeech.QUEUE_FLUSH) {
- stop(callingApp);
- } else if (queueMode == 2) {
- stopAll(callingApp);
- }
- mSpeechQueue.add(new SpeechItem(callingApp, earcon, params, SpeechItem.EARCON));
- if (!mIsSpeaking) {
- processSpeechQueue();
- }
- return TextToSpeech.SUCCESS;
- }
-
- /**
- * Stops all speech output and removes any utterances still in the queue for the calling app.
- */
- private int stop(String callingApp) {
- int result = TextToSpeech.ERROR;
- boolean speechQueueAvailable = false;
- try{
- speechQueueAvailable =
- speechQueueLock.tryLock(SPEECHQUEUELOCK_TIMEOUT, TimeUnit.MILLISECONDS);
- if (speechQueueAvailable) {
- Log.i(SERVICE_TAG, "Stopping");
- for (int i = mSpeechQueue.size() - 1; i > -1; i--){
- if (mSpeechQueue.get(i).mCallingApp.equals(callingApp)){
- mSpeechQueue.remove(i);
- }
- }
- if ((mCurrentSpeechItem != null) &&
- mCurrentSpeechItem.mCallingApp.equals(callingApp)) {
- try {
- result = sNativeSynth.stop();
- } catch (NullPointerException e1) {
- // synth will become null during onDestroy()
- result = TextToSpeech.ERROR;
- }
- mKillList.put(mCurrentSpeechItem, true);
- if (mPlayer != null) {
- try {
- mPlayer.stop();
- } catch (IllegalStateException e) {
- // Do nothing, the player is already stopped.
- }
- }
- mIsSpeaking = false;
- mCurrentSpeechItem = null;
- } else {
- result = TextToSpeech.SUCCESS;
- }
- Log.i(SERVICE_TAG, "Stopped");
- } else {
- Log.e(SERVICE_TAG, "TTS stop(): queue locked longer than expected");
- result = TextToSpeech.ERROR;
- }
- } catch (InterruptedException e) {
- Log.e(SERVICE_TAG, "TTS stop: tryLock interrupted");
- e.printStackTrace();
- } finally {
- // This check is needed because finally will always run; even if the
- // method returns somewhere in the try block.
- if (speechQueueAvailable) {
- speechQueueLock.unlock();
- }
- return result;
- }
- }
-
-
- /**
- * Stops all speech output, both rendered to a file and directly spoken, and removes any
- * utterances still in the queue globally. Files that were being written are deleted.
- */
- @SuppressWarnings("finally")
- private int killAllUtterances() {
- int result = TextToSpeech.ERROR;
- boolean speechQueueAvailable = false;
-
- try {
- speechQueueAvailable = speechQueueLock.tryLock(SPEECHQUEUELOCK_TIMEOUT,
- TimeUnit.MILLISECONDS);
- if (speechQueueAvailable) {
- // remove every single entry in the speech queue
- mSpeechQueue.clear();
-
- // clear the current speech item
- if (mCurrentSpeechItem != null) {
- result = sNativeSynth.stopSync();
- mKillList.put(mCurrentSpeechItem, true);
- mIsSpeaking = false;
-
- // was the engine writing to a file?
- if (mCurrentSpeechItem.mType == SpeechItem.TEXT_TO_FILE) {
- // delete the file that was being written
- if (mCurrentSpeechItem.mFilename != null) {
- File tempFile = new File(mCurrentSpeechItem.mFilename);
- Log.v(SERVICE_TAG, "Leaving behind " + mCurrentSpeechItem.mFilename);
- if (tempFile.exists()) {
- Log.v(SERVICE_TAG, "About to delete "
- + mCurrentSpeechItem.mFilename);
- if (tempFile.delete()) {
- Log.v(SERVICE_TAG, "file successfully deleted");
- }
- }
- }
- }
-
- mCurrentSpeechItem = null;
- }
- } else {
- Log.e(SERVICE_TAG, "TTS killAllUtterances(): queue locked longer than expected");
- result = TextToSpeech.ERROR;
- }
- } catch (InterruptedException e) {
- Log.e(SERVICE_TAG, "TTS killAllUtterances(): tryLock interrupted");
- result = TextToSpeech.ERROR;
- } finally {
- // This check is needed because finally will always run, even if the
- // method returns somewhere in the try block.
- if (speechQueueAvailable) {
- speechQueueLock.unlock();
- }
- return result;
- }
- }
-
-
- /**
- * Stops all speech output and removes any utterances still in the queue globally, except
- * those intended to be synthesized to file.
- */
- private int stopAll(String callingApp) {
- int result = TextToSpeech.ERROR;
- boolean speechQueueAvailable = false;
- try{
- speechQueueAvailable =
- speechQueueLock.tryLock(SPEECHQUEUELOCK_TIMEOUT, TimeUnit.MILLISECONDS);
- if (speechQueueAvailable) {
- for (int i = mSpeechQueue.size() - 1; i > -1; i--){
- if (mSpeechQueue.get(i).mType != SpeechItem.TEXT_TO_FILE){
- mSpeechQueue.remove(i);
- }
- }
- if ((mCurrentSpeechItem != null) &&
- ((mCurrentSpeechItem.mType != SpeechItem.TEXT_TO_FILE) ||
- mCurrentSpeechItem.mCallingApp.equals(callingApp))) {
- try {
- result = sNativeSynth.stop();
- } catch (NullPointerException e1) {
- // synth will become null during onDestroy()
- result = TextToSpeech.ERROR;
- }
- mKillList.put(mCurrentSpeechItem, true);
- if (mPlayer != null) {
- try {
- mPlayer.stop();
- } catch (IllegalStateException e) {
- // Do nothing, the player is already stopped.
- }
- }
- mIsSpeaking = false;
- mCurrentSpeechItem = null;
- } else {
- result = TextToSpeech.SUCCESS;
- }
- Log.i(SERVICE_TAG, "Stopped all");
- } else {
- Log.e(SERVICE_TAG, "TTS stopAll(): queue locked longer than expected");
- result = TextToSpeech.ERROR;
- }
- } catch (InterruptedException e) {
- Log.e(SERVICE_TAG, "TTS stopAll: tryLock interrupted");
- e.printStackTrace();
- } finally {
- // This check is needed because finally will always run; even if the
- // method returns somewhere in the try block.
- if (speechQueueAvailable) {
- speechQueueLock.unlock();
- }
- return result;
- }
- }
-
- public void onCompletion(MediaPlayer arg0) {
- // mCurrentSpeechItem may become null if it is stopped at the same
- // time it completes.
- SpeechItem currentSpeechItemCopy = mCurrentSpeechItem;
- if (currentSpeechItemCopy != null) {
- String callingApp = currentSpeechItemCopy.mCallingApp;
- ArrayList<String> params = currentSpeechItemCopy.mParams;
- String utteranceId = "";
- if (params != null) {
- for (int i = 0; i < params.size() - 1; i = i + 2) {
- String param = params.get(i);
- if (param.equals(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID)) {
- utteranceId = params.get(i + 1);
- }
- }
- }
- if (utteranceId.length() > 0) {
- dispatchUtteranceCompletedCallback(utteranceId, callingApp);
- }
- }
- processSpeechQueue();
- }
-
- private int playSilence(String callingApp, long duration, int queueMode,
- ArrayList<String> params) {
- if (queueMode == TextToSpeech.QUEUE_FLUSH) {
- stop(callingApp);
- }
- mSpeechQueue.add(new SpeechItem(callingApp, duration, params));
- if (!mIsSpeaking) {
- processSpeechQueue();
- }
- return TextToSpeech.SUCCESS;
- }
-
- private void silence(final SpeechItem speechItem) {
- class SilenceThread implements Runnable {
- public void run() {
- String utteranceId = "";
- if (speechItem.mParams != null){
- for (int i = 0; i < speechItem.mParams.size() - 1; i = i + 2){
- String param = speechItem.mParams.get(i);
- if (param.equals(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID)){
- utteranceId = speechItem.mParams.get(i+1);
- }
- }
- }
- try {
- Thread.sleep(speechItem.mDuration);
- } catch (InterruptedException e) {
- e.printStackTrace();
- } finally {
- if (utteranceId.length() > 0){
- dispatchUtteranceCompletedCallback(utteranceId, speechItem.mCallingApp);
- }
- processSpeechQueue();
- }
- }
- }
- Thread slnc = (new Thread(new SilenceThread()));
- slnc.setPriority(Thread.MIN_PRIORITY);
- slnc.start();
- }
-
- private void speakInternalOnly(final SpeechItem speechItem) {
- class SynthThread implements Runnable {
- public void run() {
- boolean synthAvailable = false;
- String utteranceId = "";
- try {
- synthAvailable = synthesizerLock.tryLock();
- if (!synthAvailable) {
- mSynthBusy = true;
- Thread.sleep(100);
- Thread synth = (new Thread(new SynthThread()));
- synth.start();
- mSynthBusy = false;
- return;
- }
- int streamType = DEFAULT_STREAM_TYPE;
- String language = "";
- String country = "";
- String variant = "";
- String speechRate = "";
- String engine = "";
- String pitch = "";
- float volume = TextToSpeech.Engine.DEFAULT_VOLUME;
- float pan = TextToSpeech.Engine.DEFAULT_PAN;
- if (speechItem.mParams != null){
- for (int i = 0; i < speechItem.mParams.size() - 1; i = i + 2){
- String param = speechItem.mParams.get(i);
- if (param != null) {
- if (param.equals(TextToSpeech.Engine.KEY_PARAM_RATE)) {
- speechRate = speechItem.mParams.get(i+1);
- } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_LANGUAGE)){
- language = speechItem.mParams.get(i+1);
- } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_COUNTRY)){
- country = speechItem.mParams.get(i+1);
- } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_VARIANT)){
- variant = speechItem.mParams.get(i+1);
- } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID)){
- utteranceId = speechItem.mParams.get(i+1);
- } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_STREAM)) {
- try {
- streamType
- = Integer.parseInt(speechItem.mParams.get(i + 1));
- } catch (NumberFormatException e) {
- streamType = DEFAULT_STREAM_TYPE;
- }
- } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_ENGINE)) {
- engine = speechItem.mParams.get(i + 1);
- } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_PITCH)) {
- pitch = speechItem.mParams.get(i + 1);
- } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_VOLUME)) {
- try {
- volume = Float.parseFloat(speechItem.mParams.get(i + 1));
- } catch (NumberFormatException e) {
- volume = TextToSpeech.Engine.DEFAULT_VOLUME;
- }
- } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_PAN)) {
- try {
- pan = Float.parseFloat(speechItem.mParams.get(i + 1));
- } catch (NumberFormatException e) {
- pan = TextToSpeech.Engine.DEFAULT_PAN;
- }
- }
- }
- }
- }
- // Only do the synthesis if it has not been killed by a subsequent utterance.
- if (mKillList.get(speechItem) == null) {
- if (engine.length() > 0) {
- setEngine(engine);
- } else {
- setEngine(getDefaultEngine());
- }
- if (language.length() > 0){
- setLanguage("", language, country, variant);
- } else {
- setLanguage("", getDefaultLanguage(), getDefaultCountry(),
- getDefaultLocVariant());
- }
- if (speechRate.length() > 0){
- setSpeechRate("", Integer.parseInt(speechRate));
- } else {
- setSpeechRate("", getDefaultRate());
- }
- if (pitch.length() > 0){
- setPitch("", Integer.parseInt(pitch));
- } else {
- setPitch("", getDefaultPitch());
- }
- try {
- sNativeSynth.speak(speechItem.mText, streamType, volume, pan);
- } catch (NullPointerException e) {
- // synth will become null during onDestroy()
- Log.v(SERVICE_TAG, " null synth, can't speak");
- }
- }
- } catch (InterruptedException e) {
- Log.e(SERVICE_TAG, "TTS speakInternalOnly(): tryLock interrupted");
- e.printStackTrace();
- } finally {
- // This check is needed because finally will always run;
- // even if the
- // method returns somewhere in the try block.
- if (utteranceId.length() > 0){
- dispatchUtteranceCompletedCallback(utteranceId, speechItem.mCallingApp);
- }
- if (synthAvailable) {
- synthesizerLock.unlock();
- processSpeechQueue();
- }
- }
- }
- }
- Thread synth = (new Thread(new SynthThread()));
- synth.setPriority(Thread.MAX_PRIORITY);
- synth.start();
- }
-
- private void synthToFileInternalOnly(final SpeechItem speechItem) {
- class SynthThread implements Runnable {
- public void run() {
- boolean synthAvailable = false;
- String utteranceId = "";
- Log.i(SERVICE_TAG, "Synthesizing to " + speechItem.mFilename);
- try {
- synthAvailable = synthesizerLock.tryLock();
- if (!synthAvailable) {
- synchronized (this) {
- mSynthBusy = true;
- }
- Thread.sleep(100);
- Thread synth = (new Thread(new SynthThread()));
- synth.start();
- synchronized (this) {
- mSynthBusy = false;
- }
- return;
- }
- String language = "";
- String country = "";
- String variant = "";
- String speechRate = "";
- String engine = "";
- String pitch = "";
- if (speechItem.mParams != null){
- for (int i = 0; i < speechItem.mParams.size() - 1; i = i + 2){
- String param = speechItem.mParams.get(i);
- if (param != null) {
- if (param.equals(TextToSpeech.Engine.KEY_PARAM_RATE)) {
- speechRate = speechItem.mParams.get(i+1);
- } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_LANGUAGE)){
- language = speechItem.mParams.get(i+1);
- } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_COUNTRY)){
- country = speechItem.mParams.get(i+1);
- } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_VARIANT)){
- variant = speechItem.mParams.get(i+1);
- } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID)){
- utteranceId = speechItem.mParams.get(i+1);
- } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_ENGINE)) {
- engine = speechItem.mParams.get(i + 1);
- } else if (param.equals(TextToSpeech.Engine.KEY_PARAM_PITCH)) {
- pitch = speechItem.mParams.get(i + 1);
- }
- }
- }
- }
- // Only do the synthesis if it has not been killed by a subsequent utterance.
- if (mKillList.get(speechItem) == null){
- if (engine.length() > 0) {
- setEngine(engine);
- } else {
- setEngine(getDefaultEngine());
- }
- if (language.length() > 0){
- setLanguage("", language, country, variant);
- } else {
- setLanguage("", getDefaultLanguage(), getDefaultCountry(),
- getDefaultLocVariant());
- }
- if (speechRate.length() > 0){
- setSpeechRate("", Integer.parseInt(speechRate));
- } else {
- setSpeechRate("", getDefaultRate());
- }
- if (pitch.length() > 0){
- setPitch("", Integer.parseInt(pitch));
- } else {
- setPitch("", getDefaultPitch());
- }
- try {
- sNativeSynth.synthesizeToFile(speechItem.mText, speechItem.mFilename);
- } catch (NullPointerException e) {
- // synth will become null during onDestroy()
- Log.v(SERVICE_TAG, " null synth, can't synthesize to file");
- }
- }
- } catch (InterruptedException e) {
- Log.e(SERVICE_TAG, "TTS synthToFileInternalOnly(): tryLock interrupted");
- e.printStackTrace();
- } finally {
- // This check is needed because finally will always run;
- // even if the
- // method returns somewhere in the try block.
- if (utteranceId.length() > 0){
- dispatchUtteranceCompletedCallback(utteranceId, speechItem.mCallingApp);
- }
- if (synthAvailable) {
- synthesizerLock.unlock();
- processSpeechQueue();
- }
- }
- }
- }
- Thread synth = (new Thread(new SynthThread()));
- synth.setPriority(Thread.MAX_PRIORITY);
- synth.start();
- }
-
- private SoundResource getSoundResource(SpeechItem speechItem) {
- SoundResource sr = null;
- String text = speechItem.mText;
- if (speechItem.mType == SpeechItem.SILENCE) {
- // Do nothing if this is just silence
- } else if (speechItem.mType == SpeechItem.EARCON) {
- sr = mEarcons.get(text);
- } else {
- sr = mUtterances.get(text);
- }
- return sr;
- }
-
- private void broadcastTtsQueueProcessingCompleted(){
- Intent i = new Intent(TextToSpeech.ACTION_TTS_QUEUE_PROCESSING_COMPLETED);
- sendBroadcast(i);
- }
-
-
- private void dispatchUtteranceCompletedCallback(String utteranceId, String packageName) {
- ITtsCallback cb = mCallbacksMap.get(packageName);
- if (cb == null){
- return;
- }
- Log.v(SERVICE_TAG, "TTS callback: dispatch started");
- // Broadcast to all clients the new value.
- final int N = mCallbacks.beginBroadcast();
- try {
- cb.utteranceCompleted(utteranceId);
- } catch (RemoteException e) {
- // The RemoteCallbackList will take care of removing
- // the dead object for us.
- }
- mCallbacks.finishBroadcast();
- Log.v(SERVICE_TAG, "TTS callback: dispatch completed to " + N);
- }
-
- private SpeechItem splitCurrentTextIfNeeded(SpeechItem currentSpeechItem){
- if (currentSpeechItem.mText.length() < MAX_SPEECH_ITEM_CHAR_LENGTH){
- return currentSpeechItem;
- } else {
- String callingApp = currentSpeechItem.mCallingApp;
- ArrayList<SpeechItem> splitItems = new ArrayList<SpeechItem>();
- int start = 0;
- int end = start + MAX_SPEECH_ITEM_CHAR_LENGTH - 1;
- String splitText;
- SpeechItem splitItem;
- while (end < currentSpeechItem.mText.length()){
- splitText = currentSpeechItem.mText.substring(start, end);
- splitItem = new SpeechItem(callingApp, splitText, null, SpeechItem.TEXT);
- splitItems.add(splitItem);
- start = end;
- end = start + MAX_SPEECH_ITEM_CHAR_LENGTH - 1;
- }
- splitText = currentSpeechItem.mText.substring(start);
- splitItem = new SpeechItem(callingApp, splitText, null, SpeechItem.TEXT);
- splitItems.add(splitItem);
- mSpeechQueue.remove(0);
- for (int i = splitItems.size() - 1; i >= 0; i--){
- mSpeechQueue.add(0, splitItems.get(i));
- }
- return mSpeechQueue.get(0);
- }
- }
-
- private void processSpeechQueue() {
- boolean speechQueueAvailable = false;
- synchronized (this) {
- if (mSynthBusy){
- // There is already a synth thread waiting to run.
- return;
- }
- }
- try {
- speechQueueAvailable =
- speechQueueLock.tryLock(SPEECHQUEUELOCK_TIMEOUT, TimeUnit.MILLISECONDS);
- if (!speechQueueAvailable) {
- Log.e(SERVICE_TAG, "processSpeechQueue - Speech queue is unavailable.");
- return;
- }
- if (mSpeechQueue.size() < 1) {
- mIsSpeaking = false;
- mKillList.clear();
- broadcastTtsQueueProcessingCompleted();
- return;
- }
-
- mCurrentSpeechItem = mSpeechQueue.get(0);
- mIsSpeaking = true;
- SoundResource sr = getSoundResource(mCurrentSpeechItem);
- // Synth speech as needed - synthesizer should call
- // processSpeechQueue to continue running the queue
- // Log.v(SERVICE_TAG, "TTS processing: " + mCurrentSpeechItem.mText);
- if (sr == null) {
- if (mCurrentSpeechItem.mType == SpeechItem.TEXT) {
- mCurrentSpeechItem = splitCurrentTextIfNeeded(mCurrentSpeechItem);
- speakInternalOnly(mCurrentSpeechItem);
- } else if (mCurrentSpeechItem.mType == SpeechItem.TEXT_TO_FILE) {
- synthToFileInternalOnly(mCurrentSpeechItem);
- } else {
- // This is either silence or an earcon that was missing
- silence(mCurrentSpeechItem);
- }
- } else {
- cleanUpPlayer();
- if (sr.mSourcePackageName == PKGNAME) {
- // Utterance is part of the TTS library
- mPlayer = MediaPlayer.create(this, sr.mResId);
- } else if (sr.mSourcePackageName != null) {
- // Utterance is part of the app calling the library
- Context ctx;
- try {
- ctx = this.createPackageContext(sr.mSourcePackageName, 0);
- } catch (NameNotFoundException e) {
- e.printStackTrace();
- mSpeechQueue.remove(0); // Remove it from the queue and
- // move on
- mIsSpeaking = false;
- return;
- }
- mPlayer = MediaPlayer.create(ctx, sr.mResId);
- } else {
- // Utterance is coming from a file
- mPlayer = MediaPlayer.create(this, Uri.parse(sr.mFilename));
- }
-
- // Check if Media Server is dead; if it is, clear the queue and
- // give up for now - hopefully, it will recover itself.
- if (mPlayer == null) {
- mSpeechQueue.clear();
- mIsSpeaking = false;
- return;
- }
- mPlayer.setOnCompletionListener(this);
- try {
- mPlayer.setAudioStreamType(getStreamTypeFromParams(mCurrentSpeechItem.mParams));
- mPlayer.start();
- } catch (IllegalStateException e) {
- mSpeechQueue.clear();
- mIsSpeaking = false;
- cleanUpPlayer();
- return;
- }
- }
- if (mSpeechQueue.size() > 0) {
- mSpeechQueue.remove(0);
- }
- } catch (InterruptedException e) {
- Log.e(SERVICE_TAG, "TTS processSpeechQueue: tryLock interrupted");
- e.printStackTrace();
- } finally {
- // This check is needed because finally will always run; even if the
- // method returns somewhere in the try block.
- if (speechQueueAvailable) {
- speechQueueLock.unlock();
- }
- }
- }
-
- private int getStreamTypeFromParams(ArrayList<String> paramList) {
- int streamType = DEFAULT_STREAM_TYPE;
- if (paramList == null) {
- return streamType;
- }
- for (int i = 0; i < paramList.size() - 1; i = i + 2) {
- String param = paramList.get(i);
- if ((param != null) && (param.equals(TextToSpeech.Engine.KEY_PARAM_STREAM))) {
- try {
- streamType = Integer.parseInt(paramList.get(i + 1));
- } catch (NumberFormatException e) {
- streamType = DEFAULT_STREAM_TYPE;
- }
- }
- }
- return streamType;
- }
-
- private void cleanUpPlayer() {
- if (mPlayer != null) {
- mPlayer.release();
- mPlayer = null;
- }
- }
-
- /**
- * Synthesizes the given text to a file using the specified parameters.
- *
- * @param text
- * The String of text that should be synthesized
- * @param params
- * An ArrayList of parameters. The first element of this array
- * controls the type of voice to use.
- * @param filename
- * The string that gives the full output filename; it should be
- * something like "/sdcard/myappsounds/mysound.wav".
- * @return A boolean that indicates if the synthesis can be started
- */
- private boolean synthesizeToFile(String callingApp, String text, ArrayList<String> params,
- String filename) {
- // Don't allow a filename that is too long
- if (filename.length() > MAX_FILENAME_LENGTH) {
- return false;
- }
- // Don't allow anything longer than the max text length; since this
- // is synthing to a file, don't even bother splitting it.
- if (text.length() >= MAX_SPEECH_ITEM_CHAR_LENGTH){
- return false;
- }
- // Check that the output file can be created
- try {
- File tempFile = new File(filename);
- if (tempFile.exists()) {
- Log.v("TtsService", "File " + filename + " exists, deleting.");
- tempFile.delete();
- }
- if (!tempFile.createNewFile()) {
- Log.e("TtsService", "Unable to synthesize to file: can't create " + filename);
- return false;
- }
- tempFile.delete();
- } catch (IOException e) {
- Log.e("TtsService", "Can't create " + filename + " due to exception " + e);
- return false;
- }
- mSpeechQueue.add(new SpeechItem(callingApp, text, params, SpeechItem.TEXT_TO_FILE, filename));
- if (!mIsSpeaking) {
- processSpeechQueue();
- }
- return true;
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- if (ACTION.equals(intent.getAction())) {
- for (String category : intent.getCategories()) {
- if (category.equals(CATEGORY)) {
- return mBinder;
- }
- }
- }
- return null;
- }
-
- private final android.speech.tts.ITts.Stub mBinder = new Stub() {
-
- public int registerCallback(String packageName, ITtsCallback cb) {
- if (cb != null) {
- mCallbacks.register(cb);
- mCallbacksMap.put(packageName, cb);
- return TextToSpeech.SUCCESS;
- }
- return TextToSpeech.ERROR;
- }
-
- public int unregisterCallback(String packageName, ITtsCallback cb) {
- if (cb != null) {
- mCallbacksMap.remove(packageName);
- mCallbacks.unregister(cb);
- return TextToSpeech.SUCCESS;
- }
- return TextToSpeech.ERROR;
- }
-
- /**
- * Speaks the given text using the specified queueing mode and
- * parameters.
- *
- * @param text
- * The text that should be spoken
- * @param queueMode
- * TextToSpeech.TTS_QUEUE_FLUSH for no queue (interrupts all previous utterances)
- * TextToSpeech.TTS_QUEUE_ADD for queued
- * @param params
- * An ArrayList of parameters. The first element of this
- * array controls the type of voice to use.
- */
- public int speak(String callingApp, String text, int queueMode, String[] params) {
- ArrayList<String> speakingParams = new ArrayList<String>();
- if (params != null) {
- speakingParams = new ArrayList<String>(Arrays.asList(params));
- }
- return mSelf.speak(callingApp, text, queueMode, speakingParams);
- }
-
- /**
- * Plays the earcon using the specified queueing mode and parameters.
- *
- * @param earcon
- * The earcon that should be played
- * @param queueMode
- * TextToSpeech.TTS_QUEUE_FLUSH for no queue (interrupts all previous utterances)
- * TextToSpeech.TTS_QUEUE_ADD for queued
- * @param params
- * An ArrayList of parameters.
- */
- public int playEarcon(String callingApp, String earcon, int queueMode, String[] params) {
- ArrayList<String> speakingParams = new ArrayList<String>();
- if (params != null) {
- speakingParams = new ArrayList<String>(Arrays.asList(params));
- }
- return mSelf.playEarcon(callingApp, earcon, queueMode, speakingParams);
- }
-
- /**
- * Plays the silence using the specified queueing mode and parameters.
- *
- * @param duration
- * The duration of the silence that should be played
- * @param queueMode
- * TextToSpeech.TTS_QUEUE_FLUSH for no queue (interrupts all previous utterances)
- * TextToSpeech.TTS_QUEUE_ADD for queued
- * @param params
- * An ArrayList of parameters.
- */
- public int playSilence(String callingApp, long duration, int queueMode, String[] params) {
- ArrayList<String> speakingParams = new ArrayList<String>();
- if (params != null) {
- speakingParams = new ArrayList<String>(Arrays.asList(params));
- }
- return mSelf.playSilence(callingApp, duration, queueMode, speakingParams);
- }
-
- /**
- * Stops all speech output and removes any utterances still in the
- * queue.
- */
- public int stop(String callingApp) {
- return mSelf.stop(callingApp);
- }
-
- /**
- * Returns whether or not the TTS is speaking.
- *
- * @return Boolean to indicate whether or not the TTS is speaking
- */
- public boolean isSpeaking() {
- return (mSelf.mIsSpeaking && (mSpeechQueue.size() < 1));
- }
-
- /**
- * Adds a sound resource to the TTS.
- *
- * @param text
- * The text that should be associated with the sound resource
- * @param packageName
- * The name of the package which has the sound resource
- * @param resId
- * The resource ID of the sound within its package
- */
- public void addSpeech(String callingApp, String text, String packageName, int resId) {
- mSelf.addSpeech(callingApp, text, packageName, resId);
- }
-
- /**
- * Adds a sound resource to the TTS.
- *
- * @param text
- * The text that should be associated with the sound resource
- * @param filename
- * The filename of the sound resource. This must be a
- * complete path like: (/sdcard/mysounds/mysoundbite.mp3).
- */
- public void addSpeechFile(String callingApp, String text, String filename) {
- mSelf.addSpeech(callingApp, text, filename);
- }
-
- /**
- * Adds a sound resource to the TTS as an earcon.
- *
- * @param earcon
- * The text that should be associated with the sound resource
- * @param packageName
- * The name of the package which has the sound resource
- * @param resId
- * The resource ID of the sound within its package
- */
- public void addEarcon(String callingApp, String earcon, String packageName, int resId) {
- mSelf.addEarcon(callingApp, earcon, packageName, resId);
- }
-
- /**
- * Adds a sound resource to the TTS as an earcon.
- *
- * @param earcon
- * The text that should be associated with the sound resource
- * @param filename
- * The filename of the sound resource. This must be a
- * complete path like: (/sdcard/mysounds/mysoundbite.mp3).
- */
- public void addEarconFile(String callingApp, String earcon, String filename) {
- mSelf.addEarcon(callingApp, earcon, filename);
- }
-
- /**
- * Sets the speech rate for the TTS. Note that this will only have an
- * effect on synthesized speech; it will not affect pre-recorded speech.
- *
- * @param speechRate
- * The speech rate that should be used
- */
- public int setSpeechRate(String callingApp, int speechRate) {
- return mSelf.setSpeechRate(callingApp, speechRate);
- }
-
- /**
- * Sets the pitch for the TTS. Note that this will only have an
- * effect on synthesized speech; it will not affect pre-recorded speech.
- *
- * @param pitch
- * The pitch that should be used for the synthesized voice
- */
- public int setPitch(String callingApp, int pitch) {
- return mSelf.setPitch(callingApp, pitch);
- }
-
- /**
- * Returns the level of support for the specified language.
- *
- * @param lang the three letter ISO language code.
- * @param country the three letter ISO country code.
- * @param variant the variant code associated with the country and language pair.
- * @return one of TTS_LANG_NOT_SUPPORTED, TTS_LANG_MISSING_DATA, TTS_LANG_AVAILABLE,
- * TTS_LANG_COUNTRY_AVAILABLE, TTS_LANG_COUNTRY_VAR_AVAILABLE as defined in
- * android.speech.tts.TextToSpeech.
- */
- public int isLanguageAvailable(String lang, String country, String variant,
- String[] params) {
- for (int i = 0; i < params.length - 1; i = i + 2){
- String param = params[i];
- if (param != null) {
- if (param.equals(TextToSpeech.Engine.KEY_PARAM_ENGINE)) {
- mSelf.setEngine(params[i + 1]);
- break;
- }
- }
- }
- return mSelf.isLanguageAvailable(lang, country, variant);
- }
-
- /**
- * Returns the currently set language / country / variant strings representing the
- * language used by the TTS engine.
- * @return null is no language is set, or an array of 3 string containing respectively
- * the language, country and variant.
- */
- public String[] getLanguage() {
- return mSelf.getLanguage();
- }
-
- /**
- * Sets the speech rate for the TTS, which affects the synthesized voice.
- *
- * @param lang the three letter ISO language code.
- * @param country the three letter ISO country code.
- * @param variant the variant code associated with the country and language pair.
- */
- public int setLanguage(String callingApp, String lang, String country, String variant) {
- return mSelf.setLanguage(callingApp, lang, country, variant);
- }
-
- /**
- * Synthesizes the given text to a file using the specified
- * parameters.
- *
- * @param text
- * The String of text that should be synthesized
- * @param params
- * An ArrayList of parameters. The first element of this
- * array controls the type of voice to use.
- * @param filename
- * The string that gives the full output filename; it should
- * be something like "/sdcard/myappsounds/mysound.wav".
- * @return A boolean that indicates if the synthesis succeeded
- */
- public boolean synthesizeToFile(String callingApp, String text, String[] params,
- String filename) {
- ArrayList<String> speakingParams = new ArrayList<String>();
- if (params != null) {
- speakingParams = new ArrayList<String>(Arrays.asList(params));
- }
- return mSelf.synthesizeToFile(callingApp, text, speakingParams, filename);
- }
-
- /**
- * Sets the speech synthesis engine for the TTS by specifying its packagename
- *
- * @param packageName the packageName of the speech synthesis engine (ie, "com.svox.pico")
- *
- * @return SUCCESS or ERROR as defined in android.speech.tts.TextToSpeech.
- */
- public int setEngineByPackageName(String packageName) {
- return mSelf.setEngine(packageName);
- }
-
- /**
- * Returns the packagename of the default speech synthesis engine.
- *
- * @return Packagename of the TTS engine that the user has chosen as their default.
- */
- public String getDefaultEngine() {
- return mSelf.getDefaultEngine();
- }
-
- /**
- * Returns whether or not the user is forcing their defaults to override the
- * Text-To-Speech settings set by applications.
- *
- * @return Whether or not defaults are enforced.
- */
- public boolean areDefaultsEnforced() {
- return mSelf.isDefaultEnforced();
- }
-
- };
-
-}
diff --git a/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java b/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java
index 5b80a93ab9d5..ca56c4fb53c4 100644
--- a/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/PasswordUnlockScreen.java
@@ -28,6 +28,7 @@ import com.android.internal.widget.PasswordEntryKeyboardView;
import android.os.CountDownTimer;
import android.os.SystemClock;
import android.telephony.TelephonyManager;
+import android.text.InputType;
import android.text.method.DigitsKeyListener;
import android.text.method.TextKeyListener;
import android.util.Log;
@@ -70,6 +71,7 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen
private CountDownTimer mCountdownTimer;
private StatusView mStatusView;
+ private final boolean mUseSystemIME = true; // TODO: Make configurable
// To avoid accidental lockout due to events while the device in in the pocket, ignore
// any passwords with length less than or equal to this length.
@@ -108,14 +110,23 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen
mPasswordEntry.setOnEditorActionListener(this);
mPasswordEntry.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
- if (mIsAlpha && !isPhysicalKbShowing) {
- mKeyboardViewAlpha.setVisibility(
- mKeyboardViewAlpha.getVisibility() == View.VISIBLE
- ? View.GONE : View.VISIBLE);
- mCallback.pokeWakelock();
+ if (mIsAlpha && !isPhysicalKbShowing && !mUseSystemIME) {
+ // Toggle visibility of alpha keyboard
+ final boolean visible = mKeyboardViewAlpha.getVisibility() == View.VISIBLE;
+ mKeyboardViewAlpha.setVisibility(visible ? View.GONE : View.VISIBLE);
}
+ mCallback.pokeWakelock();
}
});
+
+ // We don't currently use the IME for PIN mode, but this will make it work if we ever do...
+ if (!mIsAlpha) {
+ mPasswordEntry.setInputType(InputType.TYPE_CLASS_NUMBER
+ | InputType.TYPE_NUMBER_VARIATION_PASSWORD);
+ } else {
+ mPasswordEntry.setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD);
+ }
+
mEmergencyCallButton = (Button) findViewById(R.id.emergencyCall);
mEmergencyCallButton.setOnClickListener(this);
mLockPatternUtils.updateEmergencyCallButtonState(mEmergencyCallButton);
@@ -176,7 +187,7 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen
/** {@inheritDoc} */
public boolean needsInput() {
- return false;
+ return mUseSystemIME && mIsAlpha;
}
/** {@inheritDoc} */
@@ -295,7 +306,7 @@ public class PasswordUnlockScreen extends LinearLayout implements KeyguardScreen
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
// Check if this was the result of hitting the enter key
- if (actionId == EditorInfo.IME_NULL) {
+ if (actionId == EditorInfo.IME_NULL || actionId == EditorInfo.IME_ACTION_DONE) {
verifyPasswordAndUnlock();
return true;
}
diff --git a/services/audioflinger/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp
index 5c3b43fcbce4..dca795c40d9e 100644
--- a/services/audioflinger/AudioResampler.cpp
+++ b/services/audioflinger/AudioResampler.cpp
@@ -26,11 +26,15 @@
#include "AudioResamplerSinc.h"
#include "AudioResamplerCubic.h"
+#ifdef __arm__
+#include <machine/cpu-features.h>
+#endif
+
namespace android {
-#ifdef __ARM_ARCH_5E__ // optimized asm option
+#ifdef __ARM_HAVE_HALFWORD_MULTIPLY // optimized asm option
#define ASM_ARM_RESAMP1 // enable asm optimisation for ResamplerOrder1
-#endif // __ARM_ARCH_5E__
+#endif // __ARM_HAVE_HALFWORD_MULTIPLY
// ----------------------------------------------------------------------------
class AudioResamplerOrder1 : public AudioResampler {
diff --git a/services/input/Android.mk b/services/input/Android.mk
index 96431bcd9319..f9f8623f1c62 100644
--- a/services/input/Android.mk
+++ b/services/input/Android.mk
@@ -22,7 +22,9 @@ LOCAL_SRC_FILES:= \
InputManager.cpp \
InputReader.cpp \
InputWindow.cpp \
- PointerController.cpp
+ PointerController.cpp \
+ SpotController.cpp \
+ SpriteController.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index cf9b13de39c6..9ed1391301a7 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -20,6 +20,7 @@
#include "EventHub.h"
#include "InputDispatcher.h"
#include "PointerController.h"
+#include "SpotController.h"
#include <ui/Input.h>
#include <ui/DisplayInfo.h>
@@ -89,6 +90,9 @@ public:
/* Gets a pointer controller associated with the specified cursor device (ie. a mouse). */
virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId) = 0;
+
+ /* Gets a spot controller associated with the specified touch pad device. */
+ virtual sp<SpotControllerInterface> obtainSpotController(int32_t deviceId) = 0;
};
diff --git a/services/input/PointerController.cpp b/services/input/PointerController.cpp
index a4ee295a73b1..15effb7f7951 100644
--- a/services/input/PointerController.cpp
+++ b/services/input/PointerController.cpp
@@ -49,8 +49,11 @@ static const nsecs_t FADE_FRAME_INTERVAL = 1000000000LL / 60;
static const float FADE_DECAY_PER_FRAME = float(FADE_FRAME_INTERVAL) / FADE_DURATION;
-PointerController::PointerController(const sp<Looper>& looper, int32_t pointerLayer) :
- mLooper(looper), mPointerLayer(pointerLayer) {
+PointerController::PointerController(const sp<Looper>& looper,
+ const sp<SpriteController>& spriteController) :
+ mLooper(looper), mSpriteController(spriteController) {
+ mHandler = new WeakMessageHandler(this);
+
AutoMutex _l(mLock);
mLocked.displayWidth = -1;
@@ -61,34 +64,20 @@ PointerController::PointerController(const sp<Looper>& looper, int32_t pointerLa
mLocked.pointerY = 0;
mLocked.buttonState = 0;
- mLocked.iconBitmap = NULL;
- mLocked.iconHotSpotX = 0;
- mLocked.iconHotSpotY = 0;
-
mLocked.fadeAlpha = 1;
mLocked.inactivityFadeDelay = INACTIVITY_FADE_DELAY_NORMAL;
- mLocked.wantVisible = false;
mLocked.visible = false;
- mLocked.drawn = false;
- mHandler = new WeakMessageHandler(this);
+ mLocked.sprite = mSpriteController->createSprite();
}
PointerController::~PointerController() {
mLooper->removeMessages(mHandler);
- if (mSurfaceControl != NULL) {
- mSurfaceControl->clear();
- mSurfaceControl.clear();
- }
-
- if (mSurfaceComposerClient != NULL) {
- mSurfaceComposerClient->dispose();
- mSurfaceComposerClient.clear();
- }
+ AutoMutex _l(mLock);
- delete mLocked.iconBitmap;
+ mLocked.sprite.clear();
}
bool PointerController::getBounds(float* outMinX, float* outMinY,
@@ -214,75 +203,11 @@ void PointerController::setInactivityFadeDelay(InactivityFadeDelay inactivityFad
}
void PointerController::updateLocked() {
- bool wantVisibleAndHavePointerIcon = mLocked.wantVisible && mLocked.iconBitmap;
-
- if (wantVisibleAndHavePointerIcon) {
- // Want the pointer to be visible.
- // Ensure the surface is created and drawn.
- if (!createSurfaceIfNeededLocked() || !drawPointerIfNeededLocked()) {
- return;
- }
- } else {
- // Don't want the pointer to be visible.
- // If it is not visible then we are done.
- if (mSurfaceControl == NULL || !mLocked.visible) {
- return;
- }
- }
-
- status_t status = mSurfaceComposerClient->openTransaction();
- if (status) {
- LOGE("Error opening surface transaction to update pointer surface.");
- return;
- }
-
- if (wantVisibleAndHavePointerIcon) {
- status = mSurfaceControl->setPosition(
- mLocked.pointerX - mLocked.iconHotSpotX,
- mLocked.pointerY - mLocked.iconHotSpotY);
- if (status) {
- LOGE("Error %d moving pointer surface.", status);
- goto CloseTransaction;
- }
-
- status = mSurfaceControl->setAlpha(mLocked.fadeAlpha);
- if (status) {
- LOGE("Error %d setting pointer surface alpha.", status);
- goto CloseTransaction;
- }
-
- if (!mLocked.visible) {
- status = mSurfaceControl->setLayer(mPointerLayer);
- if (status) {
- LOGE("Error %d setting pointer surface layer.", status);
- goto CloseTransaction;
- }
-
- status = mSurfaceControl->show(mPointerLayer);
- if (status) {
- LOGE("Error %d showing pointer surface.", status);
- goto CloseTransaction;
- }
-
- mLocked.visible = true;
- }
- } else {
- if (mLocked.visible) {
- status = mSurfaceControl->hide();
- if (status) {
- LOGE("Error %d hiding pointer surface.", status);
- goto CloseTransaction;
- }
-
- mLocked.visible = false;
- }
- }
-
-CloseTransaction:
- status = mSurfaceComposerClient->closeTransaction();
- if (status) {
- LOGE("Error closing surface transaction to update pointer surface.");
- }
+ mLocked.sprite->openTransaction();
+ mLocked.sprite->setPosition(mLocked.pointerX, mLocked.pointerY);
+ mLocked.sprite->setAlpha(mLocked.fadeAlpha);
+ mLocked.sprite->setVisible(mLocked.visible);
+ mLocked.sprite->closeTransaction();
}
void PointerController::setDisplaySize(int32_t width, int32_t height) {
@@ -339,7 +264,7 @@ void PointerController::setDisplayOrientation(int32_t orientation) {
case DISPLAY_ORIENTATION_90:
temp = x;
x = y;
- y = mLocked.displayWidth - x;
+ y = mLocked.displayWidth - temp;
break;
case DISPLAY_ORIENTATION_180:
x = mLocked.displayWidth - x;
@@ -365,106 +290,7 @@ void PointerController::setDisplayOrientation(int32_t orientation) {
void PointerController::setPointerIcon(const SkBitmap* bitmap, float hotSpotX, float hotSpotY) {
AutoMutex _l(mLock);
- if (mLocked.iconBitmap) {
- delete mLocked.iconBitmap;
- mLocked.iconBitmap = NULL;
- }
-
- if (bitmap) {
- mLocked.iconBitmap = new SkBitmap();
- bitmap->copyTo(mLocked.iconBitmap, SkBitmap::kARGB_8888_Config);
- }
-
- mLocked.iconHotSpotX = hotSpotX;
- mLocked.iconHotSpotY = hotSpotY;
- mLocked.drawn = false;
-}
-
-bool PointerController::createSurfaceIfNeededLocked() {
- if (!mLocked.iconBitmap) {
- // If we don't have a pointer icon, then no point allocating a surface now.
- return false;
- }
-
- if (mSurfaceComposerClient == NULL) {
- mSurfaceComposerClient = new SurfaceComposerClient();
- }
-
- if (mSurfaceControl == NULL) {
- mSurfaceControl = mSurfaceComposerClient->createSurface(getpid(),
- String8("Pointer Icon"), 0,
- mLocked.iconBitmap->width(), mLocked.iconBitmap->height(),
- PIXEL_FORMAT_RGBA_8888);
- if (mSurfaceControl == NULL) {
- LOGE("Error creating pointer surface.");
- return false;
- }
- }
- return true;
-}
-
-bool PointerController::drawPointerIfNeededLocked() {
- if (!mLocked.drawn) {
- if (!mLocked.iconBitmap) {
- return false;
- }
-
- if (!resizeSurfaceLocked(mLocked.iconBitmap->width(), mLocked.iconBitmap->height())) {
- return false;
- }
-
- sp<Surface> surface = mSurfaceControl->getSurface();
-
- Surface::SurfaceInfo surfaceInfo;
- status_t status = surface->lock(&surfaceInfo);
- if (status) {
- LOGE("Error %d locking pointer surface before drawing.", status);
- return false;
- }
-
- SkBitmap surfaceBitmap;
- ssize_t bpr = surfaceInfo.s * bytesPerPixel(surfaceInfo.format);
- surfaceBitmap.setConfig(SkBitmap::kARGB_8888_Config, surfaceInfo.w, surfaceInfo.h, bpr);
- surfaceBitmap.setPixels(surfaceInfo.bits);
-
- SkCanvas surfaceCanvas;
- surfaceCanvas.setBitmapDevice(surfaceBitmap);
-
- SkPaint paint;
- paint.setXfermodeMode(SkXfermode::kSrc_Mode);
- surfaceCanvas.drawBitmap(*mLocked.iconBitmap, 0, 0, &paint);
-
- status = surface->unlockAndPost();
- if (status) {
- LOGE("Error %d unlocking pointer surface after drawing.", status);
- return false;
- }
- }
-
- mLocked.drawn = true;
- return true;
-}
-
-bool PointerController::resizeSurfaceLocked(int32_t width, int32_t height) {
- status_t status = mSurfaceComposerClient->openTransaction();
- if (status) {
- LOGE("Error opening surface transaction to resize pointer surface.");
- return false;
- }
-
- status = mSurfaceControl->setSize(width, height);
- if (status) {
- LOGE("Error %d setting pointer surface size.", status);
- return false;
- }
-
- status = mSurfaceComposerClient->closeTransaction();
- if (status) {
- LOGE("Error closing surface transaction to resize pointer surface.");
- return false;
- }
-
- return true;
+ mLocked.sprite->setBitmap(bitmap, hotSpotX, hotSpotY);
}
void PointerController::handleMessage(const Message& message) {
@@ -481,7 +307,7 @@ bool PointerController::unfadeBeforeUpdateLocked() {
sendFadeStepMessageDelayedLocked(getInactivityFadeDelayTimeLocked());
if (isFadingLocked()) {
- mLocked.wantVisible = true;
+ mLocked.visible = true;
mLocked.fadeAlpha = 1;
return true; // update required to effect the unfade
}
@@ -501,11 +327,11 @@ void PointerController::startInactivityFadeDelayLocked() {
}
void PointerController::fadeStepLocked() {
- if (mLocked.wantVisible) {
+ if (mLocked.visible) {
mLocked.fadeAlpha -= FADE_DECAY_PER_FRAME;
if (mLocked.fadeAlpha < 0) {
mLocked.fadeAlpha = 0;
- mLocked.wantVisible = false;
+ mLocked.visible = false;
} else {
sendFadeStepMessageDelayedLocked(FADE_FRAME_INTERVAL);
}
@@ -514,7 +340,7 @@ void PointerController::fadeStepLocked() {
}
bool PointerController::isFadingLocked() {
- return !mLocked.wantVisible || mLocked.fadeAlpha != 1;
+ return !mLocked.visible || mLocked.fadeAlpha != 1;
}
nsecs_t PointerController::getInactivityFadeDelayTimeLocked() {
diff --git a/services/input/PointerController.h b/services/input/PointerController.h
index e1dab5c78313..d467a5a01bcd 100644
--- a/services/input/PointerController.h
+++ b/services/input/PointerController.h
@@ -17,16 +17,14 @@
#ifndef _UI_POINTER_CONTROLLER_H
#define _UI_POINTER_CONTROLLER_H
+#include "SpriteController.h"
+
#include <ui/DisplayInfo.h>
#include <ui/Input.h>
#include <utils/RefBase.h>
#include <utils/Looper.h>
#include <utils/String8.h>
-#include <surfaceflinger/Surface.h>
-#include <surfaceflinger/SurfaceComposerClient.h>
-#include <surfaceflinger/ISurfaceComposer.h>
-
#include <SkBitmap.h>
namespace android {
@@ -86,7 +84,7 @@ public:
INACTIVITY_FADE_DELAY_SHORT = 1,
};
- PointerController(const sp<Looper>& looper, int32_t pointerLayer);
+ PointerController(const sp<Looper>& looper, const sp<SpriteController>& spriteController);
virtual bool getBounds(float* outMinX, float* outMinY,
float* outMaxX, float* outMaxY) const;
@@ -111,9 +109,8 @@ private:
mutable Mutex mLock;
sp<Looper> mLooper;
- int32_t mPointerLayer;
- sp<SurfaceComposerClient> mSurfaceComposerClient;
- sp<SurfaceControl> mSurfaceControl;
+ sp<SpriteController> mSpriteController;
+ sp<WeakMessageHandler> mHandler;
struct Locked {
int32_t displayWidth;
@@ -124,26 +121,17 @@ private:
float pointerY;
uint32_t buttonState;
- SkBitmap* iconBitmap;
- float iconHotSpotX;
- float iconHotSpotY;
-
float fadeAlpha;
InactivityFadeDelay inactivityFadeDelay;
- bool wantVisible;
bool visible;
- bool drawn;
- } mLocked;
- sp<WeakMessageHandler> mHandler;
+ sp<Sprite> sprite;
+ } mLocked;
bool getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const;
void setPositionLocked(float x, float y);
void updateLocked();
- bool createSurfaceIfNeededLocked();
- bool drawPointerIfNeededLocked();
- bool resizeSurfaceLocked(int32_t width, int32_t height);
void handleMessage(const Message& message);
bool unfadeBeforeUpdateLocked();
diff --git a/services/input/SpotController.cpp b/services/input/SpotController.cpp
new file mode 100644
index 000000000000..dffad81009c7
--- /dev/null
+++ b/services/input/SpotController.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "SpotController"
+
+//#define LOG_NDEBUG 0
+
+// Log debug messages about spot updates
+#define DEBUG_SPOT_UPDATES 0
+
+#include "SpotController.h"
+
+#include <cutils/log.h>
+
+namespace android {
+
+// --- SpotController ---
+
+SpotController::SpotController(const sp<Looper>& looper,
+ const sp<SpriteController>& spriteController) :
+ mLooper(looper), mSpriteController(spriteController) {
+ mHandler = new WeakMessageHandler(this);
+}
+
+SpotController::~SpotController() {
+ mLooper->removeMessages(mHandler);
+}
+
+void SpotController:: handleMessage(const Message& message) {
+}
+
+} // namespace android
diff --git a/services/input/SpotController.h b/services/input/SpotController.h
new file mode 100644
index 000000000000..1d091d7e2aa0
--- /dev/null
+++ b/services/input/SpotController.h
@@ -0,0 +1,71 @@
+/*
+ * 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 _UI_SPOT_CONTROLLER_H
+#define _UI_SPOT_CONTROLLER_H
+
+#include "SpriteController.h"
+
+#include <utils/RefBase.h>
+#include <utils/Looper.h>
+
+#include <SkBitmap.h>
+
+namespace android {
+
+/*
+ * Interface for displaying spots on screen that visually represent the positions
+ * of fingers on a touch pad.
+ *
+ * The spot controller is responsible for providing synchronization and for tracking
+ * display orientation changes if needed.
+ */
+class SpotControllerInterface : public virtual RefBase {
+protected:
+ SpotControllerInterface() { }
+ virtual ~SpotControllerInterface() { }
+
+public:
+
+};
+
+
+/*
+ * Sprite-based spot controller implementation.
+ */
+class SpotController : public SpotControllerInterface, public MessageHandler {
+protected:
+ virtual ~SpotController();
+
+public:
+ SpotController(const sp<Looper>& looper, const sp<SpriteController>& spriteController);
+
+private:
+ mutable Mutex mLock;
+
+ sp<Looper> mLooper;
+ sp<SpriteController> mSpriteController;
+ sp<WeakMessageHandler> mHandler;
+
+ struct Locked {
+ } mLocked;
+
+ void handleMessage(const Message& message);
+};
+
+} // namespace android
+
+#endif // _UI_SPOT_CONTROLLER_H
diff --git a/services/input/SpriteController.cpp b/services/input/SpriteController.cpp
new file mode 100644
index 000000000000..c6d4390fcc92
--- /dev/null
+++ b/services/input/SpriteController.cpp
@@ -0,0 +1,472 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Sprites"
+
+//#define LOG_NDEBUG 0
+
+#include "SpriteController.h"
+
+#include <cutils/log.h>
+#include <utils/String8.h>
+
+#include <SkBitmap.h>
+#include <SkCanvas.h>
+#include <SkColor.h>
+#include <SkPaint.h>
+#include <SkXfermode.h>
+
+namespace android {
+
+// --- SpriteController ---
+
+SpriteController::SpriteController(const sp<Looper>& looper, int32_t overlayLayer) :
+ mLooper(looper), mOverlayLayer(overlayLayer) {
+ mHandler = new WeakMessageHandler(this);
+}
+
+SpriteController::~SpriteController() {
+ mLooper->removeMessages(mHandler);
+
+ if (mSurfaceComposerClient != NULL) {
+ mSurfaceComposerClient->dispose();
+ mSurfaceComposerClient.clear();
+ }
+}
+
+sp<Sprite> SpriteController::createSprite() {
+ return new SpriteImpl(this);
+}
+
+void SpriteController::invalidateSpriteLocked(const sp<SpriteImpl>& sprite) {
+ bool wasEmpty = mInvalidatedSprites.isEmpty();
+ mInvalidatedSprites.push(sprite);
+ if (wasEmpty) {
+ mLooper->sendMessage(mHandler, Message(MSG_UPDATE_SPRITES));
+ }
+}
+
+void SpriteController::disposeSurfaceLocked(const sp<SurfaceControl>& surfaceControl) {
+ bool wasEmpty = mDisposedSurfaces.isEmpty();
+ mDisposedSurfaces.push(surfaceControl);
+ if (wasEmpty) {
+ mLooper->sendMessage(mHandler, Message(MSG_DISPOSE_SURFACES));
+ }
+}
+
+void SpriteController::handleMessage(const Message& message) {
+ switch (message.what) {
+ case MSG_UPDATE_SPRITES:
+ doUpdateSprites();
+ break;
+ case MSG_DISPOSE_SURFACES:
+ doDisposeSurfaces();
+ break;
+ }
+}
+
+void SpriteController::doUpdateSprites() {
+ // Collect information about sprite updates.
+ // Each sprite update record includes a reference to its associated sprite so we can
+ // be certain the sprites will not be deleted while this function runs. Sprites
+ // may invalidate themselves again during this time but we will handle those changes
+ // in the next iteration.
+ Vector<SpriteUpdate> updates;
+ size_t numSprites;
+ { // acquire lock
+ AutoMutex _l(mLock);
+
+ numSprites = mInvalidatedSprites.size();
+ for (size_t i = 0; i < numSprites; i++) {
+ const sp<SpriteImpl>& sprite = mInvalidatedSprites.itemAt(i);
+
+ updates.push(SpriteUpdate(sprite, sprite->getStateLocked()));
+ sprite->resetDirtyLocked();
+ }
+ mInvalidatedSprites.clear();
+ } // release lock
+
+ // Create missing surfaces.
+ bool surfaceChanged = false;
+ for (size_t i = 0; i < numSprites; i++) {
+ SpriteUpdate& update = updates.editItemAt(i);
+
+ if (update.state.surfaceControl == NULL && update.state.wantSurfaceVisible()) {
+ update.state.surfaceWidth = update.state.bitmap.width();
+ update.state.surfaceHeight = update.state.bitmap.height();
+ update.state.surfaceDrawn = false;
+ update.state.surfaceVisible = false;
+ update.state.surfaceControl = obtainSurface(
+ update.state.surfaceWidth, update.state.surfaceHeight);
+ if (update.state.surfaceControl != NULL) {
+ update.surfaceChanged = surfaceChanged = true;
+ }
+ }
+ }
+
+ // Resize sprites if needed, inside a global transaction.
+ bool haveGlobalTransaction = false;
+ for (size_t i = 0; i < numSprites; i++) {
+ SpriteUpdate& update = updates.editItemAt(i);
+
+ if (update.state.surfaceControl != NULL && update.state.wantSurfaceVisible()) {
+ int32_t desiredWidth = update.state.bitmap.width();
+ int32_t desiredHeight = update.state.bitmap.height();
+ if (update.state.surfaceWidth < desiredWidth
+ || update.state.surfaceHeight < desiredHeight) {
+ if (!haveGlobalTransaction) {
+ SurfaceComposerClient::openGlobalTransaction();
+ haveGlobalTransaction = true;
+ }
+
+ status_t status = update.state.surfaceControl->setSize(desiredWidth, desiredHeight);
+ if (status) {
+ LOGE("Error %d resizing sprite surface from %dx%d to %dx%d",
+ status, update.state.surfaceWidth, update.state.surfaceHeight,
+ desiredWidth, desiredHeight);
+ } else {
+ update.state.surfaceWidth = desiredWidth;
+ update.state.surfaceHeight = desiredHeight;
+ update.state.surfaceDrawn = false;
+ update.surfaceChanged = surfaceChanged = true;
+
+ if (update.state.surfaceVisible) {
+ status = update.state.surfaceControl->hide();
+ if (status) {
+ LOGE("Error %d hiding sprite surface after resize.", status);
+ } else {
+ update.state.surfaceVisible = false;
+ }
+ }
+ }
+ }
+ }
+ }
+ if (haveGlobalTransaction) {
+ SurfaceComposerClient::closeGlobalTransaction();
+ }
+
+ // Redraw sprites if needed.
+ for (size_t i = 0; i < numSprites; i++) {
+ SpriteUpdate& update = updates.editItemAt(i);
+
+ if ((update.state.dirty & DIRTY_BITMAP) && update.state.surfaceDrawn) {
+ update.state.surfaceDrawn = false;
+ update.surfaceChanged = surfaceChanged = true;
+ }
+
+ if (update.state.surfaceControl != NULL && !update.state.surfaceDrawn
+ && update.state.wantSurfaceVisible()) {
+ sp<Surface> surface = update.state.surfaceControl->getSurface();
+ Surface::SurfaceInfo surfaceInfo;
+ status_t status = surface->lock(&surfaceInfo);
+ if (status) {
+ LOGE("Error %d locking sprite surface before drawing.", status);
+ } else {
+ SkBitmap surfaceBitmap;
+ ssize_t bpr = surfaceInfo.s * bytesPerPixel(surfaceInfo.format);
+ surfaceBitmap.setConfig(SkBitmap::kARGB_8888_Config,
+ surfaceInfo.w, surfaceInfo.h, bpr);
+ surfaceBitmap.setPixels(surfaceInfo.bits);
+
+ SkCanvas surfaceCanvas;
+ surfaceCanvas.setBitmapDevice(surfaceBitmap);
+
+ SkPaint paint;
+ paint.setXfermodeMode(SkXfermode::kSrc_Mode);
+ surfaceCanvas.drawBitmap(update.state.bitmap, 0, 0, &paint);
+
+ if (surfaceInfo.w > uint32_t(update.state.bitmap.width())) {
+ paint.setColor(0); // transparent fill color
+ surfaceCanvas.drawRectCoords(update.state.bitmap.width(), 0,
+ surfaceInfo.w, update.state.bitmap.height(), paint);
+ }
+ if (surfaceInfo.h > uint32_t(update.state.bitmap.height())) {
+ paint.setColor(0); // transparent fill color
+ surfaceCanvas.drawRectCoords(0, update.state.bitmap.height(),
+ surfaceInfo.w, surfaceInfo.h, paint);
+ }
+
+ status = surface->unlockAndPost();
+ if (status) {
+ LOGE("Error %d unlocking and posting sprite surface after drawing.", status);
+ } else {
+ update.state.surfaceDrawn = true;
+ update.surfaceChanged = surfaceChanged = true;
+ }
+ }
+ }
+ }
+
+ // Set sprite surface properties and make them visible.
+ bool haveTransaction = false;
+ for (size_t i = 0; i < numSprites; i++) {
+ SpriteUpdate& update = updates.editItemAt(i);
+
+ bool wantSurfaceVisibleAndDrawn = update.state.wantSurfaceVisible()
+ && update.state.surfaceDrawn;
+ bool becomingVisible = wantSurfaceVisibleAndDrawn && !update.state.surfaceVisible;
+ bool becomingHidden = !wantSurfaceVisibleAndDrawn && update.state.surfaceVisible;
+ if (update.state.surfaceControl != NULL && (becomingVisible || becomingHidden
+ || (wantSurfaceVisibleAndDrawn && (update.state.dirty & (DIRTY_ALPHA
+ | DIRTY_POSITION | DIRTY_TRANSFORMATION_MATRIX | DIRTY_LAYER
+ | DIRTY_VISIBILITY | DIRTY_HOTSPOT))))) {
+ status_t status;
+ if (!haveTransaction) {
+ status = mSurfaceComposerClient->openTransaction();
+ if (status) {
+ LOGE("Error %d opening transation to update sprite surface.", status);
+ break;
+ }
+ haveTransaction = true;
+ }
+
+ if (wantSurfaceVisibleAndDrawn
+ && (becomingVisible || (update.state.dirty & DIRTY_ALPHA))) {
+ status = update.state.surfaceControl->setAlpha(update.state.alpha);
+ if (status) {
+ LOGE("Error %d setting sprite surface alpha.", status);
+ }
+ }
+
+ if (wantSurfaceVisibleAndDrawn
+ && (becomingVisible || (update.state.dirty & (DIRTY_POSITION
+ | DIRTY_HOTSPOT)))) {
+ status = update.state.surfaceControl->setPosition(
+ update.state.positionX - update.state.hotSpotX,
+ update.state.positionY - update.state.hotSpotY);
+ if (status) {
+ LOGE("Error %d setting sprite surface position.", status);
+ }
+ }
+
+ if (wantSurfaceVisibleAndDrawn
+ && (becomingVisible
+ || (update.state.dirty & DIRTY_TRANSFORMATION_MATRIX))) {
+ status = update.state.surfaceControl->setMatrix(
+ update.state.transformationMatrix.dsdx,
+ update.state.transformationMatrix.dtdx,
+ update.state.transformationMatrix.dsdy,
+ update.state.transformationMatrix.dtdy);
+ if (status) {
+ LOGE("Error %d setting sprite surface transformation matrix.", status);
+ }
+ }
+
+ int32_t surfaceLayer = mOverlayLayer + update.state.layer;
+ if (wantSurfaceVisibleAndDrawn
+ && (becomingVisible || (update.state.dirty & DIRTY_LAYER))) {
+ status = update.state.surfaceControl->setLayer(surfaceLayer);
+ if (status) {
+ LOGE("Error %d setting sprite surface layer.", status);
+ }
+ }
+
+ if (becomingVisible) {
+ status = update.state.surfaceControl->show(surfaceLayer);
+ if (status) {
+ LOGE("Error %d showing sprite surface.", status);
+ } else {
+ update.state.surfaceVisible = true;
+ update.surfaceChanged = surfaceChanged = true;
+ }
+ } else if (becomingHidden) {
+ status = update.state.surfaceControl->hide();
+ if (status) {
+ LOGE("Error %d hiding sprite surface.", status);
+ } else {
+ update.state.surfaceVisible = false;
+ update.surfaceChanged = surfaceChanged = true;
+ }
+ }
+ }
+ }
+
+ if (haveTransaction) {
+ status_t status = mSurfaceComposerClient->closeTransaction();
+ if (status) {
+ LOGE("Error %d closing transaction to update sprite surface.", status);
+ }
+ }
+
+ // If any surfaces were changed, write back the new surface properties to the sprites.
+ if (surfaceChanged) { // acquire lock
+ AutoMutex _l(mLock);
+
+ for (size_t i = 0; i < numSprites; i++) {
+ const SpriteUpdate& update = updates.itemAt(i);
+
+ if (update.surfaceChanged) {
+ update.sprite->setSurfaceLocked(update.state.surfaceControl,
+ update.state.surfaceWidth, update.state.surfaceHeight,
+ update.state.surfaceDrawn, update.state.surfaceVisible);
+ }
+ }
+ } // release lock
+
+ // Clear the sprite update vector outside the lock. It is very important that
+ // we do not clear sprite references inside the lock since we could be releasing
+ // the last remaining reference to the sprite here which would result in the
+ // sprite being deleted and the lock being reacquired by the sprite destructor
+ // while already held.
+ updates.clear();
+}
+
+void SpriteController::doDisposeSurfaces() {
+ // Collect disposed surfaces.
+ Vector<sp<SurfaceControl> > disposedSurfaces;
+ { // acquire lock
+ disposedSurfaces = mDisposedSurfaces;
+ mDisposedSurfaces.clear();
+ } // release lock
+
+ // Release the last reference to each surface outside of the lock.
+ // We don't want the surfaces to be deleted while we are holding our lock.
+ disposedSurfaces.clear();
+}
+
+void SpriteController::ensureSurfaceComposerClient() {
+ if (mSurfaceComposerClient == NULL) {
+ mSurfaceComposerClient = new SurfaceComposerClient();
+ }
+}
+
+sp<SurfaceControl> SpriteController::obtainSurface(int32_t width, int32_t height) {
+ ensureSurfaceComposerClient();
+
+ sp<SurfaceControl> surfaceControl = mSurfaceComposerClient->createSurface(
+ getpid(), String8("Sprite"), 0, width, height, PIXEL_FORMAT_RGBA_8888);
+ if (surfaceControl == NULL) {
+ LOGE("Error creating sprite surface.");
+ return NULL;
+ }
+ return surfaceControl;
+}
+
+
+// --- SpriteController::SpriteImpl ---
+
+SpriteController::SpriteImpl::SpriteImpl(const sp<SpriteController> controller) :
+ mController(controller), mTransactionNestingCount(0) {
+}
+
+SpriteController::SpriteImpl::~SpriteImpl() {
+ AutoMutex _m(mController->mLock);
+
+ // Let the controller take care of deleting the last reference to sprite
+ // surfaces so that we do not block the caller on an IPC here.
+ if (mState.surfaceControl != NULL) {
+ mController->disposeSurfaceLocked(mState.surfaceControl);
+ mState.surfaceControl.clear();
+ }
+}
+
+void SpriteController::SpriteImpl::setBitmap(const SkBitmap* bitmap,
+ float hotSpotX, float hotSpotY) {
+ AutoMutex _l(mController->mLock);
+
+ if (bitmap) {
+ bitmap->copyTo(&mState.bitmap, SkBitmap::kARGB_8888_Config);
+ } else {
+ mState.bitmap.reset();
+ }
+
+ uint32_t dirty = DIRTY_BITMAP;
+ if (mState.hotSpotX != hotSpotX || mState.hotSpotY != hotSpotY) {
+ mState.hotSpotX = hotSpotX;
+ mState.hotSpotY = hotSpotY;
+ dirty |= DIRTY_HOTSPOT;
+ }
+
+ invalidateLocked(dirty);
+}
+
+void SpriteController::SpriteImpl::setVisible(bool visible) {
+ AutoMutex _l(mController->mLock);
+
+ if (mState.visible != visible) {
+ mState.visible = visible;
+ invalidateLocked(DIRTY_VISIBILITY);
+ }
+}
+
+void SpriteController::SpriteImpl::setPosition(float x, float y) {
+ AutoMutex _l(mController->mLock);
+
+ if (mState.positionX != x || mState.positionY != y) {
+ mState.positionX = x;
+ mState.positionY = y;
+ invalidateLocked(DIRTY_POSITION);
+ }
+}
+
+void SpriteController::SpriteImpl::setLayer(int32_t layer) {
+ AutoMutex _l(mController->mLock);
+
+ if (mState.layer != layer) {
+ mState.layer = layer;
+ invalidateLocked(DIRTY_LAYER);
+ }
+}
+
+void SpriteController::SpriteImpl::setAlpha(float alpha) {
+ AutoMutex _l(mController->mLock);
+
+ if (mState.alpha != alpha) {
+ mState.alpha = alpha;
+ invalidateLocked(DIRTY_ALPHA);
+ }
+}
+
+void SpriteController::SpriteImpl::setTransformationMatrix(
+ const SpriteTransformationMatrix& matrix) {
+ AutoMutex _l(mController->mLock);
+
+ if (mState.transformationMatrix != matrix) {
+ mState.transformationMatrix = matrix;
+ invalidateLocked(DIRTY_TRANSFORMATION_MATRIX);
+ }
+}
+
+void SpriteController::SpriteImpl::openTransaction() {
+ AutoMutex _l(mController->mLock);
+
+ mTransactionNestingCount += 1;
+}
+
+void SpriteController::SpriteImpl::closeTransaction() {
+ AutoMutex _l(mController->mLock);
+
+ LOG_ALWAYS_FATAL_IF(mTransactionNestingCount == 0,
+ "Sprite closeTransaction() called but there is no open sprite transaction");
+
+ mTransactionNestingCount -= 1;
+ if (mTransactionNestingCount == 0 && mState.dirty) {
+ mController->invalidateSpriteLocked(this);
+ }
+}
+
+void SpriteController::SpriteImpl::invalidateLocked(uint32_t dirty) {
+ if (mTransactionNestingCount > 0) {
+ bool wasDirty = mState.dirty;
+ mState.dirty |= dirty;
+ if (!wasDirty) {
+ mController->invalidateSpriteLocked(this);
+ }
+ }
+}
+
+} // namespace android
diff --git a/services/input/SpriteController.h b/services/input/SpriteController.h
new file mode 100644
index 000000000000..27afb5ecbd82
--- /dev/null
+++ b/services/input/SpriteController.h
@@ -0,0 +1,251 @@
+/*
+ * 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 _UI_SPRITES_H
+#define _UI_SPRITES_H
+
+#include <utils/RefBase.h>
+#include <utils/Looper.h>
+
+#include <surfaceflinger/Surface.h>
+#include <surfaceflinger/SurfaceComposerClient.h>
+#include <surfaceflinger/ISurfaceComposer.h>
+
+#include <SkBitmap.h>
+
+namespace android {
+
+/*
+ * Transformation matrix for a sprite.
+ */
+struct SpriteTransformationMatrix {
+ inline SpriteTransformationMatrix() : dsdx(1.0f), dtdx(0.0f), dsdy(0.0f), dtdy(1.0f) { }
+
+ float dsdx;
+ float dtdx;
+ float dsdy;
+ float dtdy;
+
+ inline bool operator== (const SpriteTransformationMatrix& other) {
+ return dsdx == other.dsdx
+ && dtdx == other.dtdx
+ && dsdy == other.dsdy
+ && dtdy == other.dtdy;
+ }
+
+ inline bool operator!= (const SpriteTransformationMatrix& other) {
+ return !(*this == other);
+ }
+};
+
+/*
+ * A sprite is a simple graphical object that is displayed on-screen above other layers.
+ * The basic sprite class is an interface.
+ * The implementation is provided by the sprite controller.
+ */
+class Sprite : public RefBase {
+protected:
+ Sprite() { }
+ virtual ~Sprite() { }
+
+public:
+ /* Sets the bitmap that is drawn by the sprite.
+ * The sprite retains a copy of the bitmap for subsequent rendering. */
+ virtual void setBitmap(const SkBitmap* bitmap, float hotSpotX, float hotSpotY) = 0;
+
+ /* Sets whether the sprite is visible. */
+ virtual void setVisible(bool visible) = 0;
+
+ /* Sets the sprite position on screen, relative to the sprite's hot spot. */
+ virtual void setPosition(float x, float y) = 0;
+
+ /* Sets the layer of the sprite, relative to the system sprite overlay layer.
+ * Layer 0 is the overlay layer, > 0 appear above this layer. */
+ virtual void setLayer(int32_t layer) = 0;
+
+ /* Sets the sprite alpha blend ratio between 0.0 and 1.0. */
+ virtual void setAlpha(float alpha) = 0;
+
+ /* Sets the sprite transformation matrix. */
+ virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix) = 0;
+
+ /* Opens or closes a transaction to perform a batch of sprite updates as part of
+ * a single operation such as setPosition and setAlpha. It is not necessary to
+ * open a transaction when updating a single property.
+ * Calls to openTransaction() nest and must be matched by an equal number
+ * of calls to closeTransaction(). */
+ virtual void openTransaction() = 0;
+ virtual void closeTransaction() = 0;
+};
+
+/*
+ * Displays sprites on the screen.
+ *
+ * This interface is used by PointerController and SpotController to draw pointers or
+ * spot representations of fingers. It is not intended for general purpose use
+ * by other components.
+ *
+ * All sprite position updates and rendering is performed asynchronously.
+ *
+ * Clients are responsible for animating sprites by periodically updating their properties.
+ */
+class SpriteController : public MessageHandler {
+protected:
+ virtual ~SpriteController();
+
+public:
+ SpriteController(const sp<Looper>& looper, int32_t overlayLayer);
+
+ /* Creates a new sprite, initially invisible. */
+ sp<Sprite> createSprite();
+
+private:
+ enum {
+ MSG_UPDATE_SPRITES,
+ MSG_DISPOSE_SURFACES,
+ };
+
+ enum {
+ DIRTY_BITMAP = 1 << 0,
+ DIRTY_ALPHA = 1 << 1,
+ DIRTY_POSITION = 1 << 2,
+ DIRTY_TRANSFORMATION_MATRIX = 1 << 3,
+ DIRTY_LAYER = 1 << 4,
+ DIRTY_VISIBILITY = 1 << 5,
+ DIRTY_HOTSPOT = 1 << 6,
+ };
+
+ /* Describes the state of a sprite.
+ * This structure is designed so that it can be copied during updates so that
+ * surfaces can be resized and redrawn without blocking the client by holding a lock
+ * on the sprites for a long time.
+ * Note that the SkBitmap holds a reference to a shared (and immutable) pixel ref. */
+ struct SpriteState {
+ inline SpriteState() :
+ dirty(0), hotSpotX(0), hotSpotY(0), visible(false),
+ positionX(0), positionY(0), layer(0), alpha(1.0f),
+ surfaceWidth(0), surfaceHeight(0), surfaceDrawn(false), surfaceVisible(false) {
+ }
+
+ uint32_t dirty;
+
+ SkBitmap bitmap;
+ float hotSpotX;
+ float hotSpotY;
+ bool visible;
+ float positionX;
+ float positionY;
+ int32_t layer;
+ float alpha;
+ SpriteTransformationMatrix transformationMatrix;
+
+ sp<SurfaceControl> surfaceControl;
+ int32_t surfaceWidth;
+ int32_t surfaceHeight;
+ bool surfaceDrawn;
+ bool surfaceVisible;
+
+ inline bool wantSurfaceVisible() const {
+ return visible && alpha > 0.0f && !bitmap.isNull() && !bitmap.empty();
+ }
+ };
+
+ /* Client interface for a sprite.
+ * Requests acquire a lock on the controller, update local state and request the
+ * controller to invalidate the sprite.
+ * The real heavy lifting of creating, resizing and redrawing surfaces happens
+ * asynchronously with no locks held except in short critical section to copy
+ * the sprite state before the work and update the sprite surface control afterwards.
+ */
+ class SpriteImpl : public Sprite {
+ protected:
+ virtual ~SpriteImpl();
+
+ public:
+ SpriteImpl(const sp<SpriteController> controller);
+
+ virtual void setBitmap(const SkBitmap* bitmap, float hotSpotX, float hotSpotY);
+ virtual void setVisible(bool visible);
+ virtual void setPosition(float x, float y);
+ virtual void setLayer(int32_t layer);
+ virtual void setAlpha(float alpha);
+ virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix);
+ virtual void openTransaction();
+ virtual void closeTransaction();
+
+ inline const SpriteState& getStateLocked() const {
+ return mState;
+ }
+
+ inline void resetDirtyLocked() {
+ mState.dirty = 0;
+ }
+
+ inline void setSurfaceLocked(const sp<SurfaceControl>& surfaceControl,
+ int32_t width, int32_t height, bool drawn, bool visible) {
+ mState.surfaceControl = surfaceControl;
+ mState.surfaceWidth = width;
+ mState.surfaceHeight = height;
+ mState.surfaceDrawn = drawn;
+ mState.surfaceVisible = visible;
+ }
+
+ private:
+ sp<SpriteController> mController;
+
+ SpriteState mState; // guarded by mController->mLock
+ uint32_t mTransactionNestingCount; // guarded by mController->mLock
+
+ void invalidateLocked(uint32_t dirty);
+ };
+
+ /* Stores temporary information collected during the sprite update cycle. */
+ struct SpriteUpdate {
+ inline SpriteUpdate() : surfaceChanged(false) { }
+ inline SpriteUpdate(const sp<SpriteImpl> sprite, const SpriteState& state) :
+ sprite(sprite), state(state), surfaceChanged(false) {
+ }
+
+ sp<SpriteImpl> sprite;
+ SpriteState state;
+ bool surfaceChanged;
+ };
+
+ mutable Mutex mLock;
+
+ sp<Looper> mLooper;
+ const int32_t mOverlayLayer;
+ sp<WeakMessageHandler> mHandler;
+
+ sp<SurfaceComposerClient> mSurfaceComposerClient;
+
+ Vector<sp<SpriteImpl> > mInvalidatedSprites; // guarded by mLock
+ Vector<sp<SurfaceControl> > mDisposedSurfaces; // guarded by mLock
+
+ void invalidateSpriteLocked(const sp<SpriteImpl>& sprite);
+ void disposeSurfaceLocked(const sp<SurfaceControl>& surfaceControl);
+
+ void handleMessage(const Message& message);
+ void doUpdateSprites();
+ void doDisposeSurfaces();
+
+ void ensureSurfaceComposerClient();
+ sp<SurfaceControl> obtainSurface(int32_t width, int32_t height);
+};
+
+} // namespace android
+
+#endif // _UI_SPRITES_H
diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp
index 4c5f2397a564..ba8ca9c399a4 100644
--- a/services/input/tests/InputReader_test.cpp
+++ b/services/input/tests/InputReader_test.cpp
@@ -192,6 +192,10 @@ private:
virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId) {
return mPointerControllers.valueFor(deviceId);
}
+
+ virtual sp<SpotControllerInterface> obtainSpotController(int32_t device) {
+ return NULL;
+ }
};
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index 1455764dced8..70287721f93a 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -1399,6 +1399,24 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
+ public InputMethodSubtype getLastInputMethodSubtype() {
+ synchronized (mMethodMap) {
+ final Pair<String, String> lastIme = mSettings.getLastInputMethodAndSubtypeLocked();
+ // TODO: Handle the case of the last IME with no subtypes
+ if (lastIme == null || TextUtils.isEmpty(lastIme.first)
+ || TextUtils.isEmpty(lastIme.second)) return null;
+ final InputMethodInfo lastImi = mMethodMap.get(lastIme.first);
+ if (lastImi == null) return null;
+ try {
+ final int lastSubtypeHash = Integer.valueOf(lastIme.second);
+ return lastImi.getSubtypeAt(getSubtypeIdFromHashCode(
+ lastImi, lastSubtypeHash));
+ } catch (NumberFormatException e) {
+ return null;
+ }
+ }
+ }
+
private void setInputMethodWithSubtypeId(IBinder token, String id, int subtypeId) {
synchronized (mMethodMap) {
if (token == null) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 9990b7be7d94..31b7f86e0bb8 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -441,8 +441,7 @@ public final class ActivityManagerService extends ActivityManagerNative
/**
* List of intents that were used to start the most recent tasks.
*/
- final ArrayList<TaskRecord> mRecentTasks
- = new ArrayList<TaskRecord>();
+ final ArrayList<TaskRecord> mRecentTasks = new ArrayList<TaskRecord>();
/**
* All of the applications we currently have running organized by name.
@@ -450,8 +449,7 @@ public final class ActivityManagerService extends ActivityManagerNative
* returned by the package manager), and the keys are ApplicationRecord
* objects.
*/
- final ProcessMap<ProcessRecord> mProcessNames
- = new ProcessMap<ProcessRecord>();
+ final ProcessMap<ProcessRecord> mProcessNames = new ProcessMap<ProcessRecord>();
/**
* The currently running heavy-weight process, if any.
@@ -480,8 +478,7 @@ public final class ActivityManagerService extends ActivityManagerNative
* <p>NOTE: This object is protected by its own lock, NOT the global
* activity manager lock!
*/
- final SparseArray<ProcessRecord> mPidsSelfLocked
- = new SparseArray<ProcessRecord>();
+ final SparseArray<ProcessRecord> mPidsSelfLocked = new SparseArray<ProcessRecord>();
/**
* All of the processes that have been forced to be foreground. The key
@@ -2981,7 +2978,10 @@ public final class ActivityManagerService extends ActivityManagerNative
synchronized (this) {
if (!showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID) {
- Process.killProcess(app.pid);
+ Slog.w(TAG, "Killing " + app + ": background ANR");
+ EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+ app.processName, app.setAdj, "background ANR");
+ Process.killProcessQuiet(app.pid);
return;
}
@@ -3446,7 +3446,9 @@ public final class ActivityManagerService extends ActivityManagerNative
bringDownServiceLocked(sr, true);
}
}
- Process.killProcess(pid);
+ EventLog.writeEvent(EventLogTags.AM_KILL, pid,
+ app.processName, app.setAdj, "start timeout");
+ Process.killProcessQuiet(pid);
if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
Slog.w(TAG, "Unattached app died before backup, skipping");
try {
@@ -3492,7 +3494,7 @@ public final class ActivityManagerService extends ActivityManagerNative
+ " (IApplicationThread " + thread + "); dropping process");
EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);
if (pid > 0 && pid != MY_PID) {
- Process.killProcess(pid);
+ Process.killProcessQuiet(pid);
} else {
try {
thread.scheduleExit();
@@ -3890,18 +3892,17 @@ public final class ActivityManagerService extends ActivityManagerNative
}
for (int i=0; i<intents.length; i++) {
Intent intent = intents[i];
- if (intent == null) {
- throw new IllegalArgumentException("Null intent at index " + i);
- }
- if (intent.hasFileDescriptors()) {
- throw new IllegalArgumentException("File descriptors passed in Intent");
- }
- if (type == INTENT_SENDER_BROADCAST &&
- (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
- throw new IllegalArgumentException(
- "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
+ if (intent != null) {
+ if (intent.hasFileDescriptors()) {
+ throw new IllegalArgumentException("File descriptors passed in Intent");
+ }
+ if (type == INTENT_SENDER_BROADCAST &&
+ (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
+ throw new IllegalArgumentException(
+ "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
+ }
+ intents[i] = new Intent(intent);
}
- intents[i] = new Intent(intent);
}
if (resolvedTypes != null && resolvedTypes.length != intents.length) {
throw new IllegalArgumentException(
@@ -4832,11 +4833,6 @@ public final class ActivityManagerService extends ActivityManagerNative
throw new SecurityException(msg);
}
- final boolean canReadFb = (flags&ActivityManager.TASKS_GET_THUMBNAILS) != 0
- && checkCallingPermission(
- android.Manifest.permission.READ_FRAME_BUFFER)
- == PackageManager.PERMISSION_GRANTED;
-
int pos = mMainStack.mHistory.size()-1;
ActivityRecord next =
pos >= 0 ? (ActivityRecord)mMainStack.mHistory.get(pos) : null;
@@ -4876,13 +4872,6 @@ public final class ActivityManagerService extends ActivityManagerNative
ci.id = curTask.taskId;
ci.baseActivity = r.intent.getComponent();
ci.topActivity = top.intent.getComponent();
- if (canReadFb) {
- if (top.state == ActivityState.RESUMED) {
- ci.thumbnail = top.stack.screenshotActivities(top);
- } else if (top.thumbHolder != null) {
- ci.thumbnail = top.thumbHolder.lastThumbnail;
- }
- }
if (top.thumbHolder != null) {
ci.description = top.thumbHolder.lastDescription;
}
@@ -4955,8 +4944,6 @@ public final class ActivityManagerService extends ActivityManagerNative
IPackageManager pm = AppGlobals.getPackageManager();
- ActivityRecord resumed = mMainStack.mResumedActivity;
-
final int N = mRecentTasks.size();
ArrayList<ActivityManager.RecentTaskInfo> res
= new ArrayList<ActivityManager.RecentTaskInfo>(
@@ -5002,74 +4989,121 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
+ private TaskRecord taskForIdLocked(int id) {
+ final int N = mRecentTasks.size();
+ for (int i=0; i<N; i++) {
+ TaskRecord tr = mRecentTasks.get(i);
+ if (tr.taskId == id) {
+ return tr;
+ }
+ }
+ return null;
+ }
+
public ActivityManager.TaskThumbnails getTaskThumbnails(int id) {
synchronized (this) {
enforceCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,
- "getTaskThumbnail()");
- ActivityRecord resumed = mMainStack.mResumedActivity;
- final int N = mRecentTasks.size();
- for (int i=0; i<N; i++) {
- TaskRecord tr = mRecentTasks.get(i);
- if (tr.taskId == id) {
- final ActivityManager.TaskThumbnails thumbs
- = new ActivityManager.TaskThumbnails();
- if (resumed != null && resumed.thumbHolder == tr) {
- thumbs.mainThumbnail = resumed.stack.screenshotActivities(resumed);
- } else {
- thumbs.mainThumbnail = tr.lastThumbnail;
- }
- // How many different sub-thumbnails?
- final int NA = mMainStack.mHistory.size();
- int j = 0;
- ThumbnailHolder holder = null;
- while (j < NA) {
- ActivityRecord ar = (ActivityRecord)mMainStack.mHistory.get(j);
- j++;
- if (ar.task == tr) {
- holder = ar.thumbHolder;
- break;
- }
- }
- ArrayList<Bitmap> bitmaps = new ArrayList<Bitmap>();
- thumbs.otherThumbnails = bitmaps;
- ActivityRecord lastActivity = null;
- while (j < NA) {
- ActivityRecord ar = (ActivityRecord)mMainStack.mHistory.get(j);
- j++;
- if (ar.task != tr) {
- break;
- }
- lastActivity = ar;
- if (ar.thumbHolder != holder && holder != null) {
- thumbs.numSubThumbbails++;
- holder = ar.thumbHolder;
- bitmaps.add(holder.lastThumbnail);
- }
- }
- if (lastActivity != null && bitmaps.size() > 0) {
- if (resumed == lastActivity) {
- Bitmap bm = lastActivity.stack.screenshotActivities(lastActivity);
- if (bm != null) {
- bitmaps.remove(bitmaps.size()-1);
- bitmaps.add(bm);
- }
- }
+ "getTaskThumbnails()");
+ TaskRecord tr = taskForIdLocked(id);
+ if (tr != null) {
+ return mMainStack.getTaskThumbnailsLocked(tr);
+ }
+ }
+ return null;
+ }
+
+ public boolean removeSubTask(int taskId, int subTaskIndex) {
+ synchronized (this) {
+ enforceCallingPermission(android.Manifest.permission.REMOVE_TASKS,
+ "removeSubTask()");
+ long ident = Binder.clearCallingIdentity();
+ try {
+ return mMainStack.removeTaskActivitiesLocked(taskId, subTaskIndex) != null;
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
+ private void removeTaskProcessesLocked(ActivityRecord root) {
+ TaskRecord tr = root.task;
+ Intent baseIntent = new Intent(
+ tr.intent != null ? tr.intent : tr.affinityIntent);
+ ComponentName component = baseIntent.getComponent();
+ if (component == null) {
+ Slog.w(TAG, "Now component for base intent of task: " + tr);
+ return;
+ }
+
+ // Find any running services associated with this app.
+ ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
+ for (ServiceRecord sr : mServices.values()) {
+ if (sr.packageName.equals(component.getPackageName())) {
+ services.add(sr);
+ }
+ }
+
+ // Take care of any running services associated with the app.
+ for (int i=0; i<services.size(); i++) {
+ ServiceRecord sr = services.get(i);
+ if (sr.startRequested) {
+ if ((sr.serviceInfo.flags&ServiceInfo.FLAG_STOP_WITH_TASK) != 0) {
+ stopServiceLocked(sr);
+ } else {
+ sr.pendingStarts.add(new ServiceRecord.StartItem(sr, true,
+ sr.makeNextStartId(), baseIntent, -1));
+ if (sr.app != null && sr.app.thread != null) {
+ sendServiceArgsLocked(sr, false);
}
- if (thumbs.numSubThumbbails > 0) {
- thumbs.retriever = new IThumbnailRetriever.Stub() {
- public Bitmap getThumbnail(int index) {
- if (index < 0 || index >= thumbs.otherThumbnails.size()) {
- return null;
- }
- return thumbs.otherThumbnails.get(index);
- }
- };
+ }
+ }
+ }
+
+ // Find any running processes associated with this app.
+ ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
+ SparseArray<ProcessRecord> appProcs
+ = mProcessNames.getMap().get(component.getPackageName());
+ if (appProcs != null) {
+ for (int i=0; i<appProcs.size(); i++) {
+ procs.add(appProcs.valueAt(i));
+ }
+ }
+
+ // Kill the running processes.
+ for (int i=0; i<procs.size(); i++) {
+ ProcessRecord pr = procs.get(i);
+ if (pr.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
+ Slog.i(TAG, "Killing " + pr + ": remove task");
+ EventLog.writeEvent(EventLogTags.AM_KILL, pr.pid,
+ pr.processName, pr.setAdj, "remove task");
+ Process.killProcessQuiet(pr.pid);
+ } else {
+ pr.waitingToKill = "remove task";
+ }
+ }
+ }
+
+ public boolean removeTask(int taskId, int flags) {
+ synchronized (this) {
+ enforceCallingPermission(android.Manifest.permission.REMOVE_TASKS,
+ "removeTask()");
+ long ident = Binder.clearCallingIdentity();
+ try {
+ ActivityRecord r = mMainStack.removeTaskActivitiesLocked(taskId, -1);
+ if (r != null) {
+ mRecentTasks.remove(r.task);
+
+ if ((flags&ActivityManager.REMOVE_TASK_KILL_PROCESS) != 0) {
+ removeTaskProcessesLocked(r);
}
- return thumbs;
+
+ return true;
}
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
- return null;
+ return false;
}
private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
@@ -5123,21 +5157,18 @@ public final class ActivityManagerService extends ActivityManagerNative
}
final long origId = Binder.clearCallingIdentity();
try {
- int N = mRecentTasks.size();
- for (int i=0; i<N; i++) {
- TaskRecord tr = mRecentTasks.get(i);
- if (tr.taskId == task) {
- if ((flags&ActivityManager.MOVE_TASK_NO_USER_ACTION) == 0) {
- mMainStack.mUserLeaving = true;
- }
- if ((flags&ActivityManager.MOVE_TASK_WITH_HOME) != 0) {
- // Caller wants the home activity moved with it. To accomplish this,
- // we'll just move the home task to the top first.
- mMainStack.moveHomeToFrontLocked();
- }
- mMainStack.moveTaskToFrontLocked(tr, null);
- return;
+ TaskRecord tr = taskForIdLocked(task);
+ if (tr != null) {
+ if ((flags&ActivityManager.MOVE_TASK_NO_USER_ACTION) == 0) {
+ mMainStack.mUserLeaving = true;
}
+ if ((flags&ActivityManager.MOVE_TASK_WITH_HOME) != 0) {
+ // Caller wants the home activity moved with it. To accomplish this,
+ // we'll just move the home task to the top first.
+ mMainStack.moveHomeToFrontLocked();
+ }
+ mMainStack.moveTaskToFrontLocked(tr, null);
+ return;
}
for (int i=mMainStack.mHistory.size()-1; i>=0; i--) {
ActivityRecord hr = (ActivityRecord)mMainStack.mHistory.get(i);
@@ -6661,11 +6692,10 @@ public final class ActivityManagerService extends ActivityManagerNative
}
if (app.pid > 0 && app.pid != MY_PID) {
handleAppCrashLocked(app);
- Slog.i(ActivityManagerService.TAG, "Killing "
- + app.processName + " (pid=" + app.pid + "): user's request");
+ Slog.i(ActivityManagerService.TAG, "Killing " + app + ": user's request");
EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
app.processName, app.setAdj, "user's request after error");
- Process.killProcess(app.pid);
+ Process.killProcessQuiet(app.pid);
}
}
}
@@ -8946,7 +8976,7 @@ public final class ActivityManagerService extends ActivityManagerNative
+ " in dying process " + proc.processName);
EventLog.writeEvent(EventLogTags.AM_KILL, capp.pid,
capp.processName, capp.setAdj, "dying provider " + proc.processName);
- Process.killProcess(capp.pid);
+ Process.killProcessQuiet(capp.pid);
}
}
@@ -9453,7 +9483,7 @@ public final class ActivityManagerService extends ActivityManagerNative
if (si.doneExecutingCount > 0) {
flags |= Service.START_FLAG_REDELIVERY;
}
- r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
+ r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent);
} catch (RemoteException e) {
// Remote process gone... we'll let the normal cleanup take
// care of this.
@@ -9539,11 +9569,8 @@ public final class ActivityManagerService extends ActivityManagerNative
// pending arguments, then fake up one so its onStartCommand() will
// be called.
if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
- r.lastStartId++;
- if (r.lastStartId < 1) {
- r.lastStartId = 1;
- }
- r.pendingStarts.add(new ServiceRecord.StartItem(r, r.lastStartId, null, -1));
+ r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
+ null, -1));
}
sendServiceArgsLocked(r, true);
@@ -9897,11 +9924,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
r.startRequested = true;
r.callStart = false;
- r.lastStartId++;
- if (r.lastStartId < 1) {
- r.lastStartId = 1;
- }
- r.pendingStarts.add(new ServiceRecord.StartItem(r, r.lastStartId,
+ r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
service, targetPermissionUid));
r.lastActivity = SystemClock.uptimeMillis();
synchronized (r.stats.getBatteryStats()) {
@@ -9943,6 +9966,15 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
+ private void stopServiceLocked(ServiceRecord service) {
+ synchronized (service.stats.getBatteryStats()) {
+ service.stats.stopRunningLocked();
+ }
+ service.startRequested = false;
+ service.callStart = false;
+ bringDownServiceLocked(service, false);
+ }
+
public int stopService(IApplicationThread caller, Intent service,
String resolvedType) {
// Refuse possible leaked file descriptors
@@ -9966,14 +9998,12 @@ public final class ActivityManagerService extends ActivityManagerNative
ServiceLookupResult r = findServiceLocked(service, resolvedType);
if (r != null) {
if (r.record != null) {
- synchronized (r.record.stats.getBatteryStats()) {
- r.record.stats.stopRunningLocked();
- }
- r.record.startRequested = false;
- r.record.callStart = false;
final long origId = Binder.clearCallingIdentity();
- bringDownServiceLocked(r.record, false);
- Binder.restoreCallingIdentity(origId);
+ try {
+ stopServiceLocked(r.record);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
return 1;
}
return -1;
@@ -10035,7 +10065,7 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
- if (r.lastStartId != startId) {
+ if (r.getLastStartId() != startId) {
return false;
}
@@ -10476,7 +10506,7 @@ public final class ActivityManagerService extends ActivityManagerNative
case Service.START_NOT_STICKY: {
// We are done with the associated start arguments.
r.findDeliveredStart(startId, true);
- if (r.lastStartId == startId) {
+ if (r.getLastStartId() == startId) {
// There is no more work, and this service
// doesn't want to hang around if killed.
r.stopIfKilled = true;
@@ -10496,6 +10526,12 @@ public final class ActivityManagerService extends ActivityManagerNative
}
break;
}
+ case Service.START_TASK_REMOVED_COMPLETE: {
+ // Special processing for onTaskRemoved(). Don't
+ // impact normal onStartCommand() processing.
+ r.findDeliveredStart(startId, true);
+ break;
+ }
default:
throw new IllegalArgumentException(
"Unknown service start result: " + res);
@@ -12885,23 +12921,31 @@ public final class ActivityManagerService extends ActivityManagerNative
if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG,
"Setting process group of " + app.processName
+ " to " + app.curSchedGroup);
- if (true) {
- long oldId = Binder.clearCallingIdentity();
- try {
- Process.setProcessGroup(app.pid, app.curSchedGroup);
- } catch (Exception e) {
- Slog.w(TAG, "Failed setting process group of " + app.pid
- + " to " + app.curSchedGroup);
- e.printStackTrace();
- } finally {
- Binder.restoreCallingIdentity(oldId);
- }
- }
- if (false) {
- if (app.thread != null) {
+ if (app.waitingToKill != null &&
+ app.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
+ Slog.i(TAG, "Killing " + app + ": " + app.waitingToKill);
+ EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+ app.processName, app.setAdj, app.waitingToKill);
+ Process.killProcessQuiet(app.pid);
+ } else {
+ if (true) {
+ long oldId = Binder.clearCallingIdentity();
try {
- app.thread.setSchedulingGroup(app.curSchedGroup);
- } catch (RemoteException e) {
+ Process.setProcessGroup(app.pid, app.curSchedGroup);
+ } catch (Exception e) {
+ Slog.w(TAG, "Failed setting process group of " + app.pid
+ + " to " + app.curSchedGroup);
+ e.printStackTrace();
+ } finally {
+ Binder.restoreCallingIdentity(oldId);
+ }
+ }
+ if (false) {
+ if (app.thread != null) {
+ try {
+ app.thread.setSchedulingGroup(app.curSchedGroup);
+ } catch (RemoteException e) {
+ }
}
}
}
@@ -13024,7 +13068,9 @@ public final class ActivityManagerService extends ActivityManagerNative
+ (app.thread != null ? app.thread.asBinder() : null)
+ ")\n");
if (app.pid > 0 && app.pid != MY_PID) {
- Process.killProcess(app.pid);
+ EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+ app.processName, app.setAdj, "empty");
+ Process.killProcessQuiet(app.pid);
} else {
try {
app.thread.scheduleExit();
@@ -13090,7 +13136,9 @@ public final class ActivityManagerService extends ActivityManagerNative
+ (app.thread != null ? app.thread.asBinder() : null)
+ ")\n");
if (app.pid > 0 && app.pid != MY_PID) {
- Process.killProcess(app.pid);
+ EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+ app.processName, app.setAdj, "empty");
+ Process.killProcessQuiet(app.pid);
} else {
try {
app.thread.scheduleExit();
@@ -13147,7 +13195,9 @@ public final class ActivityManagerService extends ActivityManagerNative
+ (app.thread != null ? app.thread.asBinder() : null)
+ ")\n");
if (app.pid > 0 && app.pid != MY_PID) {
- Process.killProcess(app.pid);
+ EventLog.writeEvent(EventLogTags.AM_KILL, app.pid,
+ app.processName, app.setAdj, "old background");
+ Process.killProcessQuiet(app.pid);
} else {
try {
app.thread.scheduleExit();
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index e1d380b569e3..95588956a31a 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -21,8 +21,10 @@ import com.android.internal.os.BatteryStatsImpl;
import com.android.server.am.ActivityManagerService.PendingActivityLaunch;
import android.app.Activity;
+import android.app.ActivityManager;
import android.app.AppGlobals;
import android.app.IActivityManager;
+import android.app.IThumbnailRetriever;
import static android.app.IActivityManager.START_CLASS_NOT_FOUND;
import static android.app.IActivityManager.START_DELIVERED_TO_TOP;
import static android.app.IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
@@ -69,7 +71,7 @@ import java.util.List;
/**
* State and management of a single stack of activities.
*/
-final public class ActivityStack {
+final class ActivityStack {
static final String TAG = ActivityManagerService.TAG;
static final boolean localLOGV = ActivityManagerService.localLOGV;
static final boolean DEBUG_SWITCH = ActivityManagerService.DEBUG_SWITCH;
@@ -135,14 +137,14 @@ final public class ActivityStack {
* The back history of all previous (and possibly still
* running) activities. It contains HistoryRecord objects.
*/
- final ArrayList mHistory = new ArrayList();
+ final ArrayList<ActivityRecord> mHistory = new ArrayList<ActivityRecord>();
/**
* List of running activities, sorted by recent usage.
* The first entry in the list is the least recently used.
* It contains HistoryRecord objects.
*/
- final ArrayList mLRUActivities = new ArrayList();
+ final ArrayList<ActivityRecord> mLRUActivities = new ArrayList<ActivityRecord>();
/**
* List of activities that are waiting for a new activity
@@ -346,7 +348,7 @@ final public class ActivityStack {
final ActivityRecord topRunningActivityLocked(ActivityRecord notTop) {
int i = mHistory.size()-1;
while (i >= 0) {
- ActivityRecord r = (ActivityRecord)mHistory.get(i);
+ ActivityRecord r = mHistory.get(i);
if (!r.finishing && r != notTop) {
return r;
}
@@ -358,7 +360,7 @@ final public class ActivityStack {
final ActivityRecord topRunningNonDelayedActivityLocked(ActivityRecord notTop) {
int i = mHistory.size()-1;
while (i >= 0) {
- ActivityRecord r = (ActivityRecord)mHistory.get(i);
+ ActivityRecord r = mHistory.get(i);
if (!r.finishing && !r.delayedResume && r != notTop) {
return r;
}
@@ -379,7 +381,7 @@ final public class ActivityStack {
final ActivityRecord topRunningActivityLocked(IBinder token, int taskId) {
int i = mHistory.size()-1;
while (i >= 0) {
- ActivityRecord r = (ActivityRecord)mHistory.get(i);
+ ActivityRecord r = mHistory.get(i);
// Note: the taskId check depends on real taskId fields being non-zero
if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
return r;
@@ -425,7 +427,7 @@ final public class ActivityStack {
final int N = mHistory.size();
for (int i=(N-1); i>=0; i--) {
- ActivityRecord r = (ActivityRecord)mHistory.get(i);
+ ActivityRecord r = mHistory.get(i);
if (!r.finishing && r.task != cp
&& r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
cp = r.task;
@@ -469,7 +471,7 @@ final public class ActivityStack {
final int N = mHistory.size();
for (int i=(N-1); i>=0; i--) {
- ActivityRecord r = (ActivityRecord)mHistory.get(i);
+ ActivityRecord r = mHistory.get(i);
if (!r.finishing) {
if (r.intent.getComponent().equals(cls)) {
//Slog.i(TAG, "Found matching class!");
@@ -504,6 +506,7 @@ final public class ActivityStack {
}
r.app = app;
+ app.waitingToKill = null;
if (localLOGV) Slog.v(TAG, "Launching: " + r);
@@ -678,7 +681,7 @@ final public class ActivityStack {
}
// Ensure activities are no longer sleeping.
for (int i=mHistory.size()-1; i>=0; i--) {
- ActivityRecord r = (ActivityRecord)mHistory.get(i);
+ ActivityRecord r = mHistory.get(i);
r.setSleeping(false);
}
mGoingToSleepActivities.clear();
@@ -724,7 +727,7 @@ final public class ActivityStack {
// Make sure any stopped but visible activities are now sleeping.
// This ensures that the activity's onStop() is called.
for (int i=mHistory.size()-1; i>=0; i--) {
- ActivityRecord r = (ActivityRecord)mHistory.get(i);
+ ActivityRecord r = mHistory.get(i);
if (r.state == ActivityState.STOPPING || r.state == ActivityState.STOPPED) {
r.setSleeping(true);
}
@@ -862,7 +865,7 @@ final public class ActivityStack {
synchronized (mService) {
int index = indexOfTokenLocked(token);
if (index >= 0) {
- r = (ActivityRecord)mHistory.get(index);
+ r = mHistory.get(index);
mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
if (mPausingActivity == r) {
r.state = ActivityState.PAUSED;
@@ -1024,7 +1027,7 @@ final public class ActivityStack {
ActivityRecord r;
boolean behindFullscreen = false;
for (; i>=0; i--) {
- r = (ActivityRecord)mHistory.get(i);
+ r = mHistory.get(i);
if (DEBUG_VISBILITY) Slog.v(
TAG, "Make visible? " + r + " finishing=" + r.finishing
+ " state=" + r.state);
@@ -1108,7 +1111,7 @@ final public class ActivityStack {
// Now for any activities that aren't visible to the user, make
// sure they no longer are keeping the screen frozen.
while (i >= 0) {
- r = (ActivityRecord)mHistory.get(i);
+ r = mHistory.get(i);
if (DEBUG_VISBILITY) Slog.v(
TAG, "Make invisible? " + r + " finishing=" + r.finishing
+ " state=" + r.state
@@ -1499,7 +1502,7 @@ final public class ActivityStack {
// If starting in an existing task, find where that is...
boolean startIt = true;
for (int i = NH-1; i >= 0; i--) {
- ActivityRecord p = (ActivityRecord)mHistory.get(i);
+ ActivityRecord p = mHistory.get(i);
if (p.finishing) {
continue;
}
@@ -1646,7 +1649,7 @@ final public class ActivityStack {
int replyChainEnd = -1;
int lastReparentPos = -1;
for (int i=mHistory.size()-1; i>=-1; i--) {
- ActivityRecord below = i >= 0 ? (ActivityRecord)mHistory.get(i) : null;
+ ActivityRecord below = i >= 0 ? mHistory.get(i) : null;
if (below != null && below.finishing) {
continue;
@@ -1700,7 +1703,7 @@ final public class ActivityStack {
// bottom of the activity stack. This also keeps it
// correctly ordered with any activities we previously
// moved.
- ActivityRecord p = (ActivityRecord)mHistory.get(0);
+ ActivityRecord p = mHistory.get(0);
if (target.taskAffinity != null
&& target.taskAffinity.equals(p.task.affinity)) {
// If the activity currently at the bottom has the
@@ -1727,7 +1730,7 @@ final public class ActivityStack {
int dstPos = 0;
ThumbnailHolder curThumbHolder = target.thumbHolder;
for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
- p = (ActivityRecord)mHistory.get(srcPos);
+ p = mHistory.get(srcPos);
if (p.finishing) {
continue;
}
@@ -1764,7 +1767,7 @@ final public class ActivityStack {
// like these are all in the reply chain.
replyChainEnd = targetI+1;
while (replyChainEnd < mHistory.size() &&
- ((ActivityRecord)mHistory.get(
+ (mHistory.get(
replyChainEnd)).task == task) {
replyChainEnd++;
}
@@ -1774,7 +1777,7 @@ final public class ActivityStack {
}
ActivityRecord p = null;
for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
- p = (ActivityRecord)mHistory.get(srcPos);
+ p = mHistory.get(srcPos);
if (p.finishing) {
continue;
}
@@ -1834,7 +1837,7 @@ final public class ActivityStack {
}
ActivityRecord p = null;
for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
- p = (ActivityRecord)mHistory.get(srcPos);
+ p = mHistory.get(srcPos);
if (p.finishing) {
continue;
}
@@ -1852,7 +1855,7 @@ final public class ActivityStack {
replyChainEnd = targetI;
}
for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
- ActivityRecord p = (ActivityRecord)mHistory.get(srcPos);
+ ActivityRecord p = mHistory.get(srcPos);
if (p.finishing) {
continue;
}
@@ -1881,7 +1884,7 @@ final public class ActivityStack {
// below so it remains singleTop.
if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
for (int j=lastReparentPos-1; j>=0; j--) {
- ActivityRecord p = (ActivityRecord)mHistory.get(j);
+ ActivityRecord p = mHistory.get(j);
if (p.finishing) {
continue;
}
@@ -1922,7 +1925,7 @@ final public class ActivityStack {
// First find the requested task.
while (i > 0) {
i--;
- ActivityRecord r = (ActivityRecord)mHistory.get(i);
+ ActivityRecord r = mHistory.get(i);
if (r.task.taskId == taskId) {
i++;
break;
@@ -1932,7 +1935,7 @@ final public class ActivityStack {
// Now clear it.
while (i > 0) {
i--;
- ActivityRecord r = (ActivityRecord)mHistory.get(i);
+ ActivityRecord r = mHistory.get(i);
if (r.finishing) {
continue;
}
@@ -1944,7 +1947,7 @@ final public class ActivityStack {
ActivityRecord ret = r;
while (i < (mHistory.size()-1)) {
i++;
- r = (ActivityRecord)mHistory.get(i);
+ r = mHistory.get(i);
if (r.task.taskId != taskId) {
break;
}
@@ -1980,6 +1983,28 @@ final public class ActivityStack {
}
/**
+ * Completely remove all activities associated with an existing
+ * task starting at a specified index.
+ */
+ private final void performClearTaskAtIndexLocked(int taskId, int i) {
+ while (i < (mHistory.size()-1)) {
+ ActivityRecord r = mHistory.get(i);
+ if (r.task.taskId != taskId) {
+ // Whoops hit the end.
+ return;
+ }
+ if (r.finishing) {
+ i++;
+ continue;
+ }
+ if (!finishActivityLocked(r, i, Activity.RESULT_CANCELED,
+ null, "clear")) {
+ i++;
+ }
+ }
+ }
+
+ /**
* Completely remove all activities associated with an existing task.
*/
private final void performClearTaskLocked(int taskId) {
@@ -1988,37 +2013,23 @@ final public class ActivityStack {
// First find the requested task.
while (i > 0) {
i--;
- ActivityRecord r = (ActivityRecord)mHistory.get(i);
+ ActivityRecord r = mHistory.get(i);
if (r.task.taskId == taskId) {
i++;
break;
}
}
- // Now clear it.
+ // Now find the start and clear it.
while (i > 0) {
i--;
- ActivityRecord r = (ActivityRecord)mHistory.get(i);
+ ActivityRecord r = mHistory.get(i);
if (r.finishing) {
continue;
}
if (r.task.taskId != taskId) {
// We hit the bottom. Now finish it all...
- while (i < (mHistory.size()-1)) {
- i++;
- r = (ActivityRecord)mHistory.get(i);
- if (r.task.taskId != taskId) {
- // Whoops hit the end.
- return;
- }
- if (r.finishing) {
- continue;
- }
- if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
- null, "clear")) {
- i--;
- }
- }
+ performClearTaskAtIndexLocked(taskId, i+1);
return;
}
}
@@ -2032,7 +2043,7 @@ final public class ActivityStack {
int i = mHistory.size();
while (i > 0) {
i--;
- ActivityRecord candidate = (ActivityRecord)mHistory.get(i);
+ ActivityRecord candidate = mHistory.get(i);
if (candidate.task.taskId != task) {
break;
}
@@ -2049,9 +2060,9 @@ final public class ActivityStack {
* brought to the front.
*/
private final ActivityRecord moveActivityToFrontLocked(int where) {
- ActivityRecord newTop = (ActivityRecord)mHistory.remove(where);
+ ActivityRecord newTop = mHistory.remove(where);
int top = mHistory.size();
- ActivityRecord oldTop = (ActivityRecord)mHistory.get(top-1);
+ ActivityRecord oldTop = mHistory.get(top-1);
mHistory.add(top, newTop);
oldTop.frontOfTask = false;
newTop.frontOfTask = true;
@@ -2094,7 +2105,7 @@ final public class ActivityStack {
if (DEBUG_RESULTS) Slog.v(
TAG, "Sending result to " + resultTo + " (index " + index + ")");
if (index >= 0) {
- sourceRecord = (ActivityRecord)mHistory.get(index);
+ sourceRecord = mHistory.get(index);
if (requestCode >= 0 && !sourceRecord.finishing) {
resultRecord = sourceRecord;
}
@@ -2576,7 +2587,7 @@ final public class ActivityStack {
// this case should never happen.
final int N = mHistory.size();
ActivityRecord prev =
- N > 0 ? (ActivityRecord)mHistory.get(N-1) : null;
+ N > 0 ? mHistory.get(N-1) : null;
r.setTask(prev != null
? prev.task
: new TaskRecord(mService.mCurTask, r.info, intent), null, true);
@@ -3021,7 +3032,7 @@ final public class ActivityStack {
// Get the activity record.
int index = indexOfTokenLocked(token);
if (index >= 0) {
- ActivityRecord r = (ActivityRecord)mHistory.get(index);
+ ActivityRecord r = mHistory.get(index);
if (fromTimeout) {
reportActivityLaunchedLocked(fromTimeout, r, -1, -1);
@@ -3153,12 +3164,12 @@ final public class ActivityStack {
if (index < 0) {
return false;
}
- ActivityRecord r = (ActivityRecord)mHistory.get(index);
+ ActivityRecord r = mHistory.get(index);
// Is this the last activity left?
boolean lastActivity = true;
for (int i=mHistory.size()-1; i>=0; i--) {
- ActivityRecord p = (ActivityRecord)mHistory.get(i);
+ ActivityRecord p = mHistory.get(i);
if (!p.finishing && p != r) {
lastActivity = false;
break;
@@ -3193,7 +3204,7 @@ final public class ActivityStack {
System.identityHashCode(r),
r.task.taskId, r.shortComponentName, reason);
if (index < (mHistory.size()-1)) {
- ActivityRecord next = (ActivityRecord)mHistory.get(index+1);
+ ActivityRecord next = mHistory.get(index+1);
if (next.task == r.task) {
if (r.frontOfTask) {
// The next activity is now the front of the task.
@@ -3249,7 +3260,7 @@ final public class ActivityStack {
if (mResumedActivity == r) {
boolean endTask = index <= 0
- || ((ActivityRecord)mHistory.get(index-1)).task != r.task;
+ || (mHistory.get(index-1)).task != r.task;
if (DEBUG_TRANSITION) Slog.v(TAG,
"Prepare close transition: finishing " + r);
mService.mWindowManager.prepareAppTransition(endTask
@@ -3391,6 +3402,7 @@ final public class ActivityStack {
// Get rid of any pending idle timeouts.
mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
+ mHandler.removeMessages(DESTROY_TIMEOUT_MSG, r);
}
private final void removeActivityFromHistoryLocked(ActivityRecord r) {
@@ -3516,7 +3528,7 @@ final public class ActivityStack {
int index = indexOfTokenLocked(token);
if (index >= 0) {
- ActivityRecord r = (ActivityRecord)mHistory.get(index);
+ ActivityRecord r = mHistory.get(index);
if (r.state == ActivityState.DESTROYING) {
final long origId = Binder.clearCallingIdentity();
removeActivityFromHistoryLocked(r);
@@ -3558,7 +3570,7 @@ final public class ActivityStack {
final void moveHomeToFrontLocked() {
TaskRecord homeTask = null;
for (int i=mHistory.size()-1; i>=0; i--) {
- ActivityRecord hr = (ActivityRecord)mHistory.get(i);
+ ActivityRecord hr = mHistory.get(i);
if (hr.isHomeActivity) {
homeTask = hr.task;
break;
@@ -3576,7 +3588,7 @@ final public class ActivityStack {
final int task = tr.taskId;
int top = mHistory.size()-1;
- if (top < 0 || ((ActivityRecord)mHistory.get(top)).task.taskId == task) {
+ if (top < 0 || (mHistory.get(top)).task.taskId == task) {
// nothing to do!
return;
}
@@ -3591,7 +3603,7 @@ final public class ActivityStack {
// Shift all activities with this task up to the top
// of the stack, keeping them in the same internal order.
while (pos >= 0) {
- ActivityRecord r = (ActivityRecord)mHistory.get(pos);
+ ActivityRecord r = mHistory.get(pos);
if (localLOGV) Slog.v(
TAG, "At " + pos + " ckp " + r.task + ": " + r);
if (r.task.taskId == task) {
@@ -3680,7 +3692,7 @@ final public class ActivityStack {
// Shift all activities with this task down to the bottom
// of the stack, keeping them in the same internal order.
while (pos < N) {
- ActivityRecord r = (ActivityRecord)mHistory.get(pos);
+ ActivityRecord r = mHistory.get(pos);
if (localLOGV) Slog.v(
TAG, "At " + pos + " ckp " + r.task + ": " + r);
if (r.task.taskId == task) {
@@ -3714,6 +3726,106 @@ final public class ActivityStack {
return true;
}
+ public ActivityManager.TaskThumbnails getTaskThumbnailsLocked(TaskRecord tr) {
+ TaskAccessInfo info = getTaskAccessInfoLocked(tr.taskId, true);
+ ActivityRecord resumed = mResumedActivity;
+ if (resumed != null && resumed.thumbHolder == tr) {
+ info.mainThumbnail = resumed.stack.screenshotActivities(resumed);
+ } else {
+ info.mainThumbnail = tr.lastThumbnail;
+ }
+ return info;
+ }
+
+ public ActivityRecord removeTaskActivitiesLocked(int taskId, int subTaskIndex) {
+ TaskAccessInfo info = getTaskAccessInfoLocked(taskId, false);
+ if (info.root == null) {
+ Slog.w(TAG, "removeTaskLocked: unknown taskId " + taskId);
+ return null;
+ }
+
+ if (subTaskIndex < 0) {
+ // Just remove the entire task.
+ performClearTaskAtIndexLocked(taskId, info.rootIndex);
+ return info.root;
+ }
+
+ if (subTaskIndex >= info.subtasks.size()) {
+ Slog.w(TAG, "removeTaskLocked: unknown subTaskIndex " + subTaskIndex);
+ return null;
+ }
+
+ // Remove all of this task's activies starting at the sub task.
+ TaskAccessInfo.SubTask subtask = info.subtasks.get(subTaskIndex);
+ performClearTaskAtIndexLocked(taskId, subtask.index);
+ return subtask.activity;
+ }
+
+ public TaskAccessInfo getTaskAccessInfoLocked(int taskId, boolean inclThumbs) {
+ ActivityRecord resumed = mResumedActivity;
+ final TaskAccessInfo thumbs = new TaskAccessInfo();
+ // How many different sub-thumbnails?
+ final int NA = mHistory.size();
+ int j = 0;
+ ThumbnailHolder holder = null;
+ while (j < NA) {
+ ActivityRecord ar = mHistory.get(j);
+ if (!ar.finishing && ar.task.taskId == taskId) {
+ holder = ar.thumbHolder;
+ break;
+ }
+ j++;
+ }
+
+ if (j >= NA) {
+ return thumbs;
+ }
+
+ thumbs.root = mHistory.get(j);
+ thumbs.rootIndex = j;
+
+ ArrayList<TaskAccessInfo.SubTask> subtasks = new ArrayList<TaskAccessInfo.SubTask>();
+ thumbs.subtasks = subtasks;
+ ActivityRecord lastActivity = null;
+ while (j < NA) {
+ ActivityRecord ar = mHistory.get(j);
+ j++;
+ if (ar.finishing) {
+ continue;
+ }
+ if (ar.task.taskId != taskId) {
+ break;
+ }
+ lastActivity = ar;
+ if (ar.thumbHolder != holder && holder != null) {
+ thumbs.numSubThumbbails++;
+ holder = ar.thumbHolder;
+ TaskAccessInfo.SubTask sub = new TaskAccessInfo.SubTask();
+ sub.thumbnail = holder.lastThumbnail;
+ sub.activity = ar;
+ sub.index = j-1;
+ subtasks.add(sub);
+ }
+ }
+ if (lastActivity != null && subtasks.size() > 0) {
+ if (resumed == lastActivity) {
+ TaskAccessInfo.SubTask sub = subtasks.get(subtasks.size()-1);
+ sub.thumbnail = lastActivity.stack.screenshotActivities(lastActivity);
+ }
+ }
+ if (thumbs.numSubThumbbails > 0) {
+ thumbs.retriever = new IThumbnailRetriever.Stub() {
+ public Bitmap getThumbnail(int index) {
+ if (index < 0 || index >= thumbs.subtasks.size()) {
+ return null;
+ }
+ return thumbs.subtasks.get(index).thumbnail;
+ }
+ };
+ }
+ return thumbs;
+ }
+
private final void logStartActivity(int tag, ActivityRecord r,
TaskRecord task) {
EventLog.writeEvent(tag,
diff --git a/services/java/com/android/server/am/BatteryStatsService.java b/services/java/com/android/server/am/BatteryStatsService.java
index 963a691bb727..b4fdc9f3c0ff 100644
--- a/services/java/com/android/server/am/BatteryStatsService.java
+++ b/services/java/com/android/server/am/BatteryStatsService.java
@@ -449,6 +449,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub {
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
boolean isCheckin = false;
+ boolean noOutput = false;
if (args != null) {
for (String arg : args) {
if ("--checkin".equals(arg)) {
@@ -457,10 +458,22 @@ public final class BatteryStatsService extends IBatteryStats.Stub {
synchronized (mStats) {
mStats.resetAllStatsLocked();
pw.println("Battery stats reset.");
+ noOutput = true;
}
+ } else if ("--write".equals(arg)) {
+ synchronized (mStats) {
+ mStats.writeSyncLocked();
+ pw.println("Battery stats written.");
+ noOutput = true;
+ }
+ } else {
+ pw.println("Unknown option: " + arg);
}
}
}
+ if (noOutput) {
+ return;
+ }
if (isCheckin) {
List<ApplicationInfo> apps = mContext.getPackageManager().getInstalledApplications(0);
synchronized (mStats) {
diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java
index 353ff6d2b5f6..e39c239f77e7 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -65,6 +65,7 @@ class ProcessRecord {
boolean foregroundServices; // Running any services that are foreground?
boolean bad; // True if disabled in the bad process list
boolean killedBackground; // True when proc has been killed due to too many bg
+ String waitingToKill; // Process is waiting to be killed when in the bg; reason
IBinder forcingToForeground;// Token that is forcing this process to be foreground
int adjSeq; // Sequence id for identifying oom_adj assignment cycles
int lruSeq; // Sequence id for identifying LRU update cycles
@@ -202,8 +203,9 @@ class ProcessRecord {
pw.print(" lastLowMemory=");
TimeUtils.formatDuration(lastLowMemory, now, pw);
pw.print(" reportLowMemory="); pw.println(reportLowMemory);
- if (killedBackground) {
- pw.print(prefix); pw.print("killedBackground="); pw.println(killedBackground);
+ if (killedBackground || waitingToKill != null) {
+ pw.print(prefix); pw.print("killedBackground="); pw.print(killedBackground);
+ pw.print(" waitingToKill="); pw.println(waitingToKill);
}
if (debugging || crashing || crashDialog != null || notResponding
|| anrDialog != null || bad) {
diff --git a/services/java/com/android/server/am/ServiceRecord.java b/services/java/com/android/server/am/ServiceRecord.java
index 1a617dd05620..da00c0c87ff4 100644
--- a/services/java/com/android/server/am/ServiceRecord.java
+++ b/services/java/com/android/server/am/ServiceRecord.java
@@ -84,7 +84,6 @@ class ServiceRecord extends Binder {
boolean startRequested; // someone explicitly called start?
boolean stopIfKilled; // last onStart() said to stop if service killed?
boolean callStart; // last onStart() has asked to alway be called on restart.
- int lastStartId; // identifier of most recent start request.
int executeNesting; // number of outstanding operations keeping foreground.
long executingStart; // start time of last execute request.
int crashCount; // number of times proc has crashed with service running
@@ -96,8 +95,11 @@ class ServiceRecord extends Binder {
String stringName; // caching of toString
+ private int lastStartId; // identifier of most recent start request.
+
static class StartItem {
final ServiceRecord sr;
+ final boolean taskRemoved;
final int id;
final Intent intent;
final int targetPermissionUid;
@@ -108,8 +110,10 @@ class ServiceRecord extends Binder {
String stringName; // caching of toString
- StartItem(ServiceRecord _sr, int _id, Intent _intent, int _targetPermissionUid) {
+ StartItem(ServiceRecord _sr, boolean _taskRemoved, int _id, Intent _intent,
+ int _targetPermissionUid) {
sr = _sr;
+ taskRemoved = _taskRemoved;
id = _id;
intent = _intent;
targetPermissionUid = _targetPermissionUid;
@@ -321,6 +325,18 @@ class ServiceRecord extends Binder {
return null;
}
+ public int getLastStartId() {
+ return lastStartId;
+ }
+
+ public int makeNextStartId() {
+ lastStartId++;
+ if (lastStartId < 1) {
+ lastStartId = 1;
+ }
+ return lastStartId;
+ }
+
public void postNotification() {
final int appUid = appInfo.uid;
final int appPid = app.pid;
diff --git a/services/java/com/android/server/am/TaskAccessInfo.java b/services/java/com/android/server/am/TaskAccessInfo.java
new file mode 100644
index 000000000000..5618c1aace68
--- /dev/null
+++ b/services/java/com/android/server/am/TaskAccessInfo.java
@@ -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.
+ */
+
+package com.android.server.am;
+
+import java.util.ArrayList;
+
+import android.app.ActivityManager.TaskThumbnails;
+import android.graphics.Bitmap;
+
+final class TaskAccessInfo extends TaskThumbnails {
+ final static class SubTask {
+ Bitmap thumbnail;
+ ActivityRecord activity;
+ int index;
+ }
+
+ public ActivityRecord root;
+ public int rootIndex;
+
+ public ArrayList<SubTask> subtasks;
+}
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index 585369632a09..9ff52339499b 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -49,8 +49,9 @@ import android.provider.Settings;
import android.util.Log;
import com.android.internal.telephony.Phone;
-import com.android.internal.util.HierarchicalState;
-import com.android.internal.util.HierarchicalStateMachine;
+import com.android.internal.util.IState;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -122,7 +123,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
// resampled each time we turn on tethering - used as cache for settings/config-val
private boolean mDunRequired; // configuration info - must use DUN apn on 3g
- private HierarchicalStateMachine mTetherMasterSM;
+ private StateMachine mTetherMasterSM;
private Notification mTetheredNotification;
@@ -668,7 +669,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
}
- class TetherInterfaceSM extends HierarchicalStateMachine {
+ class TetherInterfaceSM extends StateMachine {
// notification from the master SM that it's not in tether mode
static final int CMD_TETHER_MODE_DEAD = 1;
// request from the user that it wants to tether
@@ -694,13 +695,13 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
// the upstream connection has changed
static final int CMD_TETHER_CONNECTION_CHANGED = 12;
- private HierarchicalState mDefaultState;
+ private State mDefaultState;
- private HierarchicalState mInitialState;
- private HierarchicalState mStartingState;
- private HierarchicalState mTetheredState;
+ private State mInitialState;
+ private State mStartingState;
+ private State mTetheredState;
- private HierarchicalState mUnavailableState;
+ private State mUnavailableState;
private boolean mAvailable;
private boolean mTethered;
@@ -732,7 +733,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
public String toString() {
String res = new String();
res += mIfaceName + " - ";
- HierarchicalState current = getCurrentState();
+ IState current = getCurrentState();
if (current == mInitialState) res += "InitialState";
if (current == mStartingState) res += "StartingState";
if (current == mTetheredState) res += "TetheredState";
@@ -782,7 +783,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
return (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR);
}
- class InitialState extends HierarchicalState {
+ class InitialState extends State {
@Override
public void enter() {
setAvailable(true);
@@ -812,7 +813,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
}
}
- class StartingState extends HierarchicalState {
+ class StartingState extends State {
@Override
public void enter() {
setAvailable(false);
@@ -870,7 +871,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
}
}
- class TetheredState extends HierarchicalState {
+ class TetheredState extends State {
@Override
public void enter() {
IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
@@ -1034,7 +1035,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
}
}
- class UnavailableState extends HierarchicalState {
+ class UnavailableState extends State {
@Override
public void enter() {
setAvailable(false);
@@ -1064,7 +1065,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
}
- class TetherMasterSM extends HierarchicalStateMachine {
+ class TetherMasterSM extends StateMachine {
// an interface SM has requested Tethering
static final int CMD_TETHER_MODE_REQUESTED = 1;
// an interface SM has unrequested Tethering
@@ -1082,14 +1083,14 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
// We do not flush the old ones.
private int mSequenceNumber;
- private HierarchicalState mInitialState;
- private HierarchicalState mTetherModeAliveState;
+ private State mInitialState;
+ private State mTetherModeAliveState;
- private HierarchicalState mSetIpForwardingEnabledErrorState;
- private HierarchicalState mSetIpForwardingDisabledErrorState;
- private HierarchicalState mStartTetheringErrorState;
- private HierarchicalState mStopTetheringErrorState;
- private HierarchicalState mSetDnsForwardersErrorState;
+ private State mSetIpForwardingEnabledErrorState;
+ private State mSetIpForwardingDisabledErrorState;
+ private State mStartTetheringErrorState;
+ private State mStopTetheringErrorState;
+ private State mSetDnsForwardersErrorState;
private ArrayList mNotifyList;
@@ -1125,7 +1126,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
setInitialState(mInitialState);
}
- class TetherMasterUtilState extends HierarchicalState {
+ class TetherMasterUtilState extends State {
protected final static boolean TRY_TO_SETUP_MOBILE_CONNECTION = true;
protected final static boolean WAIT_FOR_NETWORK_TO_SETTLE = false;
@@ -1440,7 +1441,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
}
}
- class ErrorState extends HierarchicalState {
+ class ErrorState extends State {
int mErrorNotification;
@Override
public boolean processMessage(Message message) {
diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java
index 11dde752272c..16b55c3634a4 100644
--- a/services/java/com/android/server/pm/Settings.java
+++ b/services/java/com/android/server/pm/Settings.java
@@ -1336,6 +1336,19 @@ final class Settings {
}
mPendingPackages.clear();
+ /*
+ * Make sure all the updated system packages have their shared users
+ * associated with them.
+ */
+ final Iterator<PackageSetting> disabledIt = mDisabledSysPackages.values().iterator();
+ while (disabledIt.hasNext()) {
+ final PackageSetting disabledPs = disabledIt.next();
+ final Object id = getUserIdLPr(disabledPs.userId);
+ if (id != null && id instanceof SharedUserSetting) {
+ disabledPs.sharedUser = (SharedUserSetting) id;
+ }
+ }
+
readStoppedLPw();
mReadMessages.append("Read completed successfully: " + mPackages.size() + " packages, "
diff --git a/services/jni/com_android_server_AlarmManagerService.cpp b/services/jni/com_android_server_AlarmManagerService.cpp
index aa8c9b32c5bc..c9a702a515bb 100644
--- a/services/jni/com_android_server_AlarmManagerService.cpp
+++ b/services/jni/com_android_server_AlarmManagerService.cpp
@@ -2,16 +2,16 @@
**
** Copyright 2006, 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
+** 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
+** 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
+** 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.
*/
@@ -84,7 +84,7 @@ static void android_server_AlarmManagerService_set(JNIEnv* env, jobject obj, jin
struct timespec ts;
ts.tv_sec = seconds;
ts.tv_nsec = nanoseconds;
-
+
int result = ioctl(fd, ANDROID_ALARM_SET(type), &ts);
if (result < 0)
{
@@ -97,18 +97,18 @@ static jint android_server_AlarmManagerService_waitForAlarm(JNIEnv* env, jobject
{
#ifdef HAVE_ANDROID_OS
int result = 0;
-
+
do
{
result = ioctl(fd, ANDROID_ALARM_WAIT);
} while (result < 0 && errno == EINTR);
-
+
if (result < 0)
{
LOGE("Unable to wait on alarm: %s\n", strerror(errno));
return 0;
}
-
+
return result;
#endif
}
@@ -124,14 +124,6 @@ static JNINativeMethod sMethods[] = {
int register_android_server_AlarmManagerService(JNIEnv* env)
{
- jclass clazz = env->FindClass("com/android/server/AlarmManagerService");
-
- if (clazz == NULL)
- {
- LOGE("Can't find com/android/server/AlarmManagerService");
- return -1;
- }
-
return jniRegisterNativeMethods(env, "com/android/server/AlarmManagerService",
sMethods, NELEM(sMethods));
}
diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp
index ab2c125667ca..aaa305e91dc2 100644
--- a/services/jni/com_android_server_InputManager.cpp
+++ b/services/jni/com_android_server_InputManager.cpp
@@ -36,6 +36,8 @@
#include <input/InputManager.h>
#include <input/PointerController.h>
+#include <input/SpotController.h>
+#include <input/SpriteController.h>
#include <android_os_MessageQueue.h>
#include <android_view_KeyEvent.h>
@@ -163,6 +165,7 @@ public:
virtual nsecs_t getVirtualKeyQuietTime();
virtual void getExcludedDeviceNames(Vector<String8>& outExcludedDeviceNames);
virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId);
+ virtual sp<SpotControllerInterface> obtainSpotController(int32_t deviceId);
/* --- InputDispatcherPolicyInterface implementation --- */
@@ -213,12 +216,16 @@ private:
// System UI visibility.
int32_t systemUiVisibility;
+ // Sprite controller singleton, created on first use.
+ sp<SpriteController> spriteController;
+
// Pointer controller singleton, created and destroyed as needed.
wp<PointerController> pointerController;
} mLocked;
void updateInactivityFadeDelayLocked(const sp<PointerController>& controller);
void handleInterceptActions(jint wmActions, nsecs_t when, uint32_t& policyFlags);
+ void ensureSpriteControllerLocked();
// Power manager interactions.
bool isScreenOn();
@@ -419,18 +426,15 @@ sp<PointerControllerInterface> NativeInputManager::obtainPointerController(int32
sp<PointerController> controller = mLocked.pointerController.promote();
if (controller == NULL) {
- JNIEnv* env = jniEnv();
- jint layer = env->CallIntMethod(mCallbacksObj, gCallbacksClassInfo.getPointerLayer);
- if (checkAndClearExceptionFromCallback(env, "getPointerLayer")) {
- layer = -1;
- }
+ ensureSpriteControllerLocked();
- controller = new PointerController(mLooper, layer);
+ controller = new PointerController(mLooper, mLocked.spriteController);
mLocked.pointerController = controller;
controller->setDisplaySize(mLocked.displayWidth, mLocked.displayHeight);
controller->setDisplayOrientation(mLocked.displayOrientation);
+ JNIEnv* env = jniEnv();
jobject iconObj = env->CallObjectMethod(mCallbacksObj, gCallbacksClassInfo.getPointerIcon);
if (!checkAndClearExceptionFromCallback(env, "getPointerIcon") && iconObj) {
jfloat iconHotSpotX = env->GetFloatField(iconObj, gPointerIconClassInfo.hotSpotX);
@@ -451,6 +455,24 @@ sp<PointerControllerInterface> NativeInputManager::obtainPointerController(int32
return controller;
}
+sp<SpotControllerInterface> NativeInputManager::obtainSpotController(int32_t deviceId) {
+ AutoMutex _l(mLock);
+
+ ensureSpriteControllerLocked();
+ return new SpotController(mLooper, mLocked.spriteController);
+}
+
+void NativeInputManager::ensureSpriteControllerLocked() {
+ if (mLocked.spriteController == NULL) {
+ JNIEnv* env = jniEnv();
+ jint layer = env->CallIntMethod(mCallbacksObj, gCallbacksClassInfo.getPointerLayer);
+ if (checkAndClearExceptionFromCallback(env, "getPointerLayer")) {
+ layer = -1;
+ }
+ mLocked.spriteController = new SpriteController(mLooper, layer);
+ }
+}
+
void NativeInputManager::notifySwitch(nsecs_t when, int32_t switchCode,
int32_t switchValue, uint32_t policyFlags) {
#if DEBUG_INPUT_DISPATCHER_POLICY
diff --git a/services/jni/com_android_server_UsbService.cpp b/services/jni/com_android_server_UsbService.cpp
index 00ee7e30002c..9cd04f659da1 100644
--- a/services/jni/com_android_server_UsbService.cpp
+++ b/services/jni/com_android_server_UsbService.cpp
@@ -37,13 +37,6 @@
namespace android
{
-static struct file_descriptor_offsets_t
-{
- jclass mClass;
- jmethodID mConstructor;
- jfieldID mDescriptor;
-} gFileDescriptorOffsets;
-
static struct parcel_file_descriptor_offsets_t
{
jclass mClass;
@@ -167,11 +160,8 @@ static jobject android_server_UsbService_openDevice(JNIEnv *env, jobject thiz, j
int newFD = dup(fd);
usb_device_close(device);
- jobject fileDescriptor = env->NewObject(gFileDescriptorOffsets.mClass,
- gFileDescriptorOffsets.mConstructor);
- if (fileDescriptor != NULL) {
- env->SetIntField(fileDescriptor, gFileDescriptorOffsets.mDescriptor, newFD);
- } else {
+ jobject fileDescriptor = jniCreateFileDescriptor(env, newFD);
+ if (fileDescriptor == NULL) {
return NULL;
}
return env->NewObject(gParcelFileDescriptorOffsets.mClass,
@@ -221,11 +211,8 @@ static jobject android_server_UsbService_openAccessory(JNIEnv *env, jobject thiz
LOGE("could not open %s", DRIVER_NAME);
return NULL;
}
- jobject fileDescriptor = env->NewObject(gFileDescriptorOffsets.mClass,
- gFileDescriptorOffsets.mConstructor);
- if (fileDescriptor != NULL) {
- env->SetIntField(fileDescriptor, gFileDescriptorOffsets.mDescriptor, fd);
- } else {
+ jobject fileDescriptor = jniCreateFileDescriptor(env, fd);
+ if (fileDescriptor == NULL) {
return NULL;
}
return env->NewObject(gParcelFileDescriptorOffsets.mClass,
@@ -260,14 +247,6 @@ int register_android_server_UsbService(JNIEnv *env)
return -1;
}
- clazz = env->FindClass("java/io/FileDescriptor");
- LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor");
- gFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
- gFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "()V");
- gFileDescriptorOffsets.mDescriptor = env->GetFieldID(clazz, "descriptor", "I");
- LOG_FATAL_IF(gFileDescriptorOffsets.mDescriptor == NULL,
- "Unable to find descriptor field in java.io.FileDescriptor");
-
clazz = env->FindClass("android/os/ParcelFileDescriptor");
LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor");
gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 64cff965b12f..a774841ddb6f 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -93,7 +93,11 @@ int DisplayHardware::getWidth() const { return mWidth; }
int DisplayHardware::getHeight() const { return mHeight; }
PixelFormat DisplayHardware::getFormat() const { return mFormat; }
uint32_t DisplayHardware::getMaxTextureSize() const { return mMaxTextureSize; }
-uint32_t DisplayHardware::getMaxViewportDims() const { return mMaxViewportDims; }
+
+uint32_t DisplayHardware::getMaxViewportDims() const {
+ return mMaxViewportDims[0] < mMaxViewportDims[1] ?
+ mMaxViewportDims[0] : mMaxViewportDims[1];
+}
void DisplayHardware::init(uint32_t dpy)
{
@@ -228,7 +232,7 @@ void DisplayHardware::init(uint32_t dpy)
eglQueryString(display, EGL_EXTENSIONS));
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
- glGetIntegerv(GL_MAX_VIEWPORT_DIMS, &mMaxViewportDims);
+ glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
#ifdef EGL_ANDROID_swap_rectangle
@@ -260,7 +264,7 @@ void DisplayHardware::init(uint32_t dpy)
LOGI("version : %s", extensions.getVersion());
LOGI("extensions: %s", extensions.getExtension());
LOGI("GL_MAX_TEXTURE_SIZE = %d", mMaxTextureSize);
- LOGI("GL_MAX_VIEWPORT_DIMS = %d", mMaxViewportDims);
+ LOGI("GL_MAX_VIEWPORT_DIMS = %d x %d", mMaxViewportDims[0], mMaxViewportDims[1]);
LOGI("flags = %08x", mFlags);
// Unbind the context from this thread
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
index ee7a2af80e34..cdf89fd0badb 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -108,7 +108,7 @@ private:
PixelFormat mFormat;
uint32_t mFlags;
mutable uint32_t mPageFlipCount;
- GLint mMaxViewportDims;
+ GLint mMaxViewportDims[2];
GLint mMaxTextureSize;
HWComposer* mHwc;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ea283c606af8..2f3a144ec1f1 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2553,22 +2553,9 @@ sp<GraphicBuffer> GraphicBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h
LOGE("createGraphicBuffer: unable to create GraphicBuffer");
return 0;
}
- Mutex::Autolock _l(mLock);
- mBuffers.add(graphicBuffer);
return graphicBuffer;
}
-void GraphicBufferAlloc::freeAllGraphicBuffersExcept(int bufIdx) {
- Mutex::Autolock _l(mLock);
- if (bufIdx >= 0 && size_t(bufIdx) < mBuffers.size()) {
- sp<GraphicBuffer> b(mBuffers[bufIdx]);
- mBuffers.clear();
- mBuffers.add(b);
- } else {
- mBuffers.clear();
- }
-}
-
// ---------------------------------------------------------------------------
GraphicPlane::GraphicPlane()
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 0964848edf94..8d431574ac38 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -125,14 +125,8 @@ class GraphicBufferAlloc : public BnGraphicBufferAlloc
public:
GraphicBufferAlloc();
virtual ~GraphicBufferAlloc();
-
virtual sp<GraphicBuffer> createGraphicBuffer(uint32_t w, uint32_t h,
PixelFormat format, uint32_t usage);
- virtual void freeAllGraphicBuffersExcept(int bufIdx);
-
-private:
- Vector<sp<GraphicBuffer> > mBuffers;
- Mutex mLock;
};
// ---------------------------------------------------------------------------
diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java
index 0c47e860f0f0..791fbfdd08a3 100644
--- a/telephony/java/com/android/internal/telephony/DataConnection.java
+++ b/telephony/java/com/android/internal/telephony/DataConnection.java
@@ -17,8 +17,8 @@
package com.android.internal.telephony;
-import com.android.internal.util.HierarchicalState;
-import com.android.internal.util.HierarchicalStateMachine;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
import android.net.LinkAddress;
import android.net.LinkCapabilities;
@@ -37,7 +37,7 @@ import java.util.HashMap;
/**
* {@hide}
*
- * DataConnection HierarchicalStateMachine.
+ * DataConnection StateMachine.
*
* This is an abstract base class for representing a single data connection.
* Instances of this class such as <code>CdmaDataConnection</code> and
@@ -55,7 +55,7 @@ import java.util.HashMap;
*
* The other public methods are provided for debugging.
*/
-public abstract class DataConnection extends HierarchicalStateMachine {
+public abstract class DataConnection extends StateMachine {
protected static final boolean DBG = true;
protected static Object mCountLock = new Object();
@@ -484,17 +484,17 @@ public abstract class DataConnection extends HierarchicalStateMachine {
/**
* The parent state for all other states.
*/
- private class DcDefaultState extends HierarchicalState {
+ private class DcDefaultState extends State {
@Override
- protected void enter() {
+ public void enter() {
phone.mCM.registerForRilConnected(getHandler(), EVENT_RIL_CONNECTED, null);
}
@Override
- protected void exit() {
+ public void exit() {
phone.mCM.unregisterForRilConnected(getHandler());
}
@Override
- protected boolean processMessage(Message msg) {
+ public boolean processMessage(Message msg) {
AsyncResult ar;
switch (msg.what) {
@@ -547,7 +547,7 @@ public abstract class DataConnection extends HierarchicalStateMachine {
/**
* The state machine is inactive and expects a EVENT_CONNECT.
*/
- private class DcInactiveState extends HierarchicalState {
+ private class DcInactiveState extends State {
private ConnectionParams mConnectionParams = null;
private FailCause mFailCause = null;
private DisconnectParams mDisconnectParams = null;
@@ -563,7 +563,8 @@ public abstract class DataConnection extends HierarchicalStateMachine {
mDisconnectParams = dp;
}
- @Override protected void enter() {
+ @Override
+ public void enter() {
mTag += 1;
/**
@@ -583,14 +584,16 @@ public abstract class DataConnection extends HierarchicalStateMachine {
}
}
- @Override protected void exit() {
+ @Override
+ public void exit() {
// clear notifications
mConnectionParams = null;
mFailCause = null;
mDisconnectParams = null;
}
- @Override protected boolean processMessage(Message msg) {
+ @Override
+ public boolean processMessage(Message msg) {
boolean retVal;
switch (msg.what) {
@@ -626,8 +629,9 @@ public abstract class DataConnection extends HierarchicalStateMachine {
/**
* The state machine is activating a connection.
*/
- private class DcActivatingState extends HierarchicalState {
- @Override protected boolean processMessage(Message msg) {
+ private class DcActivatingState extends State {
+ @Override
+ public boolean processMessage(Message msg) {
boolean retVal;
AsyncResult ar;
ConnectionParams cp;
@@ -722,7 +726,7 @@ public abstract class DataConnection extends HierarchicalStateMachine {
/**
* The state machine is connected, expecting an EVENT_DISCONNECT.
*/
- private class DcActiveState extends HierarchicalState {
+ private class DcActiveState extends State {
private ConnectionParams mConnectionParams = null;
private FailCause mFailCause = null;
@@ -746,13 +750,15 @@ public abstract class DataConnection extends HierarchicalStateMachine {
}
}
- @Override protected void exit() {
+ @Override
+ public void exit() {
// clear notifications
mConnectionParams = null;
mFailCause = null;
}
- @Override protected boolean processMessage(Message msg) {
+ @Override
+ public boolean processMessage(Message msg) {
boolean retVal;
switch (msg.what) {
@@ -778,8 +784,9 @@ public abstract class DataConnection extends HierarchicalStateMachine {
/**
* The state machine is disconnecting.
*/
- private class DcDisconnectingState extends HierarchicalState {
- @Override protected boolean processMessage(Message msg) {
+ private class DcDisconnectingState extends State {
+ @Override
+ public boolean processMessage(Message msg) {
boolean retVal;
switch (msg.what) {
@@ -812,8 +819,9 @@ public abstract class DataConnection extends HierarchicalStateMachine {
/**
* The state machine is disconnecting after an creating a connection.
*/
- private class DcDisconnectionErrorCreatingConnection extends HierarchicalState {
- @Override protected boolean processMessage(Message msg) {
+ private class DcDisconnectionErrorCreatingConnection extends State {
+ @Override
+ public boolean processMessage(Message msg) {
boolean retVal;
switch (msg.what) {
diff --git a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
index a2c08edb97ad..3280c442e65f 100644
--- a/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/DataConnectionTracker.java
@@ -97,7 +97,6 @@ public abstract class DataConnectionTracker extends Handler {
protected static final int EVENT_TRY_SETUP_DATA = 5;
protected static final int EVENT_DATA_STATE_CHANGED = 6;
protected static final int EVENT_POLL_PDP = 7;
- protected static final int EVENT_GET_PDP_LIST_COMPLETE = 11;
protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 12;
protected static final int EVENT_VOICE_CALL_STARTED = 14;
protected static final int EVENT_VOICE_CALL_ENDED = 15;
@@ -408,7 +407,7 @@ public abstract class DataConnectionTracker extends Handler {
}
/** TODO: See if we can remove */
- public String getActiveApnString() {
+ public String getActiveApnString(String apnType) {
String result = null;
if (mActiveApn != null) {
result = mActiveApn.apn;
@@ -466,6 +465,8 @@ public abstract class DataConnectionTracker extends Handler {
protected abstract void onVoiceCallEnded();
protected abstract void onCleanUpConnection(boolean tearDown, int apnId, String reason);
protected abstract void onCleanUpAllConnections(String cause);
+ protected abstract boolean isDataPossible();
+ protected abstract boolean isDataPossible(String apnType);
@Override
public void handleMessage(Message msg) {
@@ -719,29 +720,6 @@ public abstract class DataConnectionTracker extends Handler {
notifyOffApnsOfAvailability(reason, isDataPossible());
}
- /**
- * The only circumstances under which we report that data connectivity is not
- * possible are
- * <ul>
- * <li>Data is disallowed (roaming, power state, voice call, etc).</li>
- * <li>The current data state is {@code DISCONNECTED} for a reason other than
- * having explicitly disabled connectivity. In other words, data is not available
- * because the phone is out of coverage or some like reason.</li>
- * </ul>
- * @return {@code true} if data connectivity is possible, {@code false} otherwise.
- */
- protected boolean isDataPossible() {
- boolean dataAllowed = isDataAllowed();
- boolean anyDataEnabled = getAnyDataEnabled();
- boolean possible = (dataAllowed
- && !(anyDataEnabled && (mState == State.FAILED || mState == State.IDLE)));
- if (!possible && DBG) {
- log("isDataPossible() " + possible + ", dataAllowed=" + dataAllowed +
- " anyDataEnabled=" + anyDataEnabled + " dataState=" + mState);
- }
- return possible;
- }
-
public boolean isApnTypeEnabled(String apnType) {
if (apnType == null) {
return false;
diff --git a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
index 83db3d1eae8f..910905aa4543 100644
--- a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
+++ b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
@@ -114,8 +114,8 @@ public class DefaultPhoneNotifier implements PhoneNotifier {
try {
mRegistry.notifyDataConnection(
convertDataState(state),
- sender.isDataConnectivityPossible(), reason,
- sender.getActiveApnHost(),
+ sender.isDataConnectivityPossible(apnType), reason,
+ sender.getActiveApnHost(apnType),
apnType,
linkProperties,
linkCapabilities,
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index 9f16d31add76..56be570813de 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -159,8 +159,8 @@ public interface Phone {
static final String REASON_ROAMING_OFF = "roamingOff";
static final String REASON_DATA_DISABLED = "dataDisabled";
static final String REASON_DATA_ENABLED = "dataEnabled";
- static final String REASON_GPRS_ATTACHED = "gprsAttached";
- static final String REASON_GPRS_DETACHED = "gprsDetached";
+ static final String REASON_DATA_ATTACHED = "dataAttached";
+ static final String REASON_DATA_DETACHED = "dataDetached";
static final String REASON_CDMA_DATA_ATTACHED = "cdmaDataAttached";
static final String REASON_CDMA_DATA_DETACHED = "cdmaDataDetached";
static final String REASON_APN_CHANGED = "apnChanged";
@@ -333,7 +333,7 @@ public interface Phone {
* Returns string for the active APN host.
* @return type as a string or null if none.
*/
- String getActiveApnHost();
+ String getActiveApnHost(String apnType);
/**
* Return the LinkProperties for the named apn or null if not available
@@ -1375,6 +1375,11 @@ public interface Phone {
boolean isDataConnectivityPossible();
/**
+ * Report on whether data connectivity is allowed for an APN.
+ */
+ boolean isDataConnectivityPossible(String apnType);
+
+ /**
* Retrieves the unique device ID, e.g., IMEI for GSM phones and MEID for CDMA phones.
*/
String getDeviceId();
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index 3224995c7d43..5a77da7cc6ac 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -977,8 +977,8 @@ public abstract class PhoneBase extends Handler implements Phone {
return mDataConnectionTracker.getActiveApnTypes();
}
- public String getActiveApnHost() {
- return mDataConnectionTracker.getActiveApnString();
+ public String getActiveApnHost(String apnType) {
+ return mDataConnectionTracker.getActiveApnString(apnType);
}
public LinkProperties getLinkProperties(String apnType) {
@@ -1001,6 +1001,11 @@ public abstract class PhoneBase extends Handler implements Phone {
return ((mDataConnectionTracker != null) && (mDataConnectionTracker.isDataPossible()));
}
+ public boolean isDataConnectivityPossible(String apnType) {
+ return ((mDataConnectionTracker != null) &&
+ (mDataConnectionTracker.isDataPossible(apnType)));
+ }
+
/**
* simulateDataConnection
*
diff --git a/telephony/java/com/android/internal/telephony/PhoneFactory.java b/telephony/java/com/android/internal/telephony/PhoneFactory.java
index ab0bb63f17b4..a04623f99ac1 100644
--- a/telephony/java/com/android/internal/telephony/PhoneFactory.java
+++ b/telephony/java/com/android/internal/telephony/PhoneFactory.java
@@ -106,10 +106,32 @@ public class PhoneFactory {
Settings.Secure.PREFERRED_NETWORK_MODE, preferredNetworkMode);
Log.i(LOG_TAG, "Network Mode set to " + Integer.toString(networkMode));
- //Get preferredNetworkMode from Settings.System
- int cdmaSubscription = Settings.Secure.getInt(context.getContentResolver(),
- Settings.Secure.PREFERRED_CDMA_SUBSCRIPTION, preferredCdmaSubscription);
- Log.i(LOG_TAG, "Cdma Subscription set to " + Integer.toString(cdmaSubscription));
+ // Get cdmaSubscription
+ // TODO: Change when the ril will provides a way to know at runtime
+ // the configuration, bug 4202572. And the ril issues the
+ // RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED, bug 4295439.
+ int cdmaSubscription;
+ int lteOnCdma = SystemProperties.getInt(
+ TelephonyProperties.PROPERTY_NETWORK_LTE_ON_CDMA, -1);
+ switch (lteOnCdma) {
+ case 0:
+ cdmaSubscription = RILConstants.SUBSCRIPTION_FROM_NV;
+ Log.i(LOG_TAG, "lteOnCdma is 0 use SUBSCRIPTION_FROM_NV");
+ break;
+ case 1:
+ cdmaSubscription = RILConstants.SUBSCRIPTION_FROM_RUIM;
+ Log.i(LOG_TAG, "lteOnCdma is 1 use SUBSCRIPTION_FROM_RUIM");
+ break;
+ case -1:
+ default:
+ //Get cdmaSubscription mode from Settings.System
+ cdmaSubscription = Settings.Secure.getInt(context.getContentResolver(),
+ Settings.Secure.PREFERRED_CDMA_SUBSCRIPTION,
+ preferredCdmaSubscription);
+ Log.i(LOG_TAG, "lteOnCdma not set, using PREFERRED_CDMA_SUBSCRIPTION");
+ break;
+ }
+ Log.i(LOG_TAG, "Cdma Subscription set to " + cdmaSubscription);
//reads the system properties and makes commandsinterface
sCommandsInterface = new RIL(context, networkMode, cdmaSubscription);
@@ -156,7 +178,10 @@ public class PhoneFactory {
case RILConstants.NETWORK_MODE_GSM_UMTS:
return Phone.PHONE_TYPE_GSM;
+ // Use CDMA Phone for the global mode including CDMA
case RILConstants.NETWORK_MODE_GLOBAL:
+ case RILConstants.NETWORK_MODE_LTE_CDMA_EVDO:
+ case RILConstants.NETWORK_MODE_LTE_CMDA_EVDO_GSM_WCDMA:
return Phone.PHONE_TYPE_CDMA;
case RILConstants.NETWORK_MODE_LTE_ONLY:
diff --git a/telephony/java/com/android/internal/telephony/PhoneProxy.java b/telephony/java/com/android/internal/telephony/PhoneProxy.java
index 49497b440772..5e506b35f63a 100644
--- a/telephony/java/com/android/internal/telephony/PhoneProxy.java
+++ b/telephony/java/com/android/internal/telephony/PhoneProxy.java
@@ -208,8 +208,8 @@ public class PhoneProxy extends Handler implements Phone {
return mActivePhone.getActiveApnTypes();
}
- public String getActiveApnHost() {
- return mActivePhone.getActiveApnHost();
+ public String getActiveApnHost(String apnType) {
+ return mActivePhone.getActiveApnHost(apnType);
}
public LinkProperties getLinkProperties(String apnType) {
@@ -661,6 +661,10 @@ public class PhoneProxy extends Handler implements Phone {
return mActivePhone.isDataConnectivityPossible();
}
+ public boolean isDataConnectivityPossible(String apnType) {
+ return mActivePhone.isDataConnectivityPossible(apnType);
+ }
+
public String getDeviceId() {
return mActivePhone.getDeviceId();
}
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index 863daefad636..c052e5142351 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -234,9 +234,6 @@ public final class RIL extends BaseCommands implements CommandsInterface {
// WAKE_LOCK_TIMEOUT occurs.
int mRequestMessagesWaiting;
- // Is this the first radio state change?
- private boolean mInitialRadioStateChange = true;
-
//I'd rather this be LinkedList or something
ArrayList<RILRequest> mRequestsList = new ArrayList<RILRequest>();
@@ -613,11 +610,6 @@ public final class RIL extends BaseCommands implements CommandsInterface {
//***** Constructors
- public
- RIL(Context context) {
- this(context, RILConstants.PREFERRED_NETWORK_MODE,
- RILConstants.PREFERRED_CDMA_SUBSCRIPTION);
- }
public RIL(Context context, int networkMode, int cdmaSubscription) {
super(context);
@@ -913,10 +905,7 @@ public final class RIL extends BaseCommands implements CommandsInterface {
getIMSI(Message result) {
RILRequest rr = RILRequest.obtain(RIL_REQUEST_GET_IMSI, result);
- if (RILJ_LOGD) riljLog(rr.serialString() +
- "> getIMSI:RIL_REQUEST_GET_IMSI " +
- RIL_REQUEST_GET_IMSI +
- " " + requestToString(rr.mRequest));
+ if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
send(rr);
}
@@ -1394,24 +1383,6 @@ public final class RIL extends BaseCommands implements CommandsInterface {
public void
setRadioPower(boolean on, Message result) {
- //if radio is OFF set preferred NW type and cmda subscription
- if(mInitialRadioStateChange) {
- synchronized (mStateMonitor) {
- if (!mState.isOn()) {
- setPreferredNetworkType(mNetworkMode, null);
-
- RILRequest rrCs = RILRequest.obtain(
- RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE, null);
- rrCs.mp.writeInt(1);
- rrCs.mp.writeInt(mCdmaSubscription);
- if (RILJ_LOGD) {
- riljLog(rrCs.serialString() + "> "
- + requestToString(rrCs.mRequest) + " : " + mCdmaSubscription);
- }
- send(rrCs);
- }
- }
- }
RILRequest rr = RILRequest.obtain(RIL_REQUEST_RADIO_POWER, result);
rr.mp.writeInt(1);
@@ -2058,26 +2029,7 @@ public final class RIL extends BaseCommands implements CommandsInterface {
}
private void switchToRadioState(RadioState newState) {
-
- if (mInitialRadioStateChange) {
- if (newState.isOn()) {
- /* If this is our first notification, make sure the radio
- * is powered off. This gets the radio into a known state,
- * since it's possible for the phone proc to have restarted
- * (eg, if it or the runtime crashed) without the RIL
- * and/or radio knowing.
- */
- if (RILJ_LOGD) Log.d(LOG_TAG, "Radio ON @ init; reset to OFF");
- setRadioPower(false, null);
- } else {
- if (RILJ_LOGD) Log.d(LOG_TAG, "Radio OFF @ init");
- setRadioState(newState);
- setPreferredNetworkType(mNetworkMode, null);
- }
- mInitialRadioStateChange = false;
- } else {
- setRadioState(newState);
- }
+ setRadioState(newState);
}
/**
@@ -2467,7 +2419,7 @@ public final class RIL extends BaseCommands implements CommandsInterface {
case RIL_UNSOL_OEM_HOOK_RAW: ret = responseRaw(p); break;
case RIL_UNSOL_RINGBACK_TONE: ret = responseInts(p); break;
case RIL_UNSOL_RESEND_INCALL_MUTE: ret = responseVoid(p); break;
- case RIL_UNSOL_CDMA_SUBSCRIPTION_CHANGED: ret = responseInts(p); break;
+ case RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED: ret = responseInts(p); break;
case RIL_UNSOl_CDMA_PRL_CHANGED: ret = responseInts(p); break;
case RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE: ret = responseVoid(p); break;
case RIL_UNSOL_RIL_CONNECTED: ret = responseInts(p); break;
@@ -2775,7 +2727,7 @@ public final class RIL extends BaseCommands implements CommandsInterface {
}
break;
- case RIL_UNSOL_CDMA_SUBSCRIPTION_CHANGED:
+ case RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED:
if (RILJ_LOGD) unsljLogRet(response, ret);
if (mCdmaSubscriptionChangedRegistrants != null) {
@@ -2804,6 +2756,11 @@ public final class RIL extends BaseCommands implements CommandsInterface {
case RIL_UNSOL_RIL_CONNECTED: {
if (RILJ_LOGD) unsljLogRet(response, ret);
+
+ // Initial conditions
+ setRadioPower(false, null);
+ setPreferredNetworkType(mNetworkMode, null);
+ setCdmaSubscriptionSource(mCdmaSubscription, null);
notifyRegistrantsRilConnectionChanged(((int[])ret)[0]);
break;
}
@@ -3554,7 +3511,7 @@ public final class RIL extends BaseCommands implements CommandsInterface {
case RIL_UNSOL_OEM_HOOK_RAW: return "UNSOL_OEM_HOOK_RAW";
case RIL_UNSOL_RINGBACK_TONE: return "UNSOL_RINGBACK_TONG";
case RIL_UNSOL_RESEND_INCALL_MUTE: return "UNSOL_RESEND_INCALL_MUTE";
- case RIL_UNSOL_CDMA_SUBSCRIPTION_CHANGED: return "CDMA_SUBSCRIPTION_CHANGED";
+ case RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED: return "CDMA_SUBSCRIPTION_SOURCE_CHANGED";
case RIL_UNSOl_CDMA_PRL_CHANGED: return "UNSOL_CDMA_PRL_CHANGED";
case RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE: return "UNSOL_EXIT_EMERGENCY_CALLBACK_MODE";
case RIL_UNSOL_RIL_CONNECTED: return "UNSOL_RIL_CONNECTED";
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 73dfdc0bdb7d..2a27926459df 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -286,7 +286,7 @@ cat include/telephony/ril.h | \
int RIL_UNSOL_OEM_HOOK_RAW = 1028;
int RIL_UNSOL_RINGBACK_TONE = 1029;
int RIL_UNSOL_RESEND_INCALL_MUTE = 1030;
- int RIL_UNSOL_CDMA_SUBSCRIPTION_CHANGED = 1031;
+ int RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED = 1031;
int RIL_UNSOl_CDMA_PRL_CHANGED = 1032;
int RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE = 1033;
int RIL_UNSOL_RIL_CONNECTED = 1034;
diff --git a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
index e58ccfc64cf6..695805c682d5 100644
--- a/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/telephony/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -398,7 +398,7 @@ public abstract class ServiceStateTracker extends Handler {
synchronized (this) {
if (!mPendingRadioPowerOffAfterDataOff) {
if (dcTracker.isAnyActiveDataConnections()) {
- dcTracker.cleanUpAllConnections(null);
+ dcTracker.cleanUpAllConnections(Phone.REASON_RADIO_TURNED_OFF);
Message msg = Message.obtain(this);
msg.what = EVENT_SET_RADIO_POWER_OFF;
msg.arg1 = ++mPendingRadioPowerOffAfterDataOffTag;
@@ -410,7 +410,7 @@ public abstract class ServiceStateTracker extends Handler {
hangupAndPowerOff();
}
} else {
- dcTracker.cleanUpAllConnections(null);
+ dcTracker.cleanUpAllConnections(Phone.REASON_RADIO_TURNED_OFF);
if (DBG) log("Data disconnected, turn off radio right away.");
hangupAndPowerOff();
}
diff --git a/telephony/java/com/android/internal/telephony/cat/RilMessageDecoder.java b/telephony/java/com/android/internal/telephony/cat/RilMessageDecoder.java
index a197c9a5685a..2a1f508e4407 100644
--- a/telephony/java/com/android/internal/telephony/cat/RilMessageDecoder.java
+++ b/telephony/java/com/android/internal/telephony/cat/RilMessageDecoder.java
@@ -20,15 +20,15 @@ import com.android.internal.telephony.IccFileHandler;
import com.android.internal.telephony.IccUtils;
import android.os.Handler;
-import com.android.internal.util.HierarchicalState;
-import com.android.internal.util.HierarchicalStateMachine;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
import android.os.Message;
/**
* Class used for queuing raw ril messages, decoding them into CommanParams
* objects and sending the result back to the CAT Service.
*/
-class RilMessageDecoder extends HierarchicalStateMachine {
+class RilMessageDecoder extends StateMachine {
// constants
private static final int CMD_START = 1;
@@ -101,8 +101,9 @@ class RilMessageDecoder extends HierarchicalStateMachine {
mCmdParamsFactory = CommandParamsFactory.getInstance(this, fh);
}
- private class StateStart extends HierarchicalState {
- @Override protected boolean processMessage(Message msg) {
+ private class StateStart extends State {
+ @Override
+ public boolean processMessage(Message msg) {
if (msg.what == CMD_START) {
if (decodeMessageParams((RilMessage)msg.obj)) {
transitionTo(mStateCmdParamsReady);
@@ -115,8 +116,9 @@ class RilMessageDecoder extends HierarchicalStateMachine {
}
}
- private class StateCmdParamsReady extends HierarchicalState {
- @Override protected boolean processMessage(Message msg) {
+ private class StateCmdParamsReady extends State {
+ @Override
+ public boolean processMessage(Message msg) {
if (msg.what == CMD_PARAMS_READY) {
mCurrentRilMessage.mResCode = ResultCode.fromInt(msg.arg1);
mCurrentRilMessage.mData = msg.obj;
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
index 1cb1118871f9..e45141a28166 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java
@@ -164,10 +164,7 @@ public class CDMALTEPhone extends CDMAPhone {
}
public String getActiveApn(String apnType) {
- if (mDataConnectionTracker instanceof CdmaDataConnectionTracker)
- return mDataConnectionTracker.getActiveApnString();
-
- return ((GsmDataConnectionTracker)mDataConnectionTracker).getActiveApnString(apnType);
+ return mDataConnectionTracker.getActiveApnString(apnType);
}
protected void log(String s) {
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index 2637507f7991..dc8501709cce 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -215,6 +215,36 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
return allowed;
}
+ /**
+ * The only circumstances under which we report that data connectivity is not
+ * possible are
+ * <ul>
+ * <li>Data is disallowed (roaming, power state, voice call, etc).</li>
+ * <li>The current data state is {@code DISCONNECTED} for a reason other than
+ * having explicitly disabled connectivity. In other words, data is not available
+ * because the phone is out of coverage or some like reason.</li>
+ * </ul>
+ * @return {@code true} if data connectivity is possible, {@code false} otherwise.
+ */
+ @Override
+ protected boolean isDataPossible() {
+ boolean dataAllowed = isDataAllowed();
+ boolean anyDataEnabled = getAnyDataEnabled();
+ boolean possible = (dataAllowed
+ && !(anyDataEnabled && (mState == State.FAILED || mState == State.IDLE)));
+ if (!possible && DBG) {
+ log("isDataPossible() " + possible + ", dataAllowed=" + dataAllowed +
+ " anyDataEnabled=" + anyDataEnabled + " dataState=" + mState);
+ }
+ return possible;
+ }
+
+ @Override
+ protected boolean isDataPossible(String apnType) {
+ return isDataPossible();
+ }
+
+
private boolean trySetupData(String reason) {
if (DBG) log("***trySetupData due to " + (reason == null ? "(unspecified)" : reason));
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index 24c31c741945..fc1d536c20f2 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -221,7 +221,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
@Override
protected boolean isDataPossible() {
boolean possible = (isDataAllowed()
- && getAnyDataEnabled() && (getOverallState() == State.CONNECTED));
+ && !(getAnyDataEnabled() && (getOverallState() == State.FAILED)));
if (!possible && DBG && isDataAllowed()) {
log("Data not possible. No coverage: dataState = " + getOverallState());
}
@@ -229,6 +229,28 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
}
@Override
+ protected boolean isDataPossible(String apnType) {
+ ApnContext apnContext = mApnContexts.get(apnType);
+ if (apnContext == null) {
+ return false;
+ }
+ boolean apnContextIsEnabled = apnContext.isEnabled();
+ State apnContextState = apnContext.getState();
+ boolean apnTypePossible = !(apnContextIsEnabled &&
+ (apnContextState == State.FAILED));
+ boolean dataAllowed = isDataAllowed();
+ boolean possible = dataAllowed && apnTypePossible;
+
+ if (DBG) {
+ log(String.format("isDataPossible(%s): possible=%b isDataAllowed=%b " +
+ "apnTypePossible=%b apnContextisEnabled=%b apnContextState()=%s",
+ apnType, possible, dataAllowed, apnTypePossible,
+ apnContextIsEnabled, apnContextState));
+ }
+ return possible;
+ }
+
+ @Override
protected void finalize() {
if(DBG) log("finalize");
}
@@ -336,21 +358,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
}
@Override
- /**
- * Return DEFAULT APN due to the limit of the interface
- */
- public String getActiveApnString() {
- if (DBG) log( "get default active apn string");
- ApnContext defaultApnContext = mApnContexts.get(Phone.APN_TYPE_DEFAULT);
- if (defaultApnContext != null) {
- ApnSetting apnSetting = defaultApnContext.getApnSetting();
- if (apnSetting != null) {
- return apnSetting.apn;
- }
- }
- return null;
- }
-
// Return active apn of specific apn type
public String getActiveApnString(String apnType) {
if (DBG) log( "get active apn string for type:" + apnType);
@@ -365,6 +372,15 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
}
@Override
+ public boolean isApnTypeEnabled(String apnType) {
+ ApnContext apnContext = mApnContexts.get(apnType);
+ if (apnContext == null) {
+ return false;
+ }
+ return apnContext.isEnabled();
+ }
+
+ @Override
protected void setState(State s) {
if (DBG) log("setState should not be used in GSM" + s);
}
@@ -382,23 +398,43 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
// Return state of overall
public State getOverallState() {
boolean isConnecting = false;
+ boolean isFailed = true; // All enabled Apns should be FAILED.
+ boolean isAnyEnabled = false;
+
for (ApnContext apnContext : mApnContexts.values()) {
- if (apnContext.getState() == State.CONNECTED ||
- apnContext.getState() == State.DISCONNECTING) {
- if (DBG) log("overall state is CONNECTED");
- return State.CONNECTED;
- }
- else if (apnContext.getState() == State.CONNECTING
- || apnContext.getState() == State.INITING) {
- isConnecting = true;
+ if (apnContext.isEnabled()) {
+ isAnyEnabled = true;
+ switch (apnContext.getState()) {
+ case CONNECTED:
+ case DISCONNECTING:
+ if (DBG) log("overall state is CONNECTED");
+ return State.CONNECTED;
+ case CONNECTING:
+ case INITING:
+ isConnecting = true;
+ isFailed = false;
+ break;
+ case IDLE:
+ case SCANNING:
+ isFailed = false;
+ break;
+ }
}
}
+
+ if (!isAnyEnabled) { // Nothing enabled. return IDLE.
+ return State.IDLE;
+ }
+
if (isConnecting) {
if (DBG) log( "overall state is CONNECTING");
return State.CONNECTING;
- } else {
+ } else if (!isFailed) {
if (DBG) log( "overall state is IDLE");
return State.IDLE;
+ } else {
+ if (DBG) log( "overall state is FAILED");
+ return State.FAILED;
}
}
@@ -469,9 +505,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
ApnContext apnContext = mApnContexts.get(type);
if (apnContext != null) {
- apnContext.setPendingAction(ApnContext.PENDING_ACTION_APN_DISABLE);
-
if (apnContext.getState() != State.IDLE && apnContext.getState() != State.FAILED) {
+ apnContext.setPendingAction(ApnContext.PENDING_ACTION_APN_DISABLE);
Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION);
msg.arg1 = 1; // tearDown is true;
// TODO - don't set things on apnContext from public functions.
@@ -483,6 +518,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
return Phone.APN_REQUEST_STARTED;
} else {
if (DBG) log("return APN_ALREADY_INACTIVE");
+ apnContext.setEnabled(false);
return Phone.APN_ALREADY_INACTIVE;
}
@@ -509,16 +545,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
return false;
}
- protected boolean isEnabled(String apnType) {
- ApnContext apnContext = mApnContexts.get(apnType);
- if (apnContext == null) return false;
- if (apnContext.getState() == State.DISCONNECTING
- && apnContext.getPendingAction() == ApnContext.PENDING_ACTION_APN_DISABLE) {
- return false;
- }
- return true;
- }
-
/**
* Report on whether data connectivity is enabled for any APN.
* @return {@code false} if data connectivity has been explicitly disabled,
@@ -556,24 +582,16 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
* when GPRS detaches, but we should stop the network polling.
*/
stopNetStatPoll();
- notifyDataConnection(Phone.REASON_GPRS_DETACHED);
+ notifyDataConnection(Phone.REASON_DATA_DETACHED);
}
private void onDataConnectionAttached() {
if (getOverallState() == State.CONNECTED) {
startNetStatPoll();
- notifyDataConnection(Phone.REASON_GPRS_ATTACHED);
- } else {
- // Only check for default APN state
- ApnContext defaultApnContext = mApnContexts.get(Phone.APN_TYPE_DEFAULT);
- if (defaultApnContext != null) {
- if (defaultApnContext.getState() == State.FAILED) {
- cleanUpConnection(false, defaultApnContext);
- defaultApnContext.getDataConnection().resetRetryCount();
- }
- trySetupData(Phone.REASON_GPRS_ATTACHED, Phone.APN_TYPE_DEFAULT);
- }
+ notifyDataConnection(Phone.REASON_DATA_ATTACHED);
}
+
+ setupDataOnReadyApns(Phone.REASON_DATA_ATTACHED);
}
@Override
@@ -582,7 +600,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState();
boolean allowed =
- (gprsState == ServiceState.STATE_IN_SERVICE || mAutoAttachOnCreation) &&
+ gprsState == ServiceState.STATE_IN_SERVICE &&
mPhone.mSIMRecords.getRecordsLoaded() &&
mPhone.getState() == Phone.State.IDLE &&
mInternalDataEnabled &&
@@ -591,7 +609,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
desiredPowerState;
if (!allowed && DBG) {
String reason = "";
- if (!((gprsState == ServiceState.STATE_IN_SERVICE) || mAutoAttachOnCreation)) {
+ if (!(gprsState == ServiceState.STATE_IN_SERVICE)) {
reason += " - gprs= " + gprsState;
}
if (!mPhone.mSIMRecords.getRecordsLoaded()) reason += " - SIM not loaded";
@@ -609,6 +627,26 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
return allowed;
}
+ private void setupDataOnReadyApns(String reason) {
+ // Only check for default APN state
+ for (ApnContext apnContext : mApnContexts.values()) {
+ if (apnContext.isReady()) {
+ if (apnContext.getState() == State.FAILED) {
+ cleanUpConnection(false, apnContext);
+ if (apnContext.getDataConnection() != null) {
+ apnContext.getDataConnection().resetRetryCount();
+ }
+ }
+ // Do not start ApnContext in SCANNING state
+ // FAILED state must be reset to IDLE by now
+ if (apnContext.getState() == State.IDLE) {
+ apnContext.setReason(reason);
+ trySetupData(apnContext);
+ }
+ }
+ }
+ }
+
private boolean trySetupData(String reason, String type) {
if (DBG) {
log("***trySetupData for type:" + type +
@@ -638,7 +676,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
if (DBG) {
log("trySetupData for type:" + apnContext.getApnType() +
" due to " + apnContext.getReason());
- log("[DSAC DEB] " + "trySetupData with mIsPsRestricted=" + mIsPsRestricted);
+ log("trySetupData with mIsPsRestricted=" + mIsPsRestricted);
}
if (mPhone.getSimulatedRadioControl() != null) {
@@ -941,14 +979,11 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
// TODO: It'd be nice to only do this if the changed entrie(s)
// match the current operator.
+ if (DBG) log("onApnChanged createAllApnList and cleanUpAllConnections");
createAllApnList();
- if (DBG) log("onApnChanged clean all connections");
cleanUpAllConnections(isConnected, Phone.REASON_APN_CHANGED);
if (!isConnected) {
- // TODO: Won't work for multiple connections!!!!
- defaultApnContext.getDataConnection().resetRetryCount();
- defaultApnContext.setReason(Phone.REASON_APN_CHANGED);
- trySetupData(defaultApnContext);
+ setupDataOnReadyApns(Phone.REASON_APN_CHANGED);
}
}
@@ -958,7 +993,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
* via an unsolicited response (which could have happened at any
* previous state
*/
- private void onDataStateChanged (AsyncResult ar, boolean explicitPoll) {
+ private void onDataStateChanged (AsyncResult ar) {
ArrayList<DataCallState> dataCallStates;
dataCallStates = (ArrayList<DataCallState>)(ar.result);
@@ -971,12 +1006,11 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
}
for (ApnContext apnContext : mApnContexts.values()) {
- onDataStateChanged(dataCallStates, explicitPoll, apnContext);
+ onDataStateChanged(dataCallStates, apnContext);
}
}
private void onDataStateChanged (ArrayList<DataCallState> dataCallStates,
- boolean explicitPoll,
ApnContext apnContext) {
if (apnContext == null) {
@@ -1006,25 +1040,16 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
return;
} else if (!dataCallStatesHasActiveCID(dataCallStates,
apnContext.getDataConnection().getCid())) {
- // Here, we only consider this authoritative if we asked for the
- // PDP list. If it was an unsolicited response, we poll again
- // to make sure everyone agrees on the initial state.
-
- if (!explicitPoll) {
- // We think it disconnected but aren't sure...poll from our side
- mPhone.mCM.getPDPContextList(
- this.obtainMessage(EVENT_GET_PDP_LIST_COMPLETE));
- } else {
- Log.i(LOG_TAG, "PDP connection has dropped (active=false case). "
+
+ Log.i(LOG_TAG, "PDP connection has dropped (active=false case). "
+ " Reconnecting");
- // Log the network drop on the event log.
- int cid = getCellLocationId();
- EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cid,
- TelephonyManager.getDefault().getNetworkType());
+ // Log the network drop on the event log.
+ int cid = getCellLocationId();
+ EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cid,
+ TelephonyManager.getDefault().getNetworkType());
- cleanUpConnection(true, apnContext);
- }
+ cleanUpConnection(true, apnContext);
}
}
}
@@ -1176,7 +1201,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
// It's possible the PDP context went down and we weren't notified.
// Start polling the context list in an attempt to recover.
if (DBG) log("no DATAIN in a while; polling PDP");
- mPhone.mCM.getDataCallList(obtainMessage(EVENT_GET_PDP_LIST_COMPLETE));
+ mPhone.mCM.getDataCallList(obtainMessage(EVENT_DATA_STATE_CHANGED));
mNoRecvPollCount++;
@@ -1296,19 +1321,9 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
}
private void onRecordsLoaded() {
+ if (DBG) log("onRecordsLoaded: createAllApnList");
createAllApnList();
- for (ApnContext apnContext : mApnContexts.values()) {
- if (apnContext.isReady()) {
- apnContext.setReason(Phone.REASON_SIM_LOADED);
- if (apnContext.getState() == State.FAILED) {
- if (DBG) {
- log("onRecordsLoaded clean connection for " + apnContext.getApnType());
- }
- cleanUpConnection(false, apnContext);
- }
- sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, apnContext));
- }
- }
+ setupDataOnReadyApns(Phone.REASON_SIM_LOADED);
}
@Override
@@ -1394,7 +1409,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
@Override
// TODO: We shouldnt need this.
protected boolean onTrySetupData(String reason) {
- return trySetupData(reason, Phone.APN_TYPE_DEFAULT);
+ setupDataOnReadyApns(reason);
+ return true;
}
protected boolean onTrySetupData(ApnContext apnContext) {
@@ -1402,16 +1418,14 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
}
@Override
- // TODO: Need to understand if more than DEFAULT is impacted?
protected void onRoamingOff() {
- trySetupData(Phone.REASON_ROAMING_OFF, Phone.APN_TYPE_DEFAULT);
+ setupDataOnReadyApns(Phone.REASON_ROAMING_OFF);
}
@Override
- // TODO: Need to understand if more than DEFAULT is impacted?
protected void onRoamingOn() {
if (getDataOnRoamingEnabled()) {
- trySetupData(Phone.REASON_ROAMING_ON, Phone.APN_TYPE_DEFAULT);
+ setupDataOnReadyApns(Phone.REASON_ROAMING_ON);
} else {
if (DBG) log("Tear down data connection on roaming.");
cleanUpAllConnections(true, Phone.REASON_ROAMING_ON);
@@ -1429,6 +1443,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
log("We're on the simulator; assuming data is connected");
}
+ if (mPhone.mSIMRecords.getRecordsLoaded()) {
+ notifyDataAvailability(null);
+ }
+
if (getOverallState() != State.IDLE) {
cleanUpConnection(true, null);
}
@@ -1470,8 +1488,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
log(String.format("onDataSetupComplete: success apn=%s",
apnContext.getWaitingApns().get(0).apn));
}
- mLinkProperties = getLinkProperties(apnContext.getDataConnection());
- mLinkCapabilities = getLinkCapabilities(apnContext.getDataConnection());
+ mLinkProperties = getLinkProperties(apnContext.getApnType());
+ mLinkCapabilities = getLinkCapabilities(apnContext.getApnType());
ApnSetting apn = apnContext.getApnSetting();
if (apn.proxy != null && apn.proxy.length() != 0) {
@@ -1580,6 +1598,12 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
+ // Check if APN disabled.
+ if (apnContext.getPendingAction() == ApnContext.PENDING_ACTION_APN_DISABLE) {
+ apnContext.setEnabled(false);
+ apnContext.setPendingAction(ApnContext.PENDING_ACTION_NONE);
+ }
+
// if all data connection are gone, check whether Airplane mode request was
// pending.
if (!isConnected()) {
@@ -1589,20 +1613,12 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
}
}
- // Check if APN disabled.
- if (apnContext.getPendingAction() == ApnContext.PENDING_ACTION_APN_DISABLE) {
- apnContext.setEnabled(false);
- apnContext.setPendingAction(ApnContext.PENDING_ACTION_NONE);
- }
-
- if (TextUtils.equals(apnContext.getApnType(), Phone.APN_TYPE_DEFAULT)
- && retryAfterDisconnected(apnContext.getReason())) {
+ // If APN is still enabled, try to bring it back up automatically
+ if (apnContext.isReady() && retryAfterDisconnected(apnContext.getReason())) {
SystemProperties.set("gsm.defaultpdpcontext.active", "false");
- trySetupData(apnContext);
- }
- else if (apnContext.getPendingAction() == ApnContext.PENDING_ACTION_RECONNECT)
- {
- apnContext.setPendingAction(ApnContext.PENDING_ACTION_NONE);
+ if (apnContext.getPendingAction() == ApnContext.PENDING_ACTION_RECONNECT) {
+ apnContext.setPendingAction(ApnContext.PENDING_ACTION_NONE);
+ }
trySetupData(apnContext);
}
}
@@ -1610,7 +1626,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
protected void onPollPdp() {
if (getOverallState() == State.CONNECTED) {
// only poll when connected
- mPhone.mCM.getPDPContextList(this.obtainMessage(EVENT_GET_PDP_LIST_COMPLETE));
+ mPhone.mCM.getDataCallList(this.obtainMessage(EVENT_DATA_STATE_CHANGED));
sendMessageDelayed(obtainMessage(EVENT_POLL_PDP), POLL_PDP_MILLIS);
}
}
@@ -1635,13 +1651,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
}
} else {
// reset reconnect timer
- ApnContext defaultApnContext = mApnContexts.get(Phone.APN_TYPE_DEFAULT);
- if (defaultApnContext != null) {
- defaultApnContext.getDataConnection().resetRetryCount();
- mReregisterOnReconnectFailure = false;
- // in case data setup was attempted when we were on a voice call
- trySetupData(Phone.REASON_VOICE_CALL_ENDED, Phone.APN_TYPE_DEFAULT);
- }
+ setupDataOnReadyApns(Phone.REASON_VOICE_CALL_ENDED);
}
}
@@ -1890,11 +1900,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
break;
case EVENT_DATA_STATE_CHANGED:
- onDataStateChanged((AsyncResult) msg.obj, false);
- break;
-
- case EVENT_GET_PDP_LIST_COMPLETE:
- onDataStateChanged((AsyncResult) msg.obj, true);
+ onDataStateChanged((AsyncResult) msg.obj);
break;
case EVENT_POLL_PDP:
@@ -1920,7 +1926,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
* PDP context and notify us with PDP_CONTEXT_CHANGED.
* But we should stop the network polling and prevent reset PDP.
*/
- log("[DSAC DEB] " + "EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted);
+ log("EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted);
stopNetStatPoll();
mIsPsRestricted = true;
break;
@@ -1930,7 +1936,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
* When PS restrict is removed, we need setup PDP connection if
* PDP connection is down.
*/
- log("[DSAC DEB] " + "EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted);
+ log("EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted);
mIsPsRestricted = false;
if (isConnected()) {
startNetStatPoll();
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
index e69989a04dc5..8b032ff6ccaf 100755
--- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
@@ -472,17 +472,23 @@ public final class SIMRecords extends IccRecords {
* provided the SIM card. Returns null of SIM is not yet ready
*/
public String getSIMOperatorNumeric() {
- if (imsi == null || mncLength == UNINITIALIZED || mncLength == UNKNOWN) {
+ if (imsi == null) {
+ Log.d(LOG_TAG, "getSIMOperatorNumeric: IMSI == null");
+ return null;
+ }
+ if (mncLength == UNINITIALIZED || mncLength == UNKNOWN) {
+ Log.d(LOG_TAG, "getSIMOperatorNumeric: bad mncLength");
return null;
}
- // Length = length of MCC + length of MNC
- // length of mcc = 3 (TS 23.003 Section 2.2)
+ // STOPSHIP: to be removed
if (SystemProperties.getInt(com.android.internal.telephony.TelephonyProperties
.PROPERTY_NETWORK_LTE_ON_CDMA, 0) == 1) {
Log.e(LOG_TAG, "getSIMOperatorNumeric: STOPSHIP bad numeric operators in lte");
return SystemProperties.get("ro.cdma.home.operator.numeric", "310004");
}
+ // Length = length of MCC + length of MNC
+ // length of mcc = 3 (TS 23.003 Section 2.2)
return imsi.substring(0, 3 + mncLength);
}
@@ -524,7 +530,7 @@ public final class SIMRecords extends IccRecords {
imsi = null;
}
- Log.d(LOG_TAG, "IMSI: " + imsi.substring(0, 6) + "xxxxxxx");
+ Log.d(LOG_TAG, "IMSI: " + /* imsi.substring(0, 6) +*/ "xxxxxxx");
if (((mncLength == UNKNOWN) || (mncLength == 2)) &&
((imsi != null) && (imsi.length() >= 6))) {
diff --git a/tests/ActivityTests/AndroidManifest.xml b/tests/ActivityTests/AndroidManifest.xml
index 6fa27ed9bda4..de3b6d15b02f 100644
--- a/tests/ActivityTests/AndroidManifest.xml
+++ b/tests/ActivityTests/AndroidManifest.xml
@@ -17,6 +17,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.android.test.activity">
<uses-permission android:name="android.permission.GET_TASKS" />
+ <uses-permission android:name="android.permission.REORDER_TASKS" />
+ <uses-permission android:name="android.permission.REMOVE_TASKS" />
<uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
<application android:label="ActivityTest">
<activity android:name="ActivityTestMain">
diff --git a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
index 8c5c35a33071..583c13cd8ae8 100644
--- a/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
+++ b/tests/ActivityTests/src/com/google/android/test/activity/ActivityTestMain.java
@@ -23,6 +23,7 @@ import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.Application;
+import android.content.ActivityNotFoundException;
import android.os.Bundle;
import android.graphics.BitmapFactory;
import android.graphics.Bitmap;
@@ -43,7 +44,11 @@ import android.util.DisplayMetrics;
import android.util.Log;
public class ActivityTestMain extends Activity {
- private void addThumbnail(LinearLayout container, Bitmap bm) {
+ ActivityManager mAm;
+
+ private void addThumbnail(LinearLayout container, Bitmap bm,
+ final ActivityManager.RecentTaskInfo task,
+ final ActivityManager.TaskThumbnails thumbs, final int subIndex) {
ImageView iv = new ImageView(this);
if (bm != null) {
iv.setImageBitmap(bm);
@@ -52,24 +57,72 @@ public class ActivityTestMain extends Activity {
int w = getResources().getDimensionPixelSize(android.R.dimen.thumbnail_width);
int h = getResources().getDimensionPixelSize(android.R.dimen.thumbnail_height);
container.addView(iv, new LinearLayout.LayoutParams(w, h));
+
+ iv.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (task.id >= 0 && thumbs != null) {
+ if (subIndex < (thumbs.numSubThumbbails-1)) {
+ mAm.removeSubTask(task.id, subIndex+1);
+ }
+ mAm.moveTaskToFront(task.id, ActivityManager.MOVE_TASK_WITH_HOME);
+ } else {
+ try {
+ startActivity(task.baseIntent);
+ } catch (ActivityNotFoundException e) {
+ Log.w("foo", "Unable to start task: " + e);
+ }
+ }
+ buildUi();
+ }
+ });
+ iv.setOnLongClickListener(new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ if (task.id >= 0 && thumbs != null) {
+ if (subIndex < 0) {
+ mAm.removeTask(task.id, ActivityManager.REMOVE_TASK_KILL_PROCESS);
+ } else {
+ mAm.removeSubTask(task.id, subIndex);
+ }
+ buildUi();
+ return true;
+ }
+ return false;
+ }
+ });
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- ActivityManager am = (ActivityManager)getSystemService(ACTIVITY_SERVICE);
+ mAm = (ActivityManager)getSystemService(ACTIVITY_SERVICE);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ buildUi();
+ }
+
+ private View scrollWrap(View view) {
+ ScrollView scroller = new ScrollView(this);
+ scroller.addView(view, new ScrollView.LayoutParams(ScrollView.LayoutParams.MATCH_PARENT,
+ ScrollView.LayoutParams.MATCH_PARENT));
+ return scroller;
+ }
+ private void buildUi() {
LinearLayout top = new LinearLayout(this);
top.setOrientation(LinearLayout.VERTICAL);
- List<ActivityManager.RecentTaskInfo> recents = am.getRecentTasks(10,
+ List<ActivityManager.RecentTaskInfo> recents = mAm.getRecentTasks(10,
ActivityManager.RECENT_WITH_EXCLUDED);
if (recents != null) {
for (int i=0; i<recents.size(); i++) {
ActivityManager.RecentTaskInfo r = recents.get(i);
- ActivityManager.TaskThumbnails tt = r != null
- ? am.getTaskThumbnails(r.persistentId) : null;
+ ActivityManager.TaskThumbnails tt = mAm.getTaskThumbnails(r.persistentId);
TextView tv = new TextView(this);
tv.setText(r.baseIntent.getComponent().flattenToShortString());
top.addView(tv, new LinearLayout.LayoutParams(
@@ -77,9 +130,9 @@ public class ActivityTestMain extends Activity {
LinearLayout.LayoutParams.WRAP_CONTENT));
LinearLayout item = new LinearLayout(this);
item.setOrientation(LinearLayout.HORIZONTAL);
- addThumbnail(item, tt != null ? tt.mainThumbnail : null);
+ addThumbnail(item, tt != null ? tt.mainThumbnail : null, r, tt, -1);
for (int j=0; j<tt.numSubThumbbails; j++) {
- addThumbnail(item, tt.getSubThumbnail(j));
+ addThumbnail(item, tt.getSubThumbnail(j), r, tt, j);
}
top.addView(item, new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
@@ -89,11 +142,4 @@ public class ActivityTestMain extends Activity {
setContentView(scrollWrap(top));
}
-
- private View scrollWrap(View view) {
- ScrollView scroller = new ScrollView(this);
- scroller.addView(view, new ScrollView.LayoutParams(ScrollView.LayoutParams.MATCH_PARENT,
- ScrollView.LayoutParams.MATCH_PARENT));
- return scroller;
- }
}
diff --git a/tests/BiDiTests/AndroidManifest.xml b/tests/BiDiTests/AndroidManifest.xml
index 346ace808b4c..727f980b8cf3 100644
--- a/tests/BiDiTests/AndroidManifest.xml
+++ b/tests/BiDiTests/AndroidManifest.xml
@@ -25,7 +25,8 @@
android:versionName="1.0">
<application android:label="BiDiTests">
- <activity android:name="BiDiTestActivity">
+ <activity android:name="BiDiTestActivity"
+ android:windowSoftInputMode="stateAlwaysHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
diff --git a/tests/BiDiTests/res/values/strings.xml b/tests/BiDiTests/res/values/strings.xml
index 632a02ed01cb..d20600e1307c 100644
--- a/tests/BiDiTests/res/values/strings.xml
+++ b/tests/BiDiTests/res/values/strings.xml
@@ -20,9 +20,10 @@
<string name="normal_long_text">mmmmmmmmmmmmmmmmmmmmmmmm</string>
<string name="normal_long_text_2">nnnnnnnnnnnnnnnnnnnnnnnn</string>
<string name="normal_long_text_3">Notify me when an open network is available</string>
- <string name="arabic_text">&#x0644;&#x0627;</string>
+ <string name="arabic_text">&#x0644;&#x0627; &#x0627;&#x0646;&#x0627; hello world</string>
<string name="chinese_text">利比亚局势或影响美俄关系发展</string>
<string name="italic_text">Italic String</string>
<string name="bold_text">Bold String - other text</string>
<string name="bold_italic_text">Bold Italic String</string>
+ <string name="mixed_text_1">he said in Arabic: &#x0644;&#x0627;. Wow this is cool</string>
</resources> \ No newline at end of file
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
index f00bd06cf08c..2f9b026914bc 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
@@ -49,6 +49,7 @@ public class BiDiTestView extends View {
private String BOLD_ITALIC_TEXT;
private String ARABIC_TEXT;
private String CHINESE_TEXT;
+ private String MIXED_TEXT_1;
private Typeface typeface;
@@ -79,6 +80,7 @@ public class BiDiTestView extends View {
BOLD_ITALIC_TEXT = context.getString(R.string.bold_italic_text);
ARABIC_TEXT = context.getString(R.string.arabic_text);
CHINESE_TEXT = context.getString(R.string.chinese_text);
+ MIXED_TEXT_1 = context.getString(R.string.mixed_text_1);
typeface = paint.getTypeface();
paint.setAntiAlias(true);
@@ -124,6 +126,10 @@ public class BiDiTestView extends View {
// Test Chinese
deltaX = testString(canvas, CHINESE_TEXT, ORIGIN, ORIGIN + 10 * currentTextSize,
paint, typeface, false, false, Paint.DIRECTION_LTR, currentTextSize);
+
+ // Test Mixed (English and Arabic)
+ deltaX = testString(canvas, MIXED_TEXT_1, ORIGIN, ORIGIN + 12 * currentTextSize,
+ paint, typeface, false, false, Paint.DIRECTION_LTR, currentTextSize);
}
private int testString(Canvas canvas, String text, int x, int y, Paint paint, Typeface typeface,
@@ -139,12 +145,15 @@ public class BiDiTestView extends View {
paint.setTextSkewX(DEFAULT_ITALIC_SKEW_X);
}
- drawTextWithCanvasDrawText(text, canvas, x, y, textSize, Color.WHITE);
+ Log.v(TAG, "START -- drawTextWithCanvasDrawText");
+ drawTextWithCanvasDrawText(text, canvas, x, y, textSize, Color.WHITE, dir);
+ Log.v(TAG, "END -- drawTextWithCanvasDrawText");
int length = text.length();
float[] advances = new float[length];
- float textWidthHB = paint.getTextRunAdvances(text, 0, length, 0, length, 0, advances, 0);
- float textWidthICU = paint.getTextRunAdvancesICU(text, 0, length, 0, length, 0, advances, 0);
+ float textWidthHB = paint.getTextRunAdvances(text, 0, length, 0, length, dir, advances, 0);
+ setPaintDir(paint, dir);
+ float textWidthICU = paint.getTextRunAdvancesICU(text, 0, length, 0, length, dir, advances, 0);
logAdvances(text, textWidthHB, textWidthICU, advances);
drawMetricsAroundText(canvas, x, y, textWidthHB, textWidthICU, textSize, Color.RED, Color.GREEN);
@@ -156,7 +165,9 @@ public class BiDiTestView extends View {
// logGlypths(glyphs, count);
// drawTextWithDrawGlyph(canvas, glyphs, count, x, y + currentTextSize);
+ Log.v(TAG, "START -- drawTextWithGlyphs");
drawTextWithGlyphs(canvas, text, x, y + currentTextSize, dir);
+ Log.v(TAG, "END -- drawTextWithGlyphs");
// Restore old paint properties
paint.setFakeBoldText(oldFakeBold);
@@ -165,12 +176,17 @@ public class BiDiTestView extends View {
return (int) Math.ceil(textWidthHB) + TEXT_PADDING;
}
+ private void setPaintDir(Paint paint, int dir) {
+ Log.v(TAG, "Setting Paint dir=" + dir);
+ paint.setBidiFlags(dir);
+ }
+
private void drawTextWithDrawGlyph(Canvas canvas, char[] glyphs, int count, int x, int y) {
canvas.drawGlyphs(glyphs, 0, count, x, y, paint);
}
private void drawTextWithGlyphs(Canvas canvas, String text, int x, int y, int dir) {
- paint.setBidiFlags(dir);
+ setPaintDir(paint, dir);
canvas.drawTextWithGlyphs(text, x, y, paint);
}
@@ -182,7 +198,6 @@ public class BiDiTestView extends View {
}
private int getGlyphs(String text, char[] glyphs, int dir) {
-// int dir = 1; // Paint.DIRECTION_LTR;
return paint.getTextGlypths(text, 0, text.length(), 0, text.length(), dir, glyphs);
}
@@ -195,7 +210,8 @@ public class BiDiTestView extends View {
}
private void drawTextWithCanvasDrawText(String text, Canvas canvas,
- float x, float y, float textSize, int color) {
+ float x, float y, float textSize, int color, int dir) {
+ setPaintDir(paint, dir);
paint.setColor(color);
paint.setTextSize(textSize);
canvas.drawText(text, x, y, paint);
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index 15570e47e6a1..fa84e938cab4 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -40,6 +40,7 @@ public:
mWantUTF16(false), mValues(false),
mCompressionMethod(0), mOutputAPKFile(NULL),
mManifestPackageNameOverride(NULL), mInstrumentationPackageNameOverride(NULL),
+ mIsOverlayPackage(false),
mAutoAddOverlay(false), mAssetSourceDir(NULL), mProguardFile(NULL),
mAndroidManifestFile(NULL), mPublicOutputFile(NULL),
mRClassDir(NULL), mResourceIntermediatesDir(NULL), mManifestMinSdkVersion(NULL),
@@ -92,6 +93,8 @@ public:
void setManifestPackageNameOverride(const char * val) { mManifestPackageNameOverride = val; }
const char* getInstrumentationPackageNameOverride() const { return mInstrumentationPackageNameOverride; }
void setInstrumentationPackageNameOverride(const char * val) { mInstrumentationPackageNameOverride = val; }
+ bool getIsOverlayPackage() const { return mIsOverlayPackage; }
+ void setIsOverlayPackage(bool val) { mIsOverlayPackage = val; }
bool getAutoAddOverlay() { return mAutoAddOverlay; }
void setAutoAddOverlay(bool val) { mAutoAddOverlay = val; }
@@ -219,6 +222,7 @@ private:
const char* mOutputAPKFile;
const char* mManifestPackageNameOverride;
const char* mInstrumentationPackageNameOverride;
+ bool mIsOverlayPackage;
bool mAutoAddOverlay;
const char* mAssetSourceDir;
const char* mProguardFile;
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index 266a02f25a17..1e63131eb5bf 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -68,6 +68,7 @@ void usage(void)
" [-S resource-sources [-S resource-sources ...]] "
" [-F apk-file] [-J R-file-dir] \\\n"
" [--product product1,product2,...] \\\n"
+ " [-o] \\\n"
" [raw-files-dir [raw-files-dir] ...]\n"
"\n"
" Package the android resources. It will read assets and resources that are\n"
@@ -105,6 +106,7 @@ void usage(void)
" -j specify a jar or zip file containing classes to include\n"
" -k junk path of file(s) added\n"
" -m make package directories under location specified by -J\n"
+ " -o create overlay package (ie only resources; expects <overlay-package> in manifest)\n"
#if 0
" -p pseudolocalize the default configuration\n"
#endif
@@ -275,6 +277,9 @@ int main(int argc, char* const argv[])
case 'm':
bundle.setMakePackageDirs(true);
break;
+ case 'o':
+ bundle.setIsOverlayPackage(true);
+ break;
#if 0
case 'p':
bundle.setPseudolocalize(true);
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 3dcc09399850..a88476e9b544 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -3696,7 +3696,9 @@ sp<ResourceTable::Package> ResourceTable::getPackage(const String16& package)
{
sp<Package> p = mPackages.valueFor(package);
if (p == NULL) {
- if (mIsAppPackage) {
+ if (mBundle->getIsOverlayPackage()) {
+ p = new Package(package, 0x00);
+ } else if (mIsAppPackage) {
if (mHaveAppPackage) {
fprintf(stderr, "Adding multiple application package resources; only one is allowed.\n"
"Use -x to create extended resources.\n");
diff --git a/wifi/java/android/net/wifi/SupplicantStateTracker.java b/wifi/java/android/net/wifi/SupplicantStateTracker.java
index 3cde949f204c..9ae26daa9302 100644
--- a/wifi/java/android/net/wifi/SupplicantStateTracker.java
+++ b/wifi/java/android/net/wifi/SupplicantStateTracker.java
@@ -16,8 +16,8 @@
package android.net.wifi;
-import com.android.internal.util.HierarchicalState;
-import com.android.internal.util.HierarchicalStateMachine;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
import android.net.wifi.WifiStateMachine.StateChangeResult;
import android.content.Context;
@@ -33,7 +33,7 @@ import android.util.Log;
* - detect a failed WPA handshake that loops indefinitely
* - authentication failure handling
*/
-class SupplicantStateTracker extends HierarchicalStateMachine {
+class SupplicantStateTracker extends StateMachine {
private static final String TAG = "SupplicantStateTracker";
private static final boolean DBG = false;
@@ -53,14 +53,14 @@ class SupplicantStateTracker extends HierarchicalStateMachine {
private Context mContext;
- private HierarchicalState mUninitializedState = new UninitializedState();
- private HierarchicalState mDefaultState = new DefaultState();
- private HierarchicalState mInactiveState = new InactiveState();
- private HierarchicalState mDisconnectState = new DisconnectedState();
- private HierarchicalState mScanState = new ScanState();
- private HierarchicalState mHandshakeState = new HandshakeState();
- private HierarchicalState mCompletedState = new CompletedState();
- private HierarchicalState mDormantState = new DormantState();
+ private State mUninitializedState = new UninitializedState();
+ private State mDefaultState = new DefaultState();
+ private State mInactiveState = new InactiveState();
+ private State mDisconnectState = new DisconnectedState();
+ private State mScanState = new ScanState();
+ private State mHandshakeState = new HandshakeState();
+ private State mCompletedState = new CompletedState();
+ private State mDormantState = new DormantState();
public SupplicantStateTracker(Context context, WifiStateMachine wsm, Handler target) {
super(TAG, target.getLooper());
@@ -146,7 +146,7 @@ class SupplicantStateTracker extends HierarchicalStateMachine {
* HSM states
*******************************************************/
- class DefaultState extends HierarchicalState {
+ class DefaultState extends State {
@Override
public void enter() {
if (DBG) Log.d(TAG, getName() + "\n");
@@ -188,21 +188,21 @@ class SupplicantStateTracker extends HierarchicalStateMachine {
* or after we have lost the control channel
* connection to the supplicant
*/
- class UninitializedState extends HierarchicalState {
+ class UninitializedState extends State {
@Override
public void enter() {
if (DBG) Log.d(TAG, getName() + "\n");
}
}
- class InactiveState extends HierarchicalState {
+ class InactiveState extends State {
@Override
public void enter() {
if (DBG) Log.d(TAG, getName() + "\n");
}
}
- class DisconnectedState extends HierarchicalState {
+ class DisconnectedState extends State {
@Override
public void enter() {
if (DBG) Log.d(TAG, getName() + "\n");
@@ -221,14 +221,14 @@ class SupplicantStateTracker extends HierarchicalStateMachine {
}
}
- class ScanState extends HierarchicalState {
+ class ScanState extends State {
@Override
public void enter() {
if (DBG) Log.d(TAG, getName() + "\n");
}
}
- class HandshakeState extends HierarchicalState {
+ class HandshakeState extends State {
/**
* The max number of the WPA supplicant loop iterations before we
* decide that the loop should be terminated:
@@ -277,7 +277,7 @@ class SupplicantStateTracker extends HierarchicalStateMachine {
}
}
- class CompletedState extends HierarchicalState {
+ class CompletedState extends State {
@Override
public void enter() {
if (DBG) Log.d(TAG, getName() + "\n");
@@ -318,7 +318,7 @@ class SupplicantStateTracker extends HierarchicalStateMachine {
}
//TODO: remove after getting rid of the state in supplicant
- class DormantState extends HierarchicalState {
+ class DormantState extends State {
@Override
public void enter() {
if (DBG) Log.d(TAG, getName() + "\n");
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 46c07a303b90..16611d88851f 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -73,8 +73,8 @@ import android.util.LruCache;
import com.android.internal.app.IBatteryStats;
import com.android.internal.util.AsyncChannel;
-import com.android.internal.util.HierarchicalState;
-import com.android.internal.util.HierarchicalStateMachine;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
import java.net.InetAddress;
import java.util.ArrayList;
@@ -88,7 +88,7 @@ import java.util.regex.Pattern;
*
* @hide
*/
-public class WifiStateMachine extends HierarchicalStateMachine {
+public class WifiStateMachine extends StateMachine {
private static final String TAG = "WifiStateMachine";
private static final String NETWORKTYPE = "WIFI";
@@ -358,50 +358,50 @@ public class WifiStateMachine extends HierarchicalStateMachine {
private static final int MAX_RSSI = 256;
/* Default parent state */
- private HierarchicalState mDefaultState = new DefaultState();
+ private State mDefaultState = new DefaultState();
/* Temporary initial state */
- private HierarchicalState mInitialState = new InitialState();
+ private State mInitialState = new InitialState();
/* Unloading the driver */
- private HierarchicalState mDriverUnloadingState = new DriverUnloadingState();
+ private State mDriverUnloadingState = new DriverUnloadingState();
/* Loading the driver */
- private HierarchicalState mDriverUnloadedState = new DriverUnloadedState();
+ private State mDriverUnloadedState = new DriverUnloadedState();
/* Driver load/unload failed */
- private HierarchicalState mDriverFailedState = new DriverFailedState();
+ private State mDriverFailedState = new DriverFailedState();
/* Driver loading */
- private HierarchicalState mDriverLoadingState = new DriverLoadingState();
+ private State mDriverLoadingState = new DriverLoadingState();
/* Driver loaded */
- private HierarchicalState mDriverLoadedState = new DriverLoadedState();
+ private State mDriverLoadedState = new DriverLoadedState();
/* Driver loaded, waiting for supplicant to start */
- private HierarchicalState mSupplicantStartingState = new SupplicantStartingState();
+ private State mSupplicantStartingState = new SupplicantStartingState();
/* Driver loaded and supplicant ready */
- private HierarchicalState mSupplicantStartedState = new SupplicantStartedState();
+ private State mSupplicantStartedState = new SupplicantStartedState();
/* Waiting for supplicant to stop and monitor to exit */
- private HierarchicalState mSupplicantStoppingState = new SupplicantStoppingState();
+ private State mSupplicantStoppingState = new SupplicantStoppingState();
/* Driver start issued, waiting for completed event */
- private HierarchicalState mDriverStartingState = new DriverStartingState();
+ private State mDriverStartingState = new DriverStartingState();
/* Driver started */
- private HierarchicalState mDriverStartedState = new DriverStartedState();
+ private State mDriverStartedState = new DriverStartedState();
/* Driver stopping */
- private HierarchicalState mDriverStoppingState = new DriverStoppingState();
+ private State mDriverStoppingState = new DriverStoppingState();
/* Driver stopped */
- private HierarchicalState mDriverStoppedState = new DriverStoppedState();
+ private State mDriverStoppedState = new DriverStoppedState();
/* Scan for networks, no connection will be established */
- private HierarchicalState mScanModeState = new ScanModeState();
+ private State mScanModeState = new ScanModeState();
/* Connecting to an access point */
- private HierarchicalState mConnectModeState = new ConnectModeState();
+ private State mConnectModeState = new ConnectModeState();
/* Fetching IP after network connection (assoc+auth complete) */
- private HierarchicalState mConnectingState = new ConnectingState();
+ private State mConnectingState = new ConnectingState();
/* Connected with IP addr */
- private HierarchicalState mConnectedState = new ConnectedState();
+ private State mConnectedState = new ConnectedState();
/* disconnect issued, waiting for network disconnect confirmation */
- private HierarchicalState mDisconnectingState = new DisconnectingState();
+ private State mDisconnectingState = new DisconnectingState();
/* Network is not connected, supplicant assoc+auth is not complete */
- private HierarchicalState mDisconnectedState = new DisconnectedState();
+ private State mDisconnectedState = new DisconnectedState();
/* Waiting for WPS to be completed*/
- private HierarchicalState mWaitForWpsCompletionState = new WaitForWpsCompletionState();
+ private State mWaitForWpsCompletionState = new WaitForWpsCompletionState();
/* Soft Ap is running */
- private HierarchicalState mSoftApStartedState = new SoftApStartedState();
+ private State mSoftApStartedState = new SoftApStartedState();
/**
@@ -1543,7 +1543,7 @@ public class WifiStateMachine extends HierarchicalStateMachine {
* HSM states
*******************************************************/
- class DefaultState extends HierarchicalState {
+ class DefaultState extends State {
@Override
public boolean processMessage(Message message) {
if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
@@ -1617,7 +1617,7 @@ public class WifiStateMachine extends HierarchicalStateMachine {
}
}
- class InitialState extends HierarchicalState {
+ class InitialState extends State {
@Override
//TODO: could move logging into a common class
public void enter() {
@@ -1636,7 +1636,7 @@ public class WifiStateMachine extends HierarchicalStateMachine {
}
}
- class DriverLoadingState extends HierarchicalState {
+ class DriverLoadingState extends State {
@Override
public void enter() {
if (DBG) Log.d(TAG, getName() + "\n");
@@ -1715,7 +1715,7 @@ public class WifiStateMachine extends HierarchicalStateMachine {
}
}
- class DriverLoadedState extends HierarchicalState {
+ class DriverLoadedState extends State {
@Override
public void enter() {
if (DBG) Log.d(TAG, getName() + "\n");
@@ -1768,7 +1768,7 @@ public class WifiStateMachine extends HierarchicalStateMachine {
}
}
- class DriverUnloadingState extends HierarchicalState {
+ class DriverUnloadingState extends State {
@Override
public void enter() {
if (DBG) Log.d(TAG, getName() + "\n");
@@ -1849,7 +1849,7 @@ public class WifiStateMachine extends HierarchicalStateMachine {
}
}
- class DriverUnloadedState extends HierarchicalState {
+ class DriverUnloadedState extends State {
@Override
public void enter() {
if (DBG) Log.d(TAG, getName() + "\n");
@@ -1870,7 +1870,7 @@ public class WifiStateMachine extends HierarchicalStateMachine {
}
}
- class DriverFailedState extends HierarchicalState {
+ class DriverFailedState extends State {
@Override
public void enter() {
Log.e(TAG, getName() + "\n");
@@ -1884,7 +1884,7 @@ public class WifiStateMachine extends HierarchicalStateMachine {
}
- class SupplicantStartingState extends HierarchicalState {
+ class SupplicantStartingState extends State {
@Override
public void enter() {
if (DBG) Log.d(TAG, getName() + "\n");
@@ -1956,7 +1956,7 @@ public class WifiStateMachine extends HierarchicalStateMachine {
}
}
- class SupplicantStartedState extends HierarchicalState {
+ class SupplicantStartedState extends State {
@Override
public void enter() {
if (DBG) Log.d(TAG, getName() + "\n");
@@ -1978,17 +1978,6 @@ public class WifiStateMachine extends HierarchicalStateMachine {
boolean eventLoggingEnabled = true;
switch(message.what) {
case CMD_STOP_SUPPLICANT: /* Supplicant stopped by user */
- Log.d(TAG, "stopping supplicant");
- if (!WifiNative.stopSupplicant()) {
- Log.e(TAG, "Failed to stop supplicant, issue kill");
- WifiNative.killSupplicant();
- }
- mNetworkInfo.setIsAvailable(false);
- handleNetworkDisconnect();
- setWifiState(WIFI_STATE_DISABLING);
- sendSupplicantConnectionChangedBroadcast(false);
- mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
- mWpsStateMachine.sendMessage(CMD_RESET_WPS_STATE);
transitionTo(mSupplicantStoppingState);
break;
case SUP_DISCONNECTION_EVENT: /* Supplicant connection lost */
@@ -2084,11 +2073,22 @@ public class WifiStateMachine extends HierarchicalStateMachine {
}
}
- class SupplicantStoppingState extends HierarchicalState {
+ class SupplicantStoppingState extends State {
@Override
public void enter() {
if (DBG) Log.d(TAG, getName() + "\n");
EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+ Log.d(TAG, "stopping supplicant");
+ if (!WifiNative.stopSupplicant()) {
+ Log.e(TAG, "Failed to stop supplicant, issue kill");
+ WifiNative.killSupplicant();
+ }
+ mNetworkInfo.setIsAvailable(false);
+ handleNetworkDisconnect();
+ setWifiState(WIFI_STATE_DISABLING);
+ sendSupplicantConnectionChangedBroadcast(false);
+ mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
+ mWpsStateMachine.sendMessage(CMD_RESET_WPS_STATE);
}
@Override
public boolean processMessage(Message message) {
@@ -2127,7 +2127,7 @@ public class WifiStateMachine extends HierarchicalStateMachine {
}
}
- class DriverStartingState extends HierarchicalState {
+ class DriverStartingState extends State {
@Override
public void enter() {
if (DBG) Log.d(TAG, getName() + "\n");
@@ -2168,7 +2168,7 @@ public class WifiStateMachine extends HierarchicalStateMachine {
}
}
- class DriverStartedState extends HierarchicalState {
+ class DriverStartedState extends State {
@Override
public void enter() {
if (DBG) Log.d(TAG, getName() + "\n");
@@ -2272,7 +2272,7 @@ public class WifiStateMachine extends HierarchicalStateMachine {
}
}
- class DriverStoppingState extends HierarchicalState {
+ class DriverStoppingState extends State {
@Override
public void enter() {
if (DBG) Log.d(TAG, getName() + "\n");
@@ -2308,7 +2308,7 @@ public class WifiStateMachine extends HierarchicalStateMachine {
}
}
- class DriverStoppedState extends HierarchicalState {
+ class DriverStoppedState extends State {
@Override
public void enter() {
if (DBG) Log.d(TAG, getName() + "\n");
@@ -2332,7 +2332,7 @@ public class WifiStateMachine extends HierarchicalStateMachine {
}
}
- class ScanModeState extends HierarchicalState {
+ class ScanModeState extends State {
@Override
public void enter() {
if (DBG) Log.d(TAG, getName() + "\n");
@@ -2369,7 +2369,7 @@ public class WifiStateMachine extends HierarchicalStateMachine {
}
}
- class ConnectModeState extends HierarchicalState {
+ class ConnectModeState extends State {
@Override
public void enter() {
if (DBG) Log.d(TAG, getName() + "\n");
@@ -2479,7 +2479,7 @@ public class WifiStateMachine extends HierarchicalStateMachine {
}
}
- class ConnectingState extends HierarchicalState {
+ class ConnectingState extends State {
boolean mModifiedBluetoothCoexistenceMode;
int mPowerMode;
boolean mUseStaticIp;
@@ -2677,7 +2677,7 @@ public class WifiStateMachine extends HierarchicalStateMachine {
}
}
- class ConnectedState extends HierarchicalState {
+ class ConnectedState extends State {
@Override
public void enter() {
if (DBG) Log.d(TAG, getName() + "\n");
@@ -2789,7 +2789,7 @@ public class WifiStateMachine extends HierarchicalStateMachine {
}
}
- class DisconnectingState extends HierarchicalState {
+ class DisconnectingState extends State {
@Override
public void enter() {
if (DBG) Log.d(TAG, getName() + "\n");
@@ -2819,7 +2819,7 @@ public class WifiStateMachine extends HierarchicalStateMachine {
}
}
- class DisconnectedState extends HierarchicalState {
+ class DisconnectedState extends State {
private boolean mAlarmEnabled = false;
/* This is set from the overlay config file or from a secure setting.
* A value of 0 disables scanning in the framework.
@@ -2931,7 +2931,7 @@ public class WifiStateMachine extends HierarchicalStateMachine {
}
}
- class WaitForWpsCompletionState extends HierarchicalState {
+ class WaitForWpsCompletionState extends State {
@Override
public void enter() {
if (DBG) Log.d(TAG, getName() + "\n");
@@ -2970,7 +2970,7 @@ public class WifiStateMachine extends HierarchicalStateMachine {
}
}
- class SoftApStartedState extends HierarchicalState {
+ class SoftApStartedState extends State {
@Override
public void enter() {
if (DBG) Log.d(TAG, getName() + "\n");
diff --git a/wifi/java/android/net/wifi/WpsStateMachine.java b/wifi/java/android/net/wifi/WpsStateMachine.java
index 32d77a1c8420..120b22886de7 100644
--- a/wifi/java/android/net/wifi/WpsStateMachine.java
+++ b/wifi/java/android/net/wifi/WpsStateMachine.java
@@ -17,8 +17,8 @@
package android.net.wifi;
import com.android.internal.util.AsyncChannel;
-import com.android.internal.util.HierarchicalState;
-import com.android.internal.util.HierarchicalStateMachine;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
import android.content.Context;
import android.content.Intent;
@@ -46,7 +46,7 @@ import android.util.Log;
* reloads the configuration and updates the IP and proxy
* settings, if any.
*/
-class WpsStateMachine extends HierarchicalStateMachine {
+class WpsStateMachine extends StateMachine {
private static final String TAG = "WpsStateMachine";
private static final boolean DBG = false;
@@ -58,9 +58,9 @@ class WpsStateMachine extends HierarchicalStateMachine {
private Context mContext;
AsyncChannel mReplyChannel = new AsyncChannel();
- private HierarchicalState mDefaultState = new DefaultState();
- private HierarchicalState mInactiveState = new InactiveState();
- private HierarchicalState mActiveState = new ActiveState();
+ private State mDefaultState = new DefaultState();
+ private State mInactiveState = new InactiveState();
+ private State mActiveState = new ActiveState();
public WpsStateMachine(Context context, WifiStateMachine wsm, Handler target) {
super(TAG, target.getLooper());
@@ -82,7 +82,7 @@ class WpsStateMachine extends HierarchicalStateMachine {
* HSM states
*******************************************************/
- class DefaultState extends HierarchicalState {
+ class DefaultState extends State {
@Override
public void enter() {
if (DBG) Log.d(TAG, getName() + "\n");
@@ -128,7 +128,7 @@ class WpsStateMachine extends HierarchicalStateMachine {
}
}
- class ActiveState extends HierarchicalState {
+ class ActiveState extends State {
@Override
public void enter() {
if (DBG) Log.d(TAG, getName() + "\n");
@@ -182,7 +182,7 @@ class WpsStateMachine extends HierarchicalStateMachine {
}
}
- class InactiveState extends HierarchicalState {
+ class InactiveState extends State {
@Override
public void enter() {
if (DBG) Log.d(TAG, getName() + "\n");